github.com/ethersphere/bee/v2@v2.2.0/pkg/storage/inmemstore/inmembatch.go (about) 1 // Copyright 2022 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package inmemstore 6 7 import ( 8 "context" 9 "fmt" 10 "sync" 11 12 storage "github.com/ethersphere/bee/v2/pkg/storage" 13 ) 14 15 // batchOp represents a batch operations. 16 type batchOp interface { 17 Item() storage.Item 18 } 19 20 // batchOpBase is a base type for batch operations holding data. 21 type batchOpBase struct{ item storage.Item } 22 23 // Item implements batchOp interface Item method. 24 func (b batchOpBase) Item() storage.Item { return b.item } 25 26 type ( 27 batchOpPut struct{ batchOpBase } 28 batchOpDelete struct{ batchOpBase } 29 ) 30 31 type Batch struct { 32 ctx context.Context 33 34 mu sync.Mutex // mu guards batch, ops, and done. 35 ops map[string]batchOp 36 store *Store 37 done bool 38 } 39 40 // Batch implements storage.BatchedStore interface Batch method. 41 func (s *Store) Batch(ctx context.Context) storage.Batch { 42 return &Batch{ 43 ctx: ctx, 44 ops: make(map[string]batchOp), 45 store: s, 46 } 47 } 48 49 // Put implements storage.Batch interface Put method. 50 func (i *Batch) Put(item storage.Item) error { 51 if err := i.ctx.Err(); err != nil { 52 return err 53 } 54 55 i.mu.Lock() 56 i.ops[key(item)] = batchOpPut{batchOpBase{item: item}} 57 i.mu.Unlock() 58 59 return nil 60 } 61 62 // Delete implements storage.Batch interface Delete method. 63 func (i *Batch) Delete(item storage.Item) error { 64 if err := i.ctx.Err(); err != nil { 65 return err 66 } 67 68 i.mu.Lock() 69 i.ops[key(item)] = batchOpDelete{batchOpBase{item: item}} 70 i.mu.Unlock() 71 72 return nil 73 } 74 75 // Commit implements storage.Batch interface Commit method. 76 func (i *Batch) Commit() error { 77 if err := i.ctx.Err(); err != nil { 78 return err 79 } 80 81 i.mu.Lock() 82 defer i.mu.Unlock() 83 84 if i.done { 85 return storage.ErrBatchCommitted 86 } 87 88 defer func() { i.done = true }() 89 90 i.store.mu.Lock() 91 defer i.store.mu.Unlock() 92 93 for _, ops := range i.ops { 94 switch op := ops.(type) { 95 case batchOpPut: 96 err := i.store.put(op.Item()) 97 if err != nil { 98 return fmt.Errorf("unable to put item %s: %w", key(op.Item()), err) 99 } 100 case batchOpDelete: 101 err := i.store.delete(op.Item()) 102 if err != nil { 103 return fmt.Errorf("unable to delete item %s: %w", key(op.Item()), err) 104 } 105 106 } 107 } 108 109 return nil 110 }