-
Notifications
You must be signed in to change notification settings - Fork 1.6k
fix(api): Optimize memory allocation for the eth_newFilter interface
#6495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release_v4.8.1
Are you sure you want to change the base?
Changes from all commits
3e41f54
f3f22b0
8e801ad
4f78568
26187bf
f0f0b0f
aabc004
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,8 @@ | |
| import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.triggerCallContract; | ||
|
|
||
| import com.alibaba.fastjson.JSON; | ||
| import com.google.common.cache.Cache; | ||
| import com.google.common.cache.CacheBuilder; | ||
| import com.google.protobuf.ByteString; | ||
| import com.google.protobuf.GeneratedMessageV3; | ||
| import java.io.Closeable; | ||
|
|
@@ -25,10 +27,10 @@ | |
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.regex.Pattern; | ||
| import lombok.Getter; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.commons.collections4.CollectionUtils; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.bouncycastle.util.encoders.Hex; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
|
|
@@ -110,6 +112,11 @@ public enum RequestSource { | |
|
|
||
| private static final String FILTER_NOT_FOUND = "filter not found"; | ||
| public static final int EXPIRE_SECONDS = 5 * 60; | ||
| private static final Cache<LogFilterElement, LogFilterElement> logElementCache = | ||
| CacheBuilder.newBuilder() | ||
| .maximumSize(300_000L) // 300s * tps(1000) * 1 log/tx ≈ 300_000 | ||
| .expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS) | ||
| .recordStats().build(); //LRU cache | ||
| /** | ||
| * for log filter in Full Json-RPC | ||
| */ | ||
|
|
@@ -191,6 +198,9 @@ public static void handleBLockFilter(BlockFilterCapsule blockFilterCapsule) { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * append LogsFilterCapsule's LogFilterElement list to each filter if matched | ||
| */ | ||
| public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { | ||
| Iterator<Entry<String, LogFilterAndResult>> it; | ||
|
|
||
|
|
@@ -226,8 +236,17 @@ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { | |
| LogMatch.matchBlock(logFilter, logsFilterCapsule.getBlockNumber(), | ||
| logsFilterCapsule.getBlockHash(), logsFilterCapsule.getTxInfoList(), | ||
| logsFilterCapsule.isRemoved()); | ||
| if (CollectionUtils.isNotEmpty(elements)) { | ||
| logFilterAndResult.getResult().addAll(elements); | ||
|
|
||
| for (LogFilterElement element : elements) { | ||
| LogFilterElement newElement; | ||
| try { | ||
| // compare with hashcode() first, then with equals(). If not exist, put it. | ||
| newElement = logElementCache.get(element, () -> element); | ||
| } catch (ExecutionException e) { | ||
| logger.error("Getting/loading LogFilterElement from cache fails", e);// never happen | ||
| continue; | ||
| } | ||
| logFilterAndResult.getResult().add(newElement); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -797,7 +816,7 @@ public TransactionReceipt getTransactionReceipt(String txId) | |
| long blockNum = blockCapsule.getNum(); | ||
| TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum); | ||
| long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); | ||
|
|
||
| // Find transaction context | ||
| TransactionReceipt.TransactionContext context | ||
| = findTransactionContext(transactionInfoList, | ||
|
|
@@ -806,7 +825,7 @@ public TransactionReceipt getTransactionReceipt(String txId) | |
| if (context == null) { | ||
| return null; // Transaction not found in block | ||
| } | ||
|
|
||
| return new TransactionReceipt(blockCapsule, transactionInfo, context, energyFee); | ||
| } | ||
|
|
||
|
|
@@ -1529,6 +1548,7 @@ public static Object[] getFilterResult(String filterId, Map<String, BlockFilterA | |
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| logElementCache.invalidateAll(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to call invalidateAll()? The close() method is invoked when the application is about to stop completely. When the entire application (the JVM process) exits, all the memory it occupies, including all objects stored in the logElementCache, will be automatically reclaimed by the operating system. At the very last moment before the application shuts down, would manually clearing a memory cache that is about to vanish along with it (i.e., invalidateAll()) consume the final CPU cycles to perform a meaningless task? |
||
| ExecutorServiceManager.shutdownAndAwaitTermination(sectionExecutor, esName); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.