Skip to content

Commit e54c324

Browse files
authored
Merge pull request #4740 from halibobo1205/feat/second_cache
feat(db): improve performance for db query
2 parents 8d0deec + 74ec816 commit e54c324

File tree

19 files changed

+458
-74
lines changed

19 files changed

+458
-74
lines changed

chainbase/src/main/java/org/tron/core/db2/common/DB.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public interface DB<K, V> extends Iterable<Map.Entry<K, V>>, Instance<DB<K, V>>
1515

1616
void remove(K k);
1717

18-
Iterator iterator();
18+
Iterator<Map.Entry<K, V>> iterator();
1919

2020
void close();
2121

chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ public abstract class AbstractSnapshot<K, V> implements Snapshot {
1515

1616
protected WeakReference<Snapshot> next;
1717

18-
protected boolean isOptimized;
19-
2018
@Override
2119
public Snapshot advance() {
2220
return new SnapshotImpl(this);
@@ -36,9 +34,4 @@ public void setNext(Snapshot next) {
3634
public String getDbName() {
3735
return db.getDbName();
3836
}
39-
40-
@Override
41-
public boolean isOptimized(){
42-
return isOptimized;
43-
}
4437
}

chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,4 @@ static boolean isImpl(Snapshot snapshot) {
4646
void updateSolidity();
4747

4848
String getDbName();
49-
50-
boolean isOptimized();
5149
}

chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,6 @@ public class SnapshotImpl extends AbstractSnapshot<Key, Value> {
3030
}
3131
previous = snapshot;
3232
snapshot.setNext(this);
33-
// inherit
34-
isOptimized = snapshot.isOptimized();
35-
// merge for DynamicPropertiesStore,about 100 keys
36-
if (isOptimized) {
37-
if (root == previous ){
38-
Streams.stream(root.iterator()).forEach( e -> put(e.getKey(),e.getValue()));
39-
}else {
40-
merge(previous);
41-
}
42-
}
4333
}
4434

4535
@Override
@@ -50,10 +40,6 @@ public byte[] get(byte[] key) {
5040
private byte[] get(Snapshot head, byte[] key) {
5141
Snapshot snapshot = head;
5242
Value value;
53-
if (isOptimized) {
54-
value = db.get(Key.of(key));
55-
return value == null ? null: value.getBytes();
56-
}
5743
while (Snapshot.isImpl(snapshot)) {
5844
if ((value = ((SnapshotImpl) snapshot).db.get(Key.of(key))) != null) {
5945
return value.getBytes();

chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package org.tron.core.db2.core;
22

3-
import ch.qos.logback.core.encoder.ByteArrayUtil;
43
import com.google.common.collect.Maps;
54
import com.google.common.collect.Streams;
65
import java.util.HashMap;
76
import java.util.Iterator;
87
import java.util.List;
98
import java.util.Map;
9+
import java.util.Objects;
1010
import java.util.stream.Collectors;
1111
import lombok.Getter;
12+
import org.tron.common.cache.CacheManager;
13+
import org.tron.common.cache.CacheType;
14+
import org.tron.common.cache.TronCache;
15+
import org.tron.common.parameter.CommonParameter;
1216
import org.tron.common.utils.ByteArray;
1317
import org.tron.core.ChainBaseManager;
1418
import org.tron.core.capsule.AccountCapsule;
@@ -23,11 +27,17 @@ public class SnapshotRoot extends AbstractSnapshot<byte[], byte[]> {
2327
private Snapshot solidity;
2428
private boolean isAccountDB;
2529

30+
private TronCache<WrappedByteArray, WrappedByteArray> cache;
31+
private static final List<String> CACHE_DBS = CommonParameter.getInstance()
32+
.getStorage().getCacheDbs();
33+
2634
public SnapshotRoot(DB<byte[], byte[]> db) {
2735
this.db = db;
2836
solidity = this;
29-
isOptimized = "properties".equalsIgnoreCase(db.getDbName());
3037
isAccountDB = "account".equalsIgnoreCase(db.getDbName());
38+
if (CACHE_DBS.contains(this.db.getDbName())) {
39+
this.cache = CacheManager.allocate(CacheType.findByType(this.db.getDbName()));
40+
}
3141
}
3242

3343
private boolean needOptAsset() {
@@ -37,11 +47,18 @@ private boolean needOptAsset() {
3747

3848
@Override
3949
public byte[] get(byte[] key) {
40-
return db.get(key);
50+
WrappedByteArray cache = getCache(key);
51+
if (cache != null) {
52+
return cache.getBytes();
53+
}
54+
byte[] value = db.get(key);
55+
putCache(key, value);
56+
return value;
4157
}
4258

4359
@Override
4460
public void put(byte[] key, byte[] value) {
61+
byte[] v = value;
4562
if (needOptAsset()) {
4663
if (ByteArray.isEmpty(value)) {
4764
remove(key);
@@ -56,10 +73,10 @@ public void put(byte[] key, byte[] value) {
5673
}
5774
assetStore.putAccount(item.getInstance());
5875
item.clearAsset();
59-
db.put(key, item.getData());
60-
} else {
61-
db.put(key, value);
76+
v = item.getData();
6277
}
78+
db.put(key, v);
79+
putCache(key, v);
6380
}
6481

6582
@Override
@@ -68,6 +85,7 @@ public void remove(byte[] key) {
6885
ChainBaseManager.getInstance().getAccountAssetStore().deleteAccount(key);
6986
}
7087
db.remove(key);
88+
putCache(key, null);
7189
}
7290

7391
@Override
@@ -81,6 +99,7 @@ public void merge(Snapshot from) {
8199
processAccount(batch);
82100
} else {
83101
((Flusher) db).flush(batch);
102+
putCache(batch);
84103
}
85104
}
86105

@@ -97,6 +116,7 @@ public void merge(List<Snapshot> snapshots) {
97116
processAccount(batch);
98117
} else {
99118
((Flusher) db).flush(batch);
119+
putCache(batch);
100120
}
101121
}
102122

@@ -120,11 +140,37 @@ private void processAccount(Map<WrappedByteArray, WrappedByteArray> batch) {
120140
}
121141
});
122142
((Flusher) db).flush(accounts);
143+
putCache(accounts);
123144
if (assets.size() > 0) {
124145
assetStore.updateByBatch(AccountAssetStore.convert(assets));
125146
}
126147
}
127148

149+
private boolean cached() {
150+
return Objects.nonNull(this.cache);
151+
}
152+
153+
private void putCache(byte[] key, byte[] value) {
154+
if (cached()) {
155+
cache.put(WrappedByteArray.of(key), WrappedByteArray.of(value));
156+
}
157+
}
158+
159+
private void putCache(Map<WrappedByteArray, WrappedByteArray> values) {
160+
if (cached()) {
161+
values.forEach(cache::put);
162+
}
163+
}
164+
165+
private WrappedByteArray getCache(byte[] key) {
166+
if (cached()) {
167+
return cache.getIfPresent(WrappedByteArray.of(key));
168+
}
169+
return null;
170+
}
171+
172+
// second cache
173+
128174
@Override
129175
public Snapshot retreat() {
130176
return this;
@@ -142,11 +188,17 @@ public Iterator<Map.Entry<byte[], byte[]>> iterator() {
142188

143189
@Override
144190
public void close() {
191+
if (cached()) {
192+
CacheManager.release(cache);
193+
}
145194
((Flusher) db).close();
146195
}
147196

148197
@Override
149198
public void reset() {
199+
if (cached()) {
200+
CacheManager.release(cache);
201+
}
150202
((Flusher) db).reset();
151203
}
152204

chainbase/src/main/java/org/tron/core/service/MortgageService.java

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
package org.tron.core.service;
22

33
import com.google.protobuf.ByteString;
4-
54
import java.math.BigInteger;
6-
import java.util.ArrayList;
75
import java.util.Comparator;
8-
import java.util.HashMap;
96
import java.util.List;
10-
import java.util.Map;
11-
127
import lombok.Getter;
138
import lombok.Setter;
149
import lombok.extern.slf4j.Slf4j;
@@ -18,7 +13,6 @@
1813
import org.tron.common.utils.StringUtil;
1914
import org.tron.core.capsule.AccountCapsule;
2015
import org.tron.core.capsule.WitnessCapsule;
21-
import org.tron.core.config.Parameter.ChainConstant;
2216
import org.tron.core.exception.BalanceInsufficientException;
2317
import org.tron.core.store.AccountStore;
2418
import org.tron.core.store.DelegationStore;
@@ -52,31 +46,17 @@ public void initStore(WitnessStore witnessStore, DelegationStore delegationStore
5246
}
5347

5448
public void payStandbyWitness() {
55-
List<WitnessCapsule> witnessCapsules = witnessStore.getAllWitnesses();
56-
Map<ByteString, WitnessCapsule> witnessCapsuleMap = new HashMap<>();
57-
List<ByteString> witnessAddressList = new ArrayList<>();
58-
for (WitnessCapsule witnessCapsule : witnessCapsules) {
59-
witnessAddressList.add(witnessCapsule.getAddress());
60-
witnessCapsuleMap.put(witnessCapsule.getAddress(), witnessCapsule);
61-
}
62-
witnessAddressList.sort(Comparator.comparingLong((ByteString b) -> witnessCapsuleMap.get(b).getVoteCount())
63-
.reversed().thenComparing(Comparator.comparingInt(ByteString::hashCode).reversed()));
64-
if (witnessAddressList.size() > ChainConstant.WITNESS_STANDBY_LENGTH) {
65-
witnessAddressList = witnessAddressList.subList(0, ChainConstant.WITNESS_STANDBY_LENGTH);
49+
List<WitnessCapsule> witnessStandbys = witnessStore.getWitnessStandby();
50+
long voteSum = witnessStandbys.stream().mapToLong(WitnessCapsule::getVoteCount).sum();
51+
if (voteSum < 1) {
52+
return;
6653
}
67-
long voteSum = 0;
6854
long totalPay = dynamicPropertiesStore.getWitness127PayPerBlock();
69-
for (ByteString b : witnessAddressList) {
70-
voteSum += witnessCapsuleMap.get(b).getVoteCount();
71-
}
72-
73-
if (voteSum > 0) {
74-
for (ByteString b : witnessAddressList) {
75-
double eachVotePay = (double) totalPay / voteSum;
76-
long pay = (long) (witnessCapsuleMap.get(b).getVoteCount() * eachVotePay);
77-
logger.debug("Pay {} stand reward {}.", Hex.toHexString(b.toByteArray()), pay);
78-
payReward(b.toByteArray(), pay);
79-
}
55+
double eachVotePay = (double) totalPay / voteSum;
56+
for (WitnessCapsule w : witnessStandbys) {
57+
long pay = (long) (w.getVoteCount() * eachVotePay);
58+
payReward(w.getAddress().toByteArray(), pay);
59+
logger.debug("Pay {} stand reward {}.", Hex.toHexString(w.getAddress().toByteArray()), pay);
8060
}
8161
}
8262

chainbase/src/main/java/org/tron/core/store/WitnessStore.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.tron.core.store;
22

33
import com.google.common.collect.Streams;
4+
import java.util.ArrayList;
5+
import java.util.Comparator;
46
import java.util.List;
57
import java.util.Map.Entry;
68
import java.util.stream.Collectors;
@@ -9,16 +11,25 @@
911
import org.springframework.beans.factory.annotation.Autowired;
1012
import org.springframework.beans.factory.annotation.Value;
1113
import org.springframework.stereotype.Component;
14+
import org.tron.common.cache.CacheManager;
15+
import org.tron.common.cache.CacheStrategies;
16+
import org.tron.common.cache.CacheType;
17+
import org.tron.common.cache.TronCache;
1218
import org.tron.core.capsule.WitnessCapsule;
19+
import org.tron.core.config.Parameter;
1320
import org.tron.core.db.TronStoreWithRevoking;
1421

1522
@Slf4j(topic = "DB")
1623
@Component
1724
public class WitnessStore extends TronStoreWithRevoking<WitnessCapsule> {
25+
// cache for 127 SR
26+
private final TronCache<Integer, List<WitnessCapsule>> witnessStandbyCache;
1827

1928
@Autowired
2029
protected WitnessStore(@Value("witness") String dbName) {
2130
super(dbName);
31+
String strategy = String.format(CacheStrategies.PATTERNS, 1, 1, "30s", 1);
32+
witnessStandbyCache = CacheManager.allocate(CacheType.witnessStandby, strategy);
2233
}
2334

2435
/**
@@ -35,4 +46,33 @@ public WitnessCapsule get(byte[] key) {
3546
byte[] value = revokingDB.getUnchecked(key);
3647
return ArrayUtils.isEmpty(value) ? null : new WitnessCapsule(value);
3748
}
49+
50+
public List<WitnessCapsule> getWitnessStandby() {
51+
List<WitnessCapsule> list =
52+
witnessStandbyCache.getIfPresent(Parameter.ChainConstant.WITNESS_STANDBY_LENGTH);
53+
if (list != null) {
54+
return list;
55+
}
56+
return updateWitnessStandby(null);
57+
}
58+
59+
public List<WitnessCapsule> updateWitnessStandby(List<WitnessCapsule> all) {
60+
List<WitnessCapsule> ret;
61+
if (all == null) {
62+
all = getAllWitnesses();
63+
}
64+
all.sort(Comparator.comparingLong(WitnessCapsule::getVoteCount)
65+
.reversed().thenComparing(Comparator.comparingInt(
66+
(WitnessCapsule w) -> w.getAddress().hashCode()).reversed()));
67+
if (all.size() > Parameter.ChainConstant.WITNESS_STANDBY_LENGTH) {
68+
ret = new ArrayList<>(all.subList(0, Parameter.ChainConstant.WITNESS_STANDBY_LENGTH));
69+
} else {
70+
ret = new ArrayList<>(all);
71+
}
72+
// trim voteCount = 0
73+
ret.removeIf(w -> w.getVoteCount() < 1);
74+
witnessStandbyCache.put(Parameter.ChainConstant.WITNESS_STANDBY_LENGTH, ret);
75+
return ret;
76+
}
77+
3878
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.tron.common.cache;
2+
3+
import com.google.common.cache.CacheLoader;
4+
import com.google.common.cache.CacheStats;
5+
import com.google.common.collect.Maps;
6+
import java.util.Map;
7+
import java.util.stream.Collectors;
8+
import org.tron.common.parameter.CommonParameter;
9+
10+
public class CacheManager {
11+
12+
private static final Map<CacheType, TronCache<?, ?>> CACHES = Maps.newConcurrentMap();
13+
14+
public static <K, V> TronCache<K, V> allocate(CacheType name) {
15+
TronCache<K, V> cache = new TronCache<>(name, CommonParameter.getInstance()
16+
.getStorage().getCacheStrategy(name));
17+
CACHES.put(name, cache);
18+
return cache;
19+
}
20+
21+
public static <K, V> TronCache<K, V> allocate(CacheType name, String strategy) {
22+
TronCache<K, V> cache = new TronCache<>(name, strategy);
23+
CACHES.put(name, cache);
24+
return cache;
25+
}
26+
27+
public static <K, V> TronCache<K, V> allocate(CacheType name, String strategy,
28+
CacheLoader<K, V> loader) {
29+
TronCache<K, V> cache = new TronCache<>(name, strategy, loader);
30+
CACHES.put(name, cache);
31+
return cache;
32+
}
33+
34+
35+
public static void release(TronCache<?, ?> cache) {
36+
cache.invalidateAll();
37+
}
38+
39+
public static Map<String, CacheStats> stats() {
40+
return CACHES.values().stream().collect(Collectors.toMap(c -> c.getName().toString(),
41+
TronCache::stats));
42+
}
43+
44+
}

0 commit comments

Comments
 (0)