github.com/ethersphere/bee/v2@v2.2.0/pkg/statestore/leveldb/leveldb.go (about) 1 // Copyright 2020 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 leveldb 6 7 import ( 8 "encoding" 9 "encoding/json" 10 "errors" 11 "fmt" 12 13 "github.com/ethersphere/bee/v2/pkg/log" 14 "github.com/ethersphere/bee/v2/pkg/storage" 15 16 ldberr "github.com/syndtr/goleveldb/leveldb/errors" 17 18 "github.com/syndtr/goleveldb/leveldb" 19 ldbs "github.com/syndtr/goleveldb/leveldb/storage" 20 21 "github.com/syndtr/goleveldb/leveldb/util" 22 ) 23 24 // loggerName is the tree path name of the logger for this package. 25 const loggerName = "leveldb" 26 27 var ( 28 _ storage.StateStorer = (*Store)(nil) 29 ) 30 31 // Store uses LevelDB to store values. 32 type Store struct { 33 db *leveldb.DB 34 logger log.Logger 35 } 36 37 func NewInMemoryStateStore(l log.Logger) (*Store, error) { 38 ldb, err := leveldb.Open(ldbs.NewMemStorage(), nil) 39 if err != nil { 40 return nil, err 41 } 42 43 s := &Store{ 44 db: ldb, 45 logger: l.WithName(loggerName).Register(), 46 } 47 48 return s, nil 49 } 50 51 // NewStateStore creates a new persistent state storage. 52 func NewStateStore(path string, l log.Logger) (*Store, error) { 53 l = l.WithName(loggerName).Register() 54 55 db, err := leveldb.OpenFile(path, nil) 56 if err != nil { 57 if !ldberr.IsCorrupted(err) { 58 return nil, err 59 } 60 61 l.Warning("statestore open failed, attempting recovery", "error", err) 62 db, err = leveldb.RecoverFile(path, nil) 63 if err != nil { 64 return nil, fmt.Errorf("statestore recovery: %w", err) 65 } 66 l.Warning("statestore recovery done; you are kindly request to inform us about the steps that preceded the last bee shutdown") 67 } 68 69 s := &Store{ 70 db: db, 71 logger: l, 72 } 73 74 return s, nil 75 } 76 77 // Get retrieves a value of the requested key. If no results are found, 78 // storage.ErrNotFound will be returned. 79 func (s *Store) Get(key string, i interface{}) error { 80 data, err := s.db.Get([]byte(key), nil) 81 if err != nil { 82 if errors.Is(err, leveldb.ErrNotFound) { 83 return storage.ErrNotFound 84 } 85 return err 86 } 87 88 if unmarshaler, ok := i.(encoding.BinaryUnmarshaler); ok { 89 return unmarshaler.UnmarshalBinary(data) 90 } 91 92 return json.Unmarshal(data, i) 93 } 94 95 // Put stores a value for an arbitrary key. BinaryMarshaler 96 // interface method will be called on the provided value 97 // with fallback to JSON serialization. 98 func (s *Store) Put(key string, i interface{}) (err error) { 99 var bytes []byte 100 if marshaler, ok := i.(encoding.BinaryMarshaler); ok { 101 if bytes, err = marshaler.MarshalBinary(); err != nil { 102 return err 103 } 104 } else if bytes, err = json.Marshal(i); err != nil { 105 return err 106 } 107 108 return s.db.Put([]byte(key), bytes, nil) 109 } 110 111 // Delete removes entries stored under a specific key. 112 func (s *Store) Delete(key string) (err error) { 113 return s.db.Delete([]byte(key), nil) 114 } 115 116 // Iterate entries that match the supplied prefix. 117 func (s *Store) Iterate(prefix string, iterFunc storage.StateIterFunc) (err error) { 118 iter := s.db.NewIterator(util.BytesPrefix([]byte(prefix)), nil) 119 defer iter.Release() 120 for iter.Next() { 121 stop, err := iterFunc(append([]byte(nil), iter.Key()...), append([]byte(nil), iter.Value()...)) 122 if err != nil { 123 return err 124 } 125 if stop { 126 break 127 } 128 } 129 return iter.Error() 130 } 131 132 // Close releases the resources used by the store. 133 func (s *Store) Close() error { 134 return s.db.Close() 135 }