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  }