diff --git a/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java index 5979ae5bf83..4853de64116 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java @@ -143,6 +143,13 @@ public void addTransaction(TransactionCapsule pendingTrx) { getTransactions().add(pendingTrx); } + public void addAllTransactions(List pendingTrxs) { + List list = pendingTrxs.stream().map(TransactionCapsule::getInstance).collect( + Collectors.toList()); + this.block = this.block.toBuilder().addAllTransactions(list).build(); + getTransactions().addAll(pendingTrxs); + } + public List getTransactions() { return transactions; } diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionRetCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionRetCapsule.java index 499cbcb3b42..94188229d98 100644 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionRetCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionRetCapsule.java @@ -1,6 +1,7 @@ package org.tron.core.capsule; import com.google.protobuf.InvalidProtocolBufferException; +import java.util.List; import java.util.Objects; import lombok.extern.slf4j.Slf4j; import org.tron.core.exception.BadItemException; @@ -29,7 +30,7 @@ public TransactionRetCapsule() { public TransactionRetCapsule(byte[] data) throws BadItemException { try { - this.transactionRet = transactionRet.parseFrom(data); + this.transactionRet = TransactionRet.parseFrom(data); } catch (InvalidProtocolBufferException e) { throw new BadItemException("TransactionInfoCapsule proto data parse exception"); } @@ -39,6 +40,10 @@ public void addTransactionInfo(TransactionInfo result) { this.transactionRet = this.transactionRet.toBuilder().addTransactioninfo(result).build(); } + public void addAllTransactionInfos(List results) { + this.transactionRet = this.transactionRet.toBuilder().addAllTransactioninfo(results).build(); + } + @Override public byte[] getData() { if (Objects.isNull(transactionRet)) { diff --git a/chainbase/src/main/java/org/tron/core/db2/common/DB.java b/chainbase/src/main/java/org/tron/core/db2/common/DB.java index fed5e52bb04..eae529c5ca9 100644 --- a/chainbase/src/main/java/org/tron/core/db2/common/DB.java +++ b/chainbase/src/main/java/org/tron/core/db2/common/DB.java @@ -15,7 +15,7 @@ public interface DB extends Iterable>, Instance> void remove(K k); - Iterator iterator(); + Iterator> iterator(); void close(); diff --git a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java index ba6c77d43a2..496a0fd09ac 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java @@ -15,8 +15,6 @@ public abstract class AbstractSnapshot implements Snapshot { protected WeakReference next; - protected boolean isOptimized; - @Override public Snapshot advance() { return new SnapshotImpl(this); @@ -36,9 +34,4 @@ public void setNext(Snapshot next) { public String getDbName() { return db.getDbName(); } - - @Override - public boolean isOptimized(){ - return isOptimized; - } } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java index db59713f34d..e1ca149b207 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java @@ -46,6 +46,4 @@ static boolean isImpl(Snapshot snapshot) { void updateSolidity(); String getDbName(); - - boolean isOptimized(); } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java index 83c55c238ea..ae8073f668b 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java @@ -30,16 +30,6 @@ public class SnapshotImpl extends AbstractSnapshot { } previous = snapshot; snapshot.setNext(this); - // inherit - isOptimized = snapshot.isOptimized(); - // merge for DynamicPropertiesStore,about 100 keys - if (isOptimized) { - if (root == previous ){ - Streams.stream(root.iterator()).forEach( e -> put(e.getKey(),e.getValue())); - }else { - merge(previous); - } - } } @Override @@ -50,10 +40,6 @@ public byte[] get(byte[] key) { private byte[] get(Snapshot head, byte[] key) { Snapshot snapshot = head; Value value; - if (isOptimized) { - value = db.get(Key.of(key)); - return value == null ? null: value.getBytes(); - } while (Snapshot.isImpl(snapshot)) { if ((value = ((SnapshotImpl) snapshot).db.get(Key.of(key))) != null) { return value.getBytes(); diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java index 9afb5277b9c..fe4732d272e 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java @@ -1,14 +1,17 @@ package org.tron.core.db2.core; -import ch.qos.logback.core.encoder.ByteArrayUtil; import com.google.common.collect.Maps; import com.google.common.collect.Streams; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import lombok.Getter; +import org.tron.common.cache.CacheManager; +import org.tron.common.cache.TronCache; +import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.core.ChainBaseManager; import org.tron.core.capsule.AccountCapsule; @@ -23,11 +26,17 @@ public class SnapshotRoot extends AbstractSnapshot { private Snapshot solidity; private boolean isAccountDB; + private TronCache cache; + private static final List CACHE_DBS = CommonParameter.getInstance() + .getStorage().getCacheDbs(); + public SnapshotRoot(DB db) { this.db = db; solidity = this; - isOptimized = "properties".equalsIgnoreCase(db.getDbName()); isAccountDB = "account".equalsIgnoreCase(db.getDbName()); + if (CACHE_DBS.contains(this.db.getDbName())) { + this.cache = CacheManager.allocate(this.db.getDbName()); + } } private boolean needOptAsset() { @@ -37,11 +46,18 @@ private boolean needOptAsset() { @Override public byte[] get(byte[] key) { - return db.get(key); + WrappedByteArray cache = getCache(key); + if (cache != null) { + return cache.getBytes(); + } + byte[] value = db.get(key); + putCache(key, value); + return value; } @Override public void put(byte[] key, byte[] value) { + byte[] v = value; if (needOptAsset()) { if (ByteArray.isEmpty(value)) { remove(key); @@ -56,10 +72,10 @@ public void put(byte[] key, byte[] value) { } assetStore.putAccount(item.getInstance()); item.clearAsset(); - db.put(key, item.getData()); - } else { - db.put(key, value); + v = item.getData(); } + db.put(key, v); + putCache(key, v); } @Override @@ -68,6 +84,7 @@ public void remove(byte[] key) { ChainBaseManager.getInstance().getAccountAssetStore().deleteAccount(key); } db.remove(key); + putCache(key, null); } @Override @@ -81,6 +98,7 @@ public void merge(Snapshot from) { processAccount(batch); } else { ((Flusher) db).flush(batch); + putCache(batch); } } @@ -97,6 +115,7 @@ public void merge(List snapshots) { processAccount(batch); } else { ((Flusher) db).flush(batch); + putCache(batch); } } @@ -120,11 +139,37 @@ private void processAccount(Map batch) { } }); ((Flusher) db).flush(accounts); + putCache(accounts); if (assets.size() > 0) { assetStore.updateByBatch(AccountAssetStore.convert(assets)); } } + private boolean cached() { + return Objects.nonNull(this.cache); + } + + private void putCache(byte[] key, byte[] value) { + if (cached()) { + cache.put(WrappedByteArray.of(key), WrappedByteArray.of(value)); + } + } + + private void putCache(Map values) { + if (cached()) { + values.forEach(cache::put); + } + } + + private WrappedByteArray getCache(byte[] key) { + if (cached()) { + return cache.getIfPresent(WrappedByteArray.of(key)); + } + return null; + } + + // second cache + @Override public Snapshot retreat() { return this; @@ -142,11 +187,13 @@ public Iterator> iterator() { @Override public void close() { + CacheManager.release(this.getDbName()); ((Flusher) db).close(); } @Override public void reset() { + CacheManager.release(this.getDbName()); ((Flusher) db).reset(); } diff --git a/common/src/main/java/org/tron/common/cache/CacheManager.java b/common/src/main/java/org/tron/common/cache/CacheManager.java new file mode 100644 index 00000000000..18f2e0c118c --- /dev/null +++ b/common/src/main/java/org/tron/common/cache/CacheManager.java @@ -0,0 +1,45 @@ +package org.tron.common.cache; + +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.collect.Maps; +import java.util.Map; +import java.util.stream.Collectors; +import org.tron.common.parameter.CommonParameter; + +public class CacheManager { + + private static final Map> CACHES = Maps.newConcurrentMap(); + + public static TronCache allocate(String name) { + TronCache cache = new TronCache<>(name, CommonParameter.getInstance() + .getStorage().getCacheStrategy(name)); + CACHES.put(name, cache); + return cache; + } + + public static TronCache allocate(String name, String strategy) { + TronCache cache = new TronCache<>(name, strategy); + CACHES.put(name, cache); + return cache; + } + + public static TronCache allocate(String name, String strategy, + CacheLoader loader) { + TronCache cache = new TronCache<>(name, strategy, loader); + CACHES.put(name, cache); + return cache; + } + + public static void release(String name) { + TronCache cache = CACHES.remove(name); + if (cache != null) { + cache.invalidateAll(); + } + } + + public static Map stats() { + return CACHES.values().stream().collect(Collectors.toMap(TronCache::getName, TronCache::stats)); + } + +} diff --git a/common/src/main/java/org/tron/common/cache/TronCache.java b/common/src/main/java/org/tron/common/cache/TronCache.java new file mode 100644 index 00000000000..fe71d329fe2 --- /dev/null +++ b/common/src/main/java/org/tron/common/cache/TronCache.java @@ -0,0 +1,66 @@ +package org.tron.common.cache; + +import com.google.common.base.Objects; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import lombok.Getter; + +public class TronCache { + + private static final int CPUS = Runtime.getRuntime().availableProcessors(); + + @Getter + private final String name; + private final Cache cache; + + TronCache(String name, String strategy) { + this.name = name; + this.cache = CacheBuilder.from(strategy).concurrencyLevel(CPUS).recordStats().build(); + } + + TronCache(String name, String strategy, CacheLoader loader) { + this.name = name; + this.cache = CacheBuilder.from(strategy).concurrencyLevel(CPUS).recordStats().build(loader); + } + + public void put(K k, V v) { + this.cache.put(k, v); + } + + public V getIfPresent(K k) { + return this.cache.getIfPresent(k); + } + + public V get(K k, Callable loader) throws ExecutionException { + return this.cache.get(k, loader); + } + + public CacheStats stats() { + return this.cache.stats(); + } + + public void invalidateAll() { + this.cache.invalidateAll(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TronCache tronCache = (TronCache) o; + return Objects.equal(name, tronCache.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } +} diff --git a/common/src/main/java/org/tron/common/prometheus/GuavaCacheExports.java b/common/src/main/java/org/tron/common/prometheus/GuavaCacheExports.java new file mode 100644 index 00000000000..e8e39d5b3ad --- /dev/null +++ b/common/src/main/java/org/tron/common/prometheus/GuavaCacheExports.java @@ -0,0 +1,89 @@ +package org.tron.common.prometheus; + +import static io.prometheus.client.SampleNameFilter.ALLOW_ALL; + +import io.prometheus.client.Collector; +import io.prometheus.client.GaugeMetricFamily; +import io.prometheus.client.Predicate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.tron.common.cache.CacheManager; + +/** + * Exports metrics about for guava cache. + *

+ * Example usage: + *

+ * {@code
+ *   new GuavaCacheExports().register();
+ * }
+ * 
+ * Example metrics being exported: + *
+ *   tron:guava_cache_hit_rate{type="account"} 0.135679
+ *   tron:guava_cache_request{type="account"} 3000
+ * 
+ */ +public class GuavaCacheExports extends Collector { + + private static final String TRON_GUAVA_CACHE_HIT_RATE = "tron:guava_cache_hit_rate"; + private static final String TRON_GUAVA_CACHE_REQUEST = "tron:guava_cache_request"; + private static final String TRON_GUAVA_CACHE_EVICTION_COUNT = "tron:guava_cache_eviction_count"; + + + public GuavaCacheExports() { + } + + + void addHitRateMetrics(List sampleFamilies, Predicate nameFilter) { + if (nameFilter.test(TRON_GUAVA_CACHE_HIT_RATE)) { + GaugeMetricFamily hitRate = new GaugeMetricFamily( + TRON_GUAVA_CACHE_HIT_RATE, + "Hit rate of a guava cache.", + Collections.singletonList("type")); + CacheManager.stats().forEach((k, v) -> hitRate + .addMetric(Collections.singletonList(k), v.hitRate())); + sampleFamilies.add(hitRate); + } + } + + void addRequestMetrics(List sampleFamilies, Predicate nameFilter) { + if (nameFilter.test(TRON_GUAVA_CACHE_REQUEST)) { + GaugeMetricFamily request = new GaugeMetricFamily( + TRON_GUAVA_CACHE_REQUEST, + "Request of a guava cache.", + Collections.singletonList("type")); + CacheManager.stats().forEach((k, v) -> request + .addMetric(Collections.singletonList(k), v.requestCount())); + sampleFamilies.add(request); + } + } + + void addEvictionCountMetrics(List sampleFamilies, + Predicate nameFilter) { + if (nameFilter.test(TRON_GUAVA_CACHE_EVICTION_COUNT)) { + GaugeMetricFamily request = new GaugeMetricFamily( + TRON_GUAVA_CACHE_EVICTION_COUNT, + "Eviction count of a guava cache.", + Collections.singletonList("type")); + CacheManager.stats().forEach((k, v) -> request + .addMetric(Collections.singletonList(k), v.evictionCount())); + sampleFamilies.add(request); + } + } + + @Override + public List collect() { + return collect(null); + } + + @Override + public List collect(Predicate nameFilter) { + List mfs = new ArrayList<>(); + addHitRateMetrics(mfs, nameFilter == null ? ALLOW_ALL : nameFilter); + addRequestMetrics(mfs, nameFilter == null ? ALLOW_ALL : nameFilter); + addEvictionCountMetrics(mfs, nameFilter == null ? ALLOW_ALL : nameFilter); + return mfs; + } +} diff --git a/common/src/main/java/org/tron/common/prometheus/Metrics.java b/common/src/main/java/org/tron/common/prometheus/Metrics.java index fd13fa3fa5a..3f37cf331aa 100644 --- a/common/src/main/java/org/tron/common/prometheus/Metrics.java +++ b/common/src/main/java/org/tron/common/prometheus/Metrics.java @@ -27,6 +27,7 @@ public static synchronized void init() { try { DefaultExports.initialize(); new OperatingSystemExports().register(CollectorRegistry.defaultRegistry); + new GuavaCacheExports().register(CollectorRegistry.defaultRegistry); int port = CommonParameter.getInstance().getMetricsPrometheusPort(); new HTTPServer.Builder().withPort(port).build(); logger.info("prometheus exposed on port : {}", port); diff --git a/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java b/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java index 69965bf39ab..ac743ebc7b7 100644 --- a/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java +++ b/common/src/main/java/org/tron/common/utils/DbOptionalsUtils.java @@ -12,7 +12,6 @@ public class DbOptionalsUtils { public static final int DEFAULT_BLOCK_SIZE = 4 * 1024; public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024 * 1024; public static final int DEFAULT_WRITE_BUFFER_SIZE_M = 64 * 1024 * 1024; - public static final int DEFAULT_WRITE_BUFFER_SIZE_L = 256 * 1024 * 1024; public static final long DEFAULT_CACHE_SIZE = 32 * 1024 * 1024L; public static final int DEFAULT_MAX_OPEN_FILES = 100; /** @@ -30,13 +29,10 @@ public class DbOptionalsUtils { */ public static final int DEFAULT_MAX_OPEN_FILES_L = 100; // Read a lot - public static final List DB_M = Arrays.asList( "code", "contract"); + public static final List DB_M = Arrays.asList("code", "contract"); // Read frequently public static final List DB_L = Arrays.asList("account", "delegation", "storage-row"); - // Write frequently - public static final List DB_WRITE_L = Arrays.asList("block", "account", - "transactionRetStore", "storage-row", "trans"); private DbOptionalsUtils() { throw new IllegalStateException("DbOptionalsUtils class"); @@ -80,10 +76,6 @@ public static Options newDefaultDbOptions(String name ,Options defaultOptions) { adjustDefaultDbOptionsForL(dbOptions); } - if (DB_WRITE_L.contains(name)) { - adjustDefaultDbOptionsForWriteL(dbOptions); - } - return dbOptions; } @@ -97,8 +89,4 @@ private static void adjustDefaultDbOptionsForL(Options defaultOptions) { defaultOptions.writeBufferSize(DEFAULT_WRITE_BUFFER_SIZE_M); } - private static void adjustDefaultDbOptionsForWriteL(Options defaultOptions) { - - defaultOptions.writeBufferSize(DEFAULT_WRITE_BUFFER_SIZE_L); - } } diff --git a/common/src/main/java/org/tron/core/config/args/Storage.java b/common/src/main/java/org/tron/core/config/args/Storage.java index 1ea7e00eb1f..11b26a8b2c2 100644 --- a/common/src/main/java/org/tron/core/config/args/Storage.java +++ b/common/src/main/java/org/tron/core/config/args/Storage.java @@ -15,11 +15,17 @@ package org.tron.core.config.args; +import com.google.common.collect.Maps; import com.typesafe.config.Config; import com.typesafe.config.ConfigObject; import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; @@ -69,6 +75,33 @@ public class Storage { private static final String MAX_OPEN_FILES_CONFIG_KEY = "maxOpenFiles"; private static final String EVENT_SUBSCRIBE_CONTRACT_PARSE = "event.subscribe.contractParse"; + private static final String CACHE_STRATEGIES = "storage.cache.strategies"; + private static final String CACHE_STRATEGY = "storage.cache.strategy"; + private static final String CACHE_STRATEGY_DEFAULT = + "initialCapacity=500,maximumSize=1000,expireAfterAccess=30s"; + + private static final String CACHE_STRATEGY_SMALL_DEFAULT = + "initialCapacity=10,maximumSize=100,expireAfterAccess=5m"; + private static final List CACHE_SMALL_DBS = Arrays.asList("recent-block", "witness", + "witness_schedule", "DelegatedResource", "DelegatedResourceAccountIndex", + "votes", "abi"); + + private static final String CACHE_STRATEGY_NORMAL_DEFAULT = + "initialCapacity=100,maximumSize=500,expireAfterAccess=5m"; + private static final List CACHE_NORMAL_DBS = Arrays.asList("code", "contract", + "asset-issue-v2", "properties"); + + private static final String CACHE_STRATEGY_BIG_DEFAULT = + "initialCapacity=1000,maximumSize=10000,expireAfterAccess=1m"; + public static final List CACHE_BIG_DBS = Collections.singletonList("delegation"); + + private static final String CACHE_STRATEGY_HUGE_DEFAULT = + "initialCapacity=1000,maximumSize=20000,expireAfterAccess=2m"; + private static final List CACHE_HUGE_DBS = Arrays.asList("storage-row", "account"); + + private static final List CACHE_DBS = Stream.of(CACHE_SMALL_DBS, CACHE_NORMAL_DBS, + CACHE_BIG_DBS, CACHE_HUGE_DBS).flatMap(Collection::stream).collect(Collectors.toList()); + /** * Default values of directory */ @@ -126,6 +159,15 @@ public class Storage { @Setter private int estimatedBlockTransactions; + // second cache + private String cacheStrategy = CACHE_STRATEGY_DEFAULT; + + private final Map cacheStrategies = Maps.newConcurrentMap(); + + @Getter + private final List cacheDbs = CACHE_DBS; + // second cache + /** * Key: dbName, Value: Property object of that database */ @@ -188,6 +230,34 @@ public static int getEstimatedTransactionsFromConfig(final Config config) { return estimatedTransactions; } + + public void setCacheStrategies(Config config) { + if (config.hasPath(CACHE_STRATEGY)) { + this.cacheStrategy = config.getString(CACHE_STRATEGY); + } + if (config.hasPath(CACHE_STRATEGIES)) { + config.getConfig(CACHE_STRATEGIES).resolve().entrySet().forEach(c -> + this.cacheStrategies.put(c.getKey(), c.getValue().unwrapped().toString())); + } + } + + public String getCacheStrategy(String dbName) { + String defaultStrategy = this.cacheStrategy; + if (CACHE_SMALL_DBS.contains(dbName)) { + defaultStrategy = CACHE_STRATEGY_SMALL_DEFAULT; + } + if (CACHE_NORMAL_DBS.contains(dbName)) { + defaultStrategy = CACHE_STRATEGY_NORMAL_DEFAULT; + } + if (CACHE_BIG_DBS.contains(dbName)) { + defaultStrategy = CACHE_STRATEGY_BIG_DEFAULT; + } + if (CACHE_HUGE_DBS.contains(dbName)) { + defaultStrategy = CACHE_STRATEGY_HUGE_DEFAULT; + } + return this.cacheStrategies.getOrDefault(dbName, defaultStrategy); + } + private Property createProperty(final ConfigObject conf) { Property property = new Property(); diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 16ede8cdbaa..c688c109d52 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -411,6 +411,7 @@ public static void setParam(final String[] args, final String confFileName) { PARAMETER.storage.setDefaultDbOptions(config); PARAMETER.storage.setPropertyMapFromConfig(config); + PARAMETER.storage.setCacheStrategies(config); PARAMETER.seedNode = new SeedNode(); PARAMETER.seedNode.setIpList(Optional.ofNullable(PARAMETER.seedNodes) diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 457bcda999d..fe9084f35bc 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1456,16 +1456,17 @@ public BlockCapsule generateBlock(Miner miner, long blockTime, long timeout) { } } - TransactionRetCapsule transactionRetCapsule = new TransactionRetCapsule(blockCapsule); - Set accountSet = new HashSet<>(); AtomicInteger shieldedTransCounts = new AtomicInteger(0); + List toBePacked = new ArrayList<>(); + long currentSize = blockCapsule.getInstance().getSerializedSize(); + boolean isSort = Args.getInstance().isOpenTransactionSort(); while (pendingTransactions.size() > 0 || rePushTransactions.size() > 0) { boolean fromPending = false; TransactionCapsule trx; if (pendingTransactions.size() > 0) { trx = pendingTransactions.peek(); - if (Args.getInstance().isOpenTransactionSort()) { + if (isSort) { TransactionCapsule trxRepush = rePushTransactions.peek(); if (trxRepush == null || trx.getOrder() >= trxRepush.getOrder()) { fromPending = true; @@ -1501,24 +1502,24 @@ public BlockCapsule generateBlock(Miner miner, long blockTime, long timeout) { } // check the block size - if ((blockCapsule.getInstance().getSerializedSize() + trx.getSerializedSize() + 3) - > ChainConstant.BLOCK_SIZE) { + if ((currentSize = currentSize + trx.getSerializedSize() + 3) > ChainConstant.BLOCK_SIZE) { postponedTrxCount++; - continue; + break; } //shielded transaction - if (isShieldedTransaction(trx.getInstance()) + Transaction transaction = trx.getInstance(); + if (isShieldedTransaction(transaction) && shieldedTransCounts.incrementAndGet() > SHIELDED_TRANS_IN_BLOCK_COUNTS) { continue; } //multi sign transaction - Contract contract = trx.getInstance().getRawData().getContract(0); + Contract contract = transaction.getRawData().getContract(0); byte[] owner = TransactionCapsule.getOwner(contract); String ownerAddress = ByteArray.toHexString(owner); if (accountSet.contains(ownerAddress)) { continue; } else { - if (isMultiSignTransaction(trx.getInstance())) { + if (isMultiSignTransaction(transaction)) { accountSet.add(ownerAddress); } } @@ -1528,19 +1529,16 @@ public BlockCapsule generateBlock(Miner miner, long blockTime, long timeout) { // apply transaction try (ISession tmpSession = revokingStore.buildSession()) { accountStateCallBack.preExeTrans(); - TransactionInfo result = processTransaction(trx, blockCapsule); + processTransaction(trx, blockCapsule); accountStateCallBack.exeTransFinish(); tmpSession.merge(); - blockCapsule.addTransaction(trx); - if (Objects.nonNull(result)) { - transactionRetCapsule.addTransactionInfo(result); - } + toBePacked.add(trx); } catch (Exception e) { logger.error("Process trx {} failed when generating block: {}", trx.getTransactionId(), e.getMessage()); } } - + blockCapsule.addAllTransactions(toBePacked); accountStateCallBack.executeGenerateFinish(); session.reset(); @@ -1641,6 +1639,7 @@ private void processBlock(BlockCapsule block, List txs) try { merkleContainer.resetCurrentMerkleTree(); accountStateCallBack.preExecute(block); + List results = new ArrayList<>(); for (TransactionCapsule transactionCapsule : block.getTransactions()) { transactionCapsule.setBlockNum(block.getNum()); if (block.generatedByMyself) { @@ -1650,9 +1649,10 @@ private void processBlock(BlockCapsule block, List txs) TransactionInfo result = processTransaction(transactionCapsule, block); accountStateCallBack.exeTransFinish(); if (Objects.nonNull(result)) { - transactionRetCapsule.addTransactionInfo(result); + results.add(result); } } + transactionRetCapsule.addAllTransactionInfos(results); accountStateCallBack.executePushFinish(); } finally { accountStateCallBack.exceptionFinish(); diff --git a/framework/src/test/java/org/tron/core/config/args/StorageTest.java b/framework/src/test/java/org/tron/core/config/args/StorageTest.java index a6d9d9e7f73..eb349a2d146 100644 --- a/framework/src/test/java/org/tron/core/config/args/StorageTest.java +++ b/framework/src/test/java/org/tron/core/config/args/StorageTest.java @@ -93,7 +93,7 @@ public void getOptions() { Assert.assertEquals(1000, options.maxOpenFiles()); options = StorageUtils.getOptionsByDbName("trans"); - Assert.assertEquals(256 * 1024 * 1024, options.writeBufferSize()); + Assert.assertEquals(16 * 1024 * 1024, options.writeBufferSize()); Assert.assertEquals(50, options.maxOpenFiles()); }