diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-12-21 16:35:08 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-04-09 21:32:55 +0800 |
commit | 22f0d7295d7ec0ef029b69db52dab52452c1e725 (patch) | |
tree | 396bd0379b58f9a78b6d67e7214fdf2eb35876ff | |
parent | bebcd229959b250a4127bdd678b49048ee0208ea (diff) | |
download | dexon-22f0d7295d7ec0ef029b69db52dab52452c1e725.tar.gz dexon-22f0d7295d7ec0ef029b69db52dab52452c1e725.tar.zst dexon-22f0d7295d7ec0ef029b69db52dab52452c1e725.zip |
core/types: SigCache with a limited size (#98)
* core/types: SigCache with a limited size
* minor tweaks
-rw-r--r-- | core/tx_pool.go | 1 | ||||
-rw-r--r-- | core/types/transaction_signing.go | 53 |
2 files changed, 33 insertions, 21 deletions
diff --git a/core/tx_pool.go b/core/tx_pool.go index 911b6c261..546ef0a99 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -874,7 +874,6 @@ func (pool *TxPool) Get(hash common.Hash) *types.Transaction { // removeTx removes a single transaction from the queue, moving all subsequent // transactions back to the future queue. func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { - types.GlobalSigCache.Prune([]common.Hash{hash}) // Fetch the transaction we wish to delete tx := pool.all.Get(hash) if tx == nil { diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 1a13e3e3d..04abeb402 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -39,25 +39,32 @@ func init() { GlobalSigCache = newGlobalSigCache() } +type resultEntry struct { + Hash common.Hash + Addr common.Address +} + +// SigCache has maximum of `sigCacheSize` and will be purged to `pruneTargetSize` +// if exceeding `sigCacheSize`. +const sigCacheSize = 100000 +const pruneTargetSize = 90000 + // globalSigCache stores the mapping between txHash and sender address. // Since ECRecover is slow, and we run ECRecover very frequently (in // app.VerifyBlock, app.ConfirmedBlock), so we need to cache it globally. type globalSigCache struct { - cache map[common.Hash]common.Address + cacheID map[common.Hash]int + cache []resultEntry cacheMu sync.RWMutex } func newGlobalSigCache() *globalSigCache { return &globalSigCache{ - cache: make(map[common.Hash]common.Address), + cacheID: make(map[common.Hash]int, sigCacheSize), + cache: make([]resultEntry, 0, sigCacheSize), } } -type resultEntry struct { - Hash common.Hash - Addr common.Address -} - // Add adds a list of transactions into sig cache. func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transaction, err error) { num := runtime.NumCPU() - 2 @@ -94,8 +101,22 @@ func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transact // Acquire lock and set cache. c.cacheMu.Lock() defer c.cacheMu.Unlock() + for len(results)+len(c.cacheID) > sigCacheSize { + if len(results) > sigCacheSize { + // Purge all cache. + c.cacheID = make(map[common.Hash]int, len(results)) + c.cache = c.cache[:0] + break + } + var prune []resultEntry + c.cache, prune = c.cache[:pruneTargetSize], c.cache[pruneTargetSize:] + for _, r := range prune { + delete(c.cacheID, r.Hash) + } + } for _, r := range results { - c.cache[r.Hash] = r.Addr + c.cacheID[r.Hash] = len(c.cache) + c.cache = append(c.cache, r) } }(txs[i*batchSize : (i+1)*batchSize]) } @@ -108,23 +129,15 @@ func (c *globalSigCache) Add(signer Signer, txs Transactions) (errorTx *Transact return } -// Prune removes a list of hashes of tx from the cache. -func (c *globalSigCache) Prune(hashes []common.Hash) { - c.cacheMu.Lock() - defer c.cacheMu.Unlock() - - for _, hash := range hashes { - delete(c.cache, hash) - } -} - // Get returns a single address given a tx hash. func (c *globalSigCache) Get(hash common.Hash) (common.Address, bool) { c.cacheMu.RLock() defer c.cacheMu.RUnlock() - res, ok := c.cache[hash] - return res, ok + if ID, ok := c.cacheID[hash]; ok { + return c.cache[ID].Addr, true + } + return common.Address{}, false } // sigCache is used to cache the derived sender and contains |