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 }