github.com/annchain/OG@v0.0.9/og/txcache/cache.go (about) 1 // Copyright © 2019 Annchain Authors <EMAIL ADDRESS> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package txcache 15 16 import ( 17 types2 "github.com/annchain/OG/arefactor/og/types" 18 "github.com/annchain/OG/og/types" 19 20 "github.com/annchain/gcache" 21 log "github.com/sirupsen/logrus" 22 "sort" 23 "time" 24 ) 25 26 type TxCache struct { 27 cache gcache.OrderedCache 28 } 29 30 func newCacheItemCmpFunction() gcache.SearchCompareFunction { 31 cmpFunc := func(value interface{}, anotherValue interface{}) int { 32 tx1 := value.(types.Txi) 33 tx2 := anotherValue.(types.Txi) 34 if tx1.GetWeight() > tx2.GetWeight() { 35 return 1 36 } else if tx1.GetWeight() < tx2.GetWeight() { 37 return -1 38 } 39 return 0 40 } 41 return cmpFunc 42 } 43 44 func newCacheItemSortFunction() gcache.SortKeysFunction { 45 var allItem = false 46 sortByAllValue := func(keys []interface{}, values []interface{}, getItem func(key interface{}) (interface{}, bool)) (sortedKeys []interface{}, sortOk bool) { 47 var txis types.Txis 48 for i, val := range values { 49 tx := val.(types.Txi) 50 if tx == nil { 51 log.WithField("i", i).Error("got nil tx") 52 continue 53 } 54 txis = append(txis, tx) 55 } 56 sort.Sort(txis) 57 for _, tx := range txis { 58 sortedKeys = append(sortedKeys, tx.GetHash()) 59 } 60 if len(keys) != len(sortedKeys) { 61 log.WithField("len keys", len(keys)).WithField("len txis ", len(txis)).Info("sorted tx") 62 } 63 return sortedKeys, true 64 } 65 sortByGetEachItem := func(keys []interface{}, values []interface{}, getItem func(key interface{}) (interface{}, bool)) (sortedKeys []interface{}, sortOk bool) { 66 var txis types.Txis 67 for i, k := range keys { 68 val, ok := getItem(k) 69 if !ok { 70 continue 71 } 72 tx := val.(types.Txi) 73 if tx == nil { 74 log.WithField("i", i).WithField("key ", k).Error("got nil tx") 75 continue 76 } 77 txis = append(txis, tx) 78 } 79 sort.Sort(txis) 80 for _, tx := range txis { 81 sortedKeys = append(sortedKeys, tx.GetHash()) 82 } 83 if len(keys) != len(sortedKeys) { 84 log.WithField("len keys", len(keys)).WithField("len txis ", len(txis)).Info("sorted tx") 85 } 86 return sortedKeys, true 87 } 88 if allItem { 89 return sortByAllValue 90 } 91 return sortByGetEachItem 92 } 93 94 func NewTxCache(maxSize int, expire int, invalidTx func(h types2.Hash) bool, sorted bool) *TxCache { 95 96 expireFunction := func(key interface{}) bool { 97 hash := key.(types2.Hash) 98 return invalidTx(hash) 99 } 100 sortFunc := newCacheItemSortFunction() 101 var cmpFunction gcache.SearchCompareFunction 102 if sorted { 103 cmpFunction = newCacheItemCmpFunction() 104 } else { 105 cmpFunction = nil 106 } 107 return &TxCache{ 108 cache: gcache.New(maxSize).Expiration( 109 time.Second * time.Duration(expire)).ExpiredFunc(expireFunction).SortKeysFunc(sortFunc).SearchCompareFunction( 110 cmpFunction).BuildOrderedCache(), 111 } 112 113 } 114 115 func (t *TxCache) GetHashOrder() types2.Hashes { 116 v := t.cache.OrderedKeys() 117 var hashes types2.Hashes 118 for _, k := range v { 119 hash := k.(types2.Hash) 120 hashes = append(hashes, hash) 121 } 122 return hashes 123 } 124 125 //Get get an item 126 func (t *TxCache) Get(h types2.Hash) types.Txi { 127 v, err := t.cache.GetIFPresent(h) 128 if err == nil { 129 return v.(types.Txi) 130 } 131 return nil 132 } 133 134 func (t *TxCache) Has(h types2.Hash) bool { 135 _, err := t.cache.GetIFPresent(h) 136 if err == nil { 137 return true 138 } 139 return false 140 } 141 142 // Add tx into txCache 143 func (t *TxCache) EnQueue(tx types.Txi) error { 144 err := t.cache.EnQueue(tx.GetHash(), tx) 145 //log.WithField("enqueued tx",tx).WithField("used",time.Now().Sub(start)).Debug("enqueue total") 146 return err 147 } 148 149 //get top element end remove it 150 func (t *TxCache) DeQueue() types.Txi { 151 _, value, err := t.cache.DeQueue() 152 if err != nil { 153 return nil 154 } 155 return value.(types.Txi) 156 } 157 158 // Remove tx from txCache 159 func (t *TxCache) Remove(h types2.Hash) bool { 160 return t.cache.Remove(h) 161 } 162 163 func (t *TxCache) Len() int { 164 return t.cache.Len() 165 } 166 167 // 168 func (t *TxCache) RemoveExpiredAndInvalid(allowFailCount int) error { 169 return t.cache.RemoveExpired(allowFailCount) 170 } 171 172 func (t *TxCache) Refresh() { 173 t.cache.Refresh() 174 } 175 176 func (c *TxCache) DeQueueBatch(count int) (txs types.Txis, err error) { 177 _, values, err := c.cache.DeQueueBatch(count) 178 if err != nil { 179 return nil, err 180 } 181 for _, v := range values { 182 txi := v.(types.Txi) 183 txs = append(txs, txi) 184 } 185 return txs, nil 186 } 187 188 // Add tx into txCache 189 func (t *TxCache) Prepend(tx types.Txi) error { 190 start := time.Now() 191 err := t.cache.Prepend(tx.GetHash(), tx) 192 log.WithField("Prepend tx", tx).WithField("used", time.Now().Sub(start)).Debug("Prepend total") 193 return err 194 } 195 196 func (c *TxCache) PrependBatch(txs types.Txis) error { 197 if len(txs) == 0 { 198 return nil 199 } 200 sort.Sort(txs) 201 var keys []interface{} 202 var values []interface{} 203 for _, tx := range txs { 204 keys = append(keys, tx.GetHash()) 205 values = append(values, tx) 206 } 207 start := time.Now() 208 log.WithField("len ", len(keys)).Debug("before prepend keys") 209 err := c.cache.PrependBatch(keys, values) 210 log.WithField("used time ", time.Now().Sub(start)).WithField("len ", len(keys)).Debug("after prepend keys") 211 return err 212 } 213 214 func (c *TxCache) EnQueueBatch(txs types.Txis) error { 215 if len(txs) == 0 { 216 return nil 217 } 218 sort.Sort(txs) 219 var keys []interface{} 220 var values []interface{} 221 for _, tx := range txs { 222 keys = append(keys, tx.GetHash()) 223 values = append(values, tx) 224 } 225 return c.cache.EnQueueBatch(keys, values) 226 } 227 228 func (t *TxCache) GetTop() types.Txi { 229 _, value, err := t.cache.GetTop() 230 if err != nil { 231 return nil 232 } 233 return value.(types.Txi) 234 } 235 236 //MoveFront move an element to font, if searchFunction is set 237 //func (t *TxCache) MoveFront(tx types.Txi) error { 238 // defer log.WithField(" tx", tx).Debug("moved to front") 239 // return t.cache.MoveFront(tx.GetHash()) 240 //} 241 242 func (t *TxCache) Sort() { 243 t.cache.Sort() 244 }