Skip to content

Commit 6c5926a

Browse files
317787106halibobo1205
authored andcommitted
fix(db): fix storage config properties (tronprotocol#6806)
1 parent 65a7fb1 commit 6c5926a

7 files changed

Lines changed: 215 additions & 119 deletions

File tree

common/src/main/java/org/tron/core/config/README.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ storage {
2828
{
2929
name = "account",
3030
path = "/path/to/accout", // relative or absolute path
31-
createIfMissing = true,
32-
paranoidChecks = true,
33-
verifyChecksums = true,
34-
compressionType = 1, // 0 - no compression, 1 - compressed with snappy
31+
# following are only used for LevelDB
3532
blockSize = 4096, // 4 KB = 4 * 1024 B
3633
writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
3734
cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
@@ -43,7 +40,7 @@ storage {
4340
4441
```
4542

46-
As shown in the example above, the `accout` database will be stored in the path of `/path/to/accout/database` while the index be stored in `/path/to/accout/index`. And, the example also shows our default value of LevelDB options(Start from `createIfMissing` and end at `maxOpenFiles`). Please refer to the docs of [LevelDB](https://github.com/google/leveldb/blob/master/doc/index.md#performance) to figure out the details of these options.
43+
As shown in the example above, the `accout` database will be stored in the path of `/path/to/accout/database` while the index be stored in `/path/to/accout/index`. And, the example also shows our default value of LevelDB options(Start from `blockSize` and end at `maxOpenFiles`). Please refer to the docs of [LevelDB](https://github.com/google/leveldb/blob/master/doc/index.md#performance) to figure out the details of these options.
4744

4845
## gRPC
4946

common/src/main/java/org/tron/core/config/args/Storage.java

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import lombok.Getter;
2626
import lombok.Setter;
2727
import lombok.extern.slf4j.Slf4j;
28-
import org.iq80.leveldb.CompressionType;
2928
import org.iq80.leveldb.Options;
3029
import org.tron.common.cache.CacheStrategies;
3130
import org.tron.common.cache.CacheType;
@@ -170,26 +169,13 @@ private Property createPropertyFromBean(StorageConfig.PropertyConfig pc) {
170169
}
171170

172171
Options dbOptions = newDefaultDbOptions(property.getName());
173-
applyPropertyOptions(pc, dbOptions);
172+
// PropertyConfig is-a DbOptionOverride: apply only user-specified (non-null) overrides
173+
// so unset fields keep the per-tier defaults already applied by newDefaultDbOptions.
174+
applyDbOptionOverride(pc, dbOptions);
174175
property.setDbOptions(dbOptions);
175176
return property;
176177
}
177178

178-
/**
179-
* Apply LevelDB options from PropertyConfig bean values.
180-
*/
181-
private static void applyPropertyOptions(StorageConfig.PropertyConfig pc, Options dbOptions) {
182-
dbOptions.createIfMissing(pc.isCreateIfMissing());
183-
dbOptions.paranoidChecks(pc.isParanoidChecks());
184-
dbOptions.verifyChecksums(pc.isVerifyChecksums());
185-
dbOptions.compressionType(
186-
CompressionType.getCompressionTypeByPersistentId(pc.getCompressionType()));
187-
dbOptions.blockSize(pc.getBlockSize());
188-
dbOptions.writeBufferSize(pc.getWriteBufferSize());
189-
dbOptions.cacheSize(pc.getCacheSize());
190-
dbOptions.maxOpenFiles(pc.getMaxOpenFiles());
191-
}
192-
193179
/**
194180
* Set propertyMap from StorageConfig bean list. No Config parameter needed.
195181
*/
@@ -247,19 +233,6 @@ public Options newDefaultDbOptions(String name) {
247233
// Apply only user-specified overrides (non-null fields) to LevelDB Options.
248234
private static void applyDbOptionOverride(
249235
StorageConfig.DbOptionOverride o, Options dbOptions) {
250-
if (o.getCreateIfMissing() != null) {
251-
dbOptions.createIfMissing(o.getCreateIfMissing());
252-
}
253-
if (o.getParanoidChecks() != null) {
254-
dbOptions.paranoidChecks(o.getParanoidChecks());
255-
}
256-
if (o.getVerifyChecksums() != null) {
257-
dbOptions.verifyChecksums(o.getVerifyChecksums());
258-
}
259-
if (o.getCompressionType() != null) {
260-
dbOptions.compressionType(
261-
CompressionType.getCompressionTypeByPersistentId(o.getCompressionType()));
262-
}
263236
if (o.getBlockSize() != null) {
264237
dbOptions.blockSize(o.getBlockSize());
265238
}

common/src/main/java/org/tron/core/config/args/StorageConfig.java

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class StorageConfig {
2828
private CheckpointConfig checkpoint = new CheckpointConfig();
2929
private SnapshotConfig snapshot = new SnapshotConfig();
3030
private TxCacheConfig txCache = new TxCacheConfig();
31+
// ConfigBeanFactory requires all bean fields present per item, so we parse manually.
32+
@Setter(lombok.AccessLevel.NONE)
3133
private List<PropertyConfig> properties = new ArrayList<>();
3234

3335
// merkleRoot is a nested object (e.g. { reward-vi = "hash..." }) not a string.
@@ -54,6 +56,7 @@ public class StorageConfig {
5456
@Getter
5557
@Setter
5658
public static class DbConfig {
59+
5760
private String engine = "LEVELDB";
5861
private boolean sync = false;
5962
private String directory = "database";
@@ -62,6 +65,7 @@ public static class DbConfig {
6265
@Getter
6366
@Setter
6467
public static class TransHistoryConfig {
68+
6569
// "switch" is a reserved Java keyword; ConfigBeanFactory calls setSwitch() which works fine
6670
@Getter(lombok.AccessLevel.NONE)
6771
@Setter(lombok.AccessLevel.NONE)
@@ -79,6 +83,7 @@ public void setSwitch(String v) {
7983
@Getter
8084
@Setter
8185
public static class DbSettingsConfig {
86+
8287
private int levelNumber = 7;
8388
private int compactThreads = 0; // 0 = auto: max(availableProcessors, 1)
8489
private int blocksize = 16;
@@ -100,25 +105,29 @@ void postProcess() {
100105
@Getter
101106
@Setter
102107
public static class BalanceConfig {
108+
103109
private HistoryConfig history = new HistoryConfig();
104110

105111
@Getter
106112
@Setter
107113
public static class HistoryConfig {
114+
108115
private boolean lookup = false;
109116
}
110117
}
111118

112119
@Getter
113120
@Setter
114121
public static class CheckpointConfig {
122+
115123
private int version = 1;
116124
private boolean sync = true;
117125
}
118126

119127
@Getter
120128
@Setter
121129
public static class SnapshotConfig {
130+
122131
private int maxFlushCount = 1;
123132

124133
// Reject out-of-range values. Mirrors develop Storage.getSnapshotMaxFlushCountFromConfig.
@@ -135,6 +144,7 @@ void postProcess() {
135144
@Getter
136145
@Setter
137146
public static class TxCacheConfig {
147+
138148
private int estimatedTransactions = 1000;
139149
private boolean initOptimization = false;
140150

@@ -148,19 +158,14 @@ void postProcess() {
148158
}
149159
}
150160

161+
// A named database entry: name/path plus the optional LevelDB option overrides
162+
// inherited from DbOptionOverride (boxed types, null = "inherit per-tier defaults").
151163
@Getter
152164
@Setter
153-
public static class PropertyConfig {
165+
public static class PropertyConfig extends DbOptionOverride {
166+
154167
private String name = "";
155168
private String path = "";
156-
private boolean createIfMissing = true;
157-
private boolean paranoidChecks = true;
158-
private boolean verifyChecksums = true;
159-
private int compressionType = 1;
160-
private int blockSize = 4096;
161-
private int writeBufferSize = 10485760;
162-
private long cacheSize = 10485760;
163-
private int maxOpenFiles = 100;
164169
}
165170

166171
// Defaults come from reference.conf (loaded globally via Configuration.java)
@@ -170,6 +175,7 @@ public static StorageConfig fromConfig(Config config) {
170175

171176
StorageConfig sc = ConfigBeanFactory.create(section, StorageConfig.class);
172177
sc.rawStorageConfig = section;
178+
sc.properties = readProperties(section);
173179

174180
// Read optional LevelDB option overrides (default, defaultM, defaultL).
175181
sc.defaultDbOption = readDbOption(section, "default");
@@ -187,45 +193,17 @@ public static StorageConfig fromConfig(Config config) {
187193
@Getter
188194
@Setter
189195
public static class DbOptionOverride {
190-
private Boolean createIfMissing;
191-
private Boolean paranoidChecks;
192-
private Boolean verifyChecksums;
193-
private Integer compressionType;
196+
194197
private Integer blockSize;
195198
private Integer writeBufferSize;
196199
private Long cacheSize;
197200
private Integer maxOpenFiles;
198201
}
199202

200-
// Read optional LevelDB option override (default/defaultM/defaultL).
201-
// Not bean-bound: users may only set a subset of keys (e.g. just maxOpenFiles),
202-
// ConfigBeanFactory requires all fields present so partial overrides would fail.
203-
private static DbOptionOverride readDbOption(Config section, String key) {
204-
if (!section.hasPath(key)) {
205-
return null;
206-
}
207-
ConfigObject conf = section.getObject(key);
208-
DbOptionOverride o = new DbOptionOverride();
209-
if (conf.containsKey("createIfMissing")) {
210-
o.setCreateIfMissing(
211-
Boolean.parseBoolean(conf.get("createIfMissing").unwrapped().toString()));
212-
}
213-
if (conf.containsKey("paranoidChecks")) {
214-
o.setParanoidChecks(
215-
Boolean.parseBoolean(conf.get("paranoidChecks").unwrapped().toString()));
216-
}
217-
if (conf.containsKey("verifyChecksums")) {
218-
o.setVerifyChecksums(
219-
Boolean.parseBoolean(conf.get("verifyChecksums").unwrapped().toString()));
220-
}
221-
if (conf.containsKey("compressionType")) {
222-
String param = conf.get("compressionType").unwrapped().toString();
223-
try {
224-
o.setCompressionType(Integer.parseInt(param));
225-
} catch (NumberFormatException e) {
226-
throwIllegalArgumentException("compressionType", Integer.class, param);
227-
}
228-
}
203+
// Shared LevelDB option parser used by both readDbOption and readProperties.
204+
// Fills the given target (boxed fields, null means "not specified by user") so the
205+
// same parser can populate a plain DbOptionOverride or a PropertyConfig (which extends it).
206+
private static void readLevelDbOptions(ConfigObject conf, DbOptionOverride o) {
229207
if (conf.containsKey("blockSize")) {
230208
String param = conf.get("blockSize").unwrapped().toString();
231209
try {
@@ -258,9 +236,43 @@ private static DbOptionOverride readDbOption(Config section, String key) {
258236
throwIllegalArgumentException("maxOpenFiles", Integer.class, param);
259237
}
260238
}
239+
}
240+
241+
// Read optional LevelDB option override for default/defaultM/defaultL keys.
242+
private static DbOptionOverride readDbOption(Config section, String key) {
243+
if (!section.hasPath(key)) {
244+
return null;
245+
}
246+
DbOptionOverride o = new DbOptionOverride();
247+
readLevelDbOptions(section.getObject(key), o);
261248
return o;
262249
}
263250

251+
// Parse storage.properties list manually: ConfigBeanFactory requires every bean field to be
252+
// present in each list item, but name+path-only entries (all LevelDB opts commented out) are
253+
// valid — missing fields fall back to PropertyConfig Java defaults.
254+
private static List<PropertyConfig> readProperties(Config section) {
255+
if (!section.hasPath("properties")) {
256+
return new ArrayList<>();
257+
}
258+
List<? extends ConfigObject> items = section.getObjectList("properties");
259+
List<PropertyConfig> result = new ArrayList<>(items.size());
260+
for (ConfigObject obj : items) {
261+
PropertyConfig p = new PropertyConfig();
262+
if (obj.containsKey("name")) {
263+
p.setName(obj.get("name").unwrapped().toString());
264+
}
265+
if (obj.containsKey("path")) {
266+
p.setPath(obj.get("path").unwrapped().toString());
267+
}
268+
// Boxed nullable fields: unset options stay null so they inherit the per-tier
269+
// defaults applied by newDefaultDbOptions instead of resetting them.
270+
readLevelDbOptions(obj, p);
271+
result.add(p);
272+
}
273+
return result;
274+
}
275+
264276
private static void throwIllegalArgumentException(String param, Class<?> type, String actual) {
265277
throw new IllegalArgumentException(
266278
String.format("[storage.properties] %s must be %s type, actual: %s.",

common/src/main/resources/reference.conf

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,49 +44,68 @@ net {
4444
}
4545

4646
storage {
47-
# Database engine: "LEVELDB" or "ROCKSDB" (ARM only supports ROCKSDB)
47+
# Database engine: "LEVELDB" or "ROCKSDB" (ARM only supports ROCKSDB), case-insensitive
4848
db.engine = "LEVELDB"
49+
50+
# Controls the database write strategy.
51+
# true - Synchronous writes. Higher durability, lower performance.
52+
# false - Asynchronous writes. Higher performance, but recent writes may be
53+
# lost if the machine crashes before data is flushed to disk.
54+
# Asynchronous writes can significantly improve FullNode block sync performance.
4955
db.sync = false
56+
5057
db.directory = "database"
5158

5259
# Whether to write transaction result in transactionRetStore
5360
transHistory.switch = "on"
5461

55-
# Per-database LevelDB option overrides. Default: empty (all databases use global defaults).
56-
# setting can improve leveldb performance .... start, deprecated for arm
57-
# node: if this will increase process fds, you may check your ulimit if 'too many open files' error occurs
58-
# see https://github.com/tronprotocol/tips/blob/master/tip-343.md for detail
59-
# if you find block sync has lower performance, you can try this settings
62+
# Per-database LevelDB option overrides.Default: empty. All databases use global LevelDB settings.
63+
# These settings can be tuned to improve database performance during block synchronization.
64+
# Note:
65+
# - Increasing `maxOpenFiles` may significantly increase file descriptor usage.
66+
# - If "Too many open files" errors occur, check the system `ulimit` configuration.
67+
# - See TIP-343 for tuning recommendations:
68+
# https://github.com/tronprotocol/tips/blob/master/tip-343.md
69+
# The following presets are provided as default. If block synchronization
70+
# performance is unsatisfactory, consider adjusting the settings accordingly.
71+
#
72+
# Global default settings:
6073
# default = {
74+
# blockSize = 4096, // 4 KB
75+
# writeBufferSize = 16777216, // 16 MB
76+
# cacheSize = 33554432, // 32 MB
6177
# maxOpenFiles = 100
6278
# }
79+
# Default for bulk-read databases: code, contract
6380
# defaultM = {
64-
# maxOpenFiles = 500
81+
# blockSize = 4096, // 4 KB
82+
# writeBufferSize = 67108864, // 64 MB
83+
# cacheSize = 33554432, // 32 MB
84+
# maxOpenFiles = 100 // recommend 500 for production
6585
# }
86+
# Default for frequently accessed databases: account, delegation, storage-row
6687
# defaultL = {
67-
# maxOpenFiles = 1000
88+
# blockSize = 4096, // 4 KB
89+
# writeBufferSize = 67108864, // 64 MB
90+
# cacheSize = 33554432, // 32 MB
91+
# maxOpenFiles = 100 // recommend 1000 for production
6892
# }
69-
# setting can improve leveldb performance .... end, deprecated for arm
7093

7194
# Per-database storage configuration overrides. Otherwise databases use global defaults and store
7295
# data in "output-directory" or the directory specified by the "-d" / "--output-directory" option.
7396
# Attention: name is a required field that must be set!
7497
# The name and path properties take effect for both LevelDB and RocksDB storage engines,
75-
# while additional properties (createIfMissing, paranoidChecks, compressionType, etc.)
98+
# while additional 4 properties (blockSize, writeBufferSize, cacheSize, maxOpenFiles)
7699
# only take effect when using LevelDB.
77100
# Example:
78101
# properties = [
79102
# {
80103
# name = "account",
81104
# path = "storage_directory_test",
82-
# createIfMissing = true, // deprecated for arm start
83-
# paranoidChecks = true,
84-
# verifyChecksums = true,
85-
# compressionType = 1, // compressed with snappy
86105
# blockSize = 4096, // 4 KB = 4 * 1024 B
87106
# writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
88107
# cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B
89-
# maxOpenFiles = 100 // deprecated for arm end
108+
# maxOpenFiles = 100
90109
# },
91110
# ]
92111
properties = []

0 commit comments

Comments
 (0)