github.com/koko1123/flow-go-1@v0.29.6/storage/badger/events.go (about)

     1  package badger
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/dgraph-io/badger/v3"
     7  
     8  	"github.com/koko1123/flow-go-1/model/flow"
     9  	"github.com/koko1123/flow-go-1/module"
    10  	"github.com/koko1123/flow-go-1/module/metrics"
    11  	"github.com/koko1123/flow-go-1/storage"
    12  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    13  )
    14  
    15  type Events struct {
    16  	db    *badger.DB
    17  	cache *Cache
    18  }
    19  
    20  func NewEvents(collector module.CacheMetrics, db *badger.DB) *Events {
    21  	retrieve := func(key interface{}) func(tx *badger.Txn) (interface{}, error) {
    22  		blockID := key.(flow.Identifier)
    23  		var events []flow.Event
    24  		return func(tx *badger.Txn) (interface{}, error) {
    25  			err := operation.LookupEventsByBlockID(blockID, &events)(tx)
    26  			return events, handleError(err, flow.Event{})
    27  		}
    28  	}
    29  
    30  	return &Events{
    31  		db: db,
    32  		cache: newCache(collector, metrics.ResourceEvents,
    33  			withStore(noopStore),
    34  			withRetrieve(retrieve)),
    35  	}
    36  }
    37  
    38  // BatchStore stores events keyed by a blockID in provided batch
    39  // No errors are expected during normal operation, but it may return generic error
    40  // if badger fails to process request
    41  func (e *Events) BatchStore(blockID flow.Identifier, blockEvents []flow.EventsList, batch storage.BatchStorage) error {
    42  	writeBatch := batch.GetWriter()
    43  
    44  	// pre-allocating and indexing slice is faster than appending
    45  	sliceSize := 0
    46  	for _, b := range blockEvents {
    47  		sliceSize += len(b)
    48  	}
    49  
    50  	combinedEvents := make([]flow.Event, sliceSize)
    51  
    52  	eventIndex := 0
    53  
    54  	for _, events := range blockEvents {
    55  		for _, event := range events {
    56  			err := operation.BatchInsertEvent(blockID, event)(writeBatch)
    57  			if err != nil {
    58  				return fmt.Errorf("cannot batch insert event: %w", err)
    59  			}
    60  			combinedEvents[eventIndex] = event
    61  			eventIndex++
    62  		}
    63  	}
    64  
    65  	callback := func() {
    66  		e.cache.Insert(blockID, combinedEvents)
    67  	}
    68  	batch.OnSucceed(callback)
    69  	return nil
    70  }
    71  
    72  // ByBlockID returns the events for the given block ID
    73  func (e *Events) ByBlockID(blockID flow.Identifier) ([]flow.Event, error) {
    74  	tx := e.db.NewTransaction(false)
    75  	defer tx.Discard()
    76  	val, err := e.cache.Get(blockID)(tx)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	return val.([]flow.Event), nil
    81  }
    82  
    83  // ByBlockIDTransactionID returns the events for the given block ID and transaction ID
    84  func (e *Events) ByBlockIDTransactionID(blockID flow.Identifier, txID flow.Identifier) ([]flow.Event, error) {
    85  	events, err := e.ByBlockID(blockID)
    86  	if err != nil {
    87  		return nil, handleError(err, flow.Event{})
    88  	}
    89  
    90  	var matched []flow.Event
    91  	for _, event := range events {
    92  		if event.TransactionID == txID {
    93  			matched = append(matched, event)
    94  		}
    95  	}
    96  	return matched, nil
    97  }
    98  
    99  func (e *Events) ByBlockIDTransactionIndex(blockID flow.Identifier, txIndex uint32) ([]flow.Event, error) {
   100  	events, err := e.ByBlockID(blockID)
   101  	if err != nil {
   102  		return nil, handleError(err, flow.Event{})
   103  	}
   104  
   105  	var matched []flow.Event
   106  	for _, event := range events {
   107  		if event.TransactionIndex == txIndex {
   108  			matched = append(matched, event)
   109  		}
   110  	}
   111  	return matched, nil
   112  }
   113  
   114  // ByBlockIDEventType returns the events for the given block ID and event type
   115  func (e *Events) ByBlockIDEventType(blockID flow.Identifier, eventType flow.EventType) ([]flow.Event, error) {
   116  	events, err := e.ByBlockID(blockID)
   117  	if err != nil {
   118  		return nil, handleError(err, flow.Event{})
   119  	}
   120  
   121  	var matched []flow.Event
   122  	for _, event := range events {
   123  		if event.Type == eventType {
   124  			matched = append(matched, event)
   125  		}
   126  	}
   127  	return matched, nil
   128  }
   129  
   130  // RemoveByBlockID removes events by block ID
   131  func (e *Events) RemoveByBlockID(blockID flow.Identifier) error {
   132  	return e.db.Update(operation.RemoveEventsByBlockID(blockID))
   133  }
   134  
   135  // BatchRemoveByBlockID removes events keyed by a blockID in provided batch
   136  // No errors are expected during normal operation, even if no entries are matched.
   137  // If Badger unexpectedly fails to process the request, the error is wrapped in a generic error and returned.
   138  func (e *Events) BatchRemoveByBlockID(blockID flow.Identifier, batch storage.BatchStorage) error {
   139  	writeBatch := batch.GetWriter()
   140  	return e.db.View(operation.BatchRemoveEventsByBlockID(blockID, writeBatch))
   141  }
   142  
   143  type ServiceEvents struct {
   144  	db    *badger.DB
   145  	cache *Cache
   146  }
   147  
   148  func NewServiceEvents(collector module.CacheMetrics, db *badger.DB) *ServiceEvents {
   149  	retrieve := func(key interface{}) func(tx *badger.Txn) (interface{}, error) {
   150  		blockID := key.(flow.Identifier)
   151  		var events []flow.Event
   152  		return func(tx *badger.Txn) (interface{}, error) {
   153  			err := operation.LookupServiceEventsByBlockID(blockID, &events)(tx)
   154  			return events, handleError(err, flow.Event{})
   155  		}
   156  	}
   157  
   158  	return &ServiceEvents{
   159  		db: db,
   160  		cache: newCache(collector, metrics.ResourceEvents,
   161  			withStore(noopStore),
   162  			withRetrieve(retrieve)),
   163  	}
   164  }
   165  
   166  // BatchStore stores service events keyed by a blockID in provided batch
   167  // No errors are expected during normal operation, even if no entries are matched.
   168  // If Badger unexpectedly fails to process the request, the error is wrapped in a generic error and returned.
   169  func (e *ServiceEvents) BatchStore(blockID flow.Identifier, events []flow.Event, batch storage.BatchStorage) error {
   170  	writeBatch := batch.GetWriter()
   171  	for _, event := range events {
   172  		err := operation.BatchInsertServiceEvent(blockID, event)(writeBatch)
   173  		if err != nil {
   174  			return fmt.Errorf("cannot batch insert service event: %w", err)
   175  		}
   176  	}
   177  
   178  	callback := func() {
   179  		e.cache.Insert(blockID, events)
   180  	}
   181  	batch.OnSucceed(callback)
   182  	return nil
   183  }
   184  
   185  // ByBlockID returns the events for the given block ID
   186  func (e *ServiceEvents) ByBlockID(blockID flow.Identifier) ([]flow.Event, error) {
   187  	tx := e.db.NewTransaction(false)
   188  	defer tx.Discard()
   189  	val, err := e.cache.Get(blockID)(tx)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return val.([]flow.Event), nil
   194  }
   195  
   196  // RemoveByBlockID removes service events by block ID
   197  func (e *ServiceEvents) RemoveByBlockID(blockID flow.Identifier) error {
   198  	return e.db.Update(operation.RemoveServiceEventsByBlockID(blockID))
   199  }
   200  
   201  // BatchRemoveByBlockID removes service events keyed by a blockID in provided batch
   202  // No errors are expected during normal operation, even if no entries are matched.
   203  // If Badger unexpectedly fails to process the request, the error is wrapped in a generic error and returned.
   204  func (e *ServiceEvents) BatchRemoveByBlockID(blockID flow.Identifier, batch storage.BatchStorage) error {
   205  	writeBatch := batch.GetWriter()
   206  	return e.db.View(operation.BatchRemoveServiceEventsByBlockID(blockID, writeBatch))
   207  }