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  }