github.com/koko1123/flow-go-1@v0.29.6/module/mempool/stdmap/backend.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package stdmap
     4  
     5  import (
     6  	"math"
     7  	"sync"
     8  
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/module/mempool"
    11  	"github.com/koko1123/flow-go-1/module/mempool/stdmap/backdata"
    12  	_ "github.com/koko1123/flow-go-1/utils/binstat"
    13  )
    14  
    15  // Backend provides synchronized access to a backdata
    16  type Backend struct {
    17  	sync.RWMutex
    18  	backData           mempool.BackData
    19  	guaranteedCapacity uint
    20  	batchEject         BatchEjectFunc
    21  	eject              EjectFunc
    22  	ejectionCallbacks  []mempool.OnEjection
    23  }
    24  
    25  // NewBackend creates a new memory pool backend.
    26  // This is using EjectTrueRandomFast()
    27  func NewBackend(options ...OptionFunc) *Backend {
    28  	b := Backend{
    29  		backData:           backdata.NewMapBackData(),
    30  		guaranteedCapacity: uint(math.MaxUint32),
    31  		batchEject:         EjectTrueRandomFast,
    32  		eject:              nil,
    33  		ejectionCallbacks:  nil,
    34  	}
    35  	for _, option := range options {
    36  		option(&b)
    37  	}
    38  	return &b
    39  }
    40  
    41  // Has checks if we already contain the item with the given hash.
    42  func (b *Backend) Has(entityID flow.Identifier) bool {
    43  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)Has")
    44  	b.RLock()
    45  	//binstat.Leave(bs1)
    46  
    47  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Has")
    48  	//defer binstat.Leave(bs2)
    49  	defer b.RUnlock()
    50  	has := b.backData.Has(entityID)
    51  	return has
    52  }
    53  
    54  // Add adds the given item to the pool.
    55  func (b *Backend) Add(entity flow.Entity) bool {
    56  	//bs0 := binstat.EnterTime(binstat.BinStdmap + ".<<lock.(Backend)Add")
    57  	entityID := entity.ID() // this expensive operation done OUTSIDE of lock :-)
    58  	//binstat.Leave(bs0)
    59  
    60  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Add")
    61  	b.Lock()
    62  	//binstat.Leave(bs1)
    63  
    64  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Add")
    65  	//defer binstat.Leave(bs2)
    66  	defer b.Unlock()
    67  	added := b.backData.Add(entityID, entity)
    68  	b.reduce()
    69  	return added
    70  }
    71  
    72  // Remove will remove the item with the given hash.
    73  func (b *Backend) Remove(entityID flow.Identifier) bool {
    74  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Remove")
    75  	b.Lock()
    76  	//binstat.Leave(bs1)
    77  
    78  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Remove")
    79  	//defer binstat.Leave(bs2)
    80  	defer b.Unlock()
    81  	_, removed := b.backData.Remove(entityID)
    82  	return removed
    83  }
    84  
    85  // Adjust will adjust the value item using the given function if the given key can be found.
    86  // Returns a bool which indicates whether the value was updated.
    87  func (b *Backend) Adjust(entityID flow.Identifier, f func(flow.Entity) flow.Entity) (flow.Entity, bool) {
    88  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Adjust")
    89  	b.Lock()
    90  	//binstat.Leave(bs1)
    91  
    92  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Adjust")
    93  	//defer binstat.Leave(bs2)
    94  	defer b.Unlock()
    95  	entity, wasUpdated := b.backData.Adjust(entityID, f)
    96  	return entity, wasUpdated
    97  }
    98  
    99  // ByID returns the given item from the pool.
   100  func (b *Backend) ByID(entityID flow.Identifier) (flow.Entity, bool) {
   101  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)ByID")
   102  	b.RLock()
   103  	//binstat.Leave(bs1)
   104  
   105  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)ByID")
   106  	//defer binstat.Leave(bs2)
   107  	defer b.RUnlock()
   108  	entity, exists := b.backData.ByID(entityID)
   109  	return entity, exists
   110  }
   111  
   112  // Run executes a function giving it exclusive access to the backdata
   113  func (b *Backend) Run(f func(backdata mempool.BackData) error) error {
   114  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Run")
   115  	b.Lock()
   116  	//binstat.Leave(bs1)
   117  
   118  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Run")
   119  	//defer binstat.Leave(bs2)
   120  	defer b.Unlock()
   121  	err := f(b.backData)
   122  	b.reduce()
   123  	return err
   124  }
   125  
   126  // Size will return the size of the backend.
   127  func (b *Backend) Size() uint {
   128  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)Size")
   129  	b.RLock()
   130  	//binstat.Leave(bs1)
   131  
   132  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Size")
   133  	//defer binstat.Leave(bs2)
   134  	defer b.RUnlock()
   135  	size := b.backData.Size()
   136  	return size
   137  }
   138  
   139  // Limit returns the maximum number of items allowed in the backend.
   140  func (b *Backend) Limit() uint {
   141  	return b.guaranteedCapacity
   142  }
   143  
   144  // All returns all entities from the pool.
   145  func (b *Backend) All() []flow.Entity {
   146  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)All")
   147  	b.RLock()
   148  	//binstat.Leave(bs1)
   149  
   150  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)All")
   151  	//defer binstat.Leave(bs2)
   152  	defer b.RUnlock()
   153  
   154  	return b.backData.Entities()
   155  }
   156  
   157  // Clear removes all entities from the pool.
   158  func (b *Backend) Clear() {
   159  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Clear")
   160  	b.Lock()
   161  	//binstat.Leave(bs1)
   162  
   163  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Clear")
   164  	//defer binstat.Leave(bs2)
   165  	defer b.Unlock()
   166  	b.backData.Clear()
   167  }
   168  
   169  // RegisterEjectionCallbacks adds the provided OnEjection callbacks
   170  func (b *Backend) RegisterEjectionCallbacks(callbacks ...mempool.OnEjection) {
   171  	//bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)RegisterEjectionCallbacks")
   172  	b.Lock()
   173  	//binstat.Leave(bs1)
   174  
   175  	//bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)RegisterEjectionCallbacks")
   176  	//defer binstat.Leave(bs2)
   177  	defer b.Unlock()
   178  	b.ejectionCallbacks = append(b.ejectionCallbacks, callbacks...)
   179  }
   180  
   181  // reduce will reduce the size of the kept entities until we are within the
   182  // configured memory pool size limit.
   183  func (b *Backend) reduce() {
   184  	//bs := binstat.EnterTime(binstat.BinStdmap + ".??lock.(Backend)reduce")
   185  	//defer binstat.Leave(bs)
   186  
   187  	// we keep reducing the cache size until we are at limit again
   188  	// this was a loop, but the loop is now in EjectTrueRandomFast()
   189  	// the ejections are batched, so this call to eject() may not actually
   190  	// do anything until the batch threshold is reached (currently 128)
   191  	if b.backData.Size() > b.guaranteedCapacity {
   192  		// get the key from the eject function
   193  		// we don't do anything if there is an error
   194  		if b.batchEject != nil {
   195  			_ = b.batchEject(b)
   196  		} else {
   197  			_, _, _ = b.eject(b)
   198  		}
   199  	}
   200  }