You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
3.6 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package leveldb
  2. import (
  3. "github.com/iden3/go-merkletree"
  4. "github.com/syndtr/goleveldb/leveldb"
  5. "github.com/syndtr/goleveldb/leveldb/errors"
  6. "github.com/syndtr/goleveldb/leveldb/opt"
  7. "github.com/syndtr/goleveldb/leveldb/util"
  8. )
  9. // Storage implements the db.Storage interface
  10. type Storage struct {
  11. ldb *leveldb.DB
  12. prefix []byte
  13. }
  14. // StorageTx implements the db.Tx interface
  15. type StorageTx struct {
  16. *Storage
  17. cache merkletree.KvMap
  18. }
  19. // NewLevelDbStorage returns a new Storage
  20. func NewLevelDbStorage(path string, errorIfMissing bool) (*Storage, error) {
  21. o := &opt.Options{
  22. ErrorIfMissing: errorIfMissing,
  23. }
  24. ldb, err := leveldb.OpenFile(path, o)
  25. if err != nil {
  26. return nil, err
  27. }
  28. return &Storage{ldb, []byte{}}, nil
  29. }
  30. // WithPrefix implements the method WithPrefix of the interface db.Storage
  31. func (l *Storage) WithPrefix(prefix []byte) merkletree.Storage {
  32. return &Storage{l.ldb, merkletree.Concat(l.prefix, prefix)}
  33. }
  34. // NewTx implements the method NewTx of the interface db.Storage
  35. func (l *Storage) NewTx() (merkletree.Tx, error) {
  36. return &StorageTx{l, make(merkletree.KvMap)}, nil
  37. }
  38. // Get retrieves a value from a key in the db.Storage
  39. func (l *Storage) Get(key []byte) ([]byte, error) {
  40. v, err := l.ldb.Get(merkletree.Concat(l.prefix, key[:]), nil)
  41. if err == errors.ErrNotFound {
  42. return nil, merkletree.ErrNotFound
  43. }
  44. return v, err
  45. }
  46. // Iterate implements the method Iterate of the interface db.Storage
  47. func (l *Storage) Iterate(f func([]byte, []byte) (bool, error)) error {
  48. // FIXME: Use the prefix!
  49. snapshot, err := l.ldb.GetSnapshot()
  50. if err != nil {
  51. return err
  52. }
  53. iter := snapshot.NewIterator(util.BytesPrefix(l.prefix), nil)
  54. defer iter.Release()
  55. for iter.Next() {
  56. localKey := iter.Key()[len(l.prefix):]
  57. if cont, err := f(localKey, iter.Value()); err != nil {
  58. return err
  59. } else if !cont {
  60. break
  61. }
  62. }
  63. iter.Release()
  64. return iter.Error()
  65. }
  66. // Get retreives a value from a key in the interface db.Tx
  67. func (tx *StorageTx) Get(key []byte) ([]byte, error) {
  68. var err error
  69. fullkey := merkletree.Concat(tx.prefix, key)
  70. if value, ok := tx.cache.Get(fullkey); ok {
  71. return value, nil
  72. }
  73. value, err := tx.ldb.Get(fullkey, nil)
  74. if err == errors.ErrNotFound {
  75. return nil, merkletree.ErrNotFound
  76. }
  77. return value, err
  78. }
  79. // Put saves a key:value into the db.Storage
  80. func (tx *StorageTx) Put(k, v []byte) error {
  81. tx.cache.Put(merkletree.Concat(tx.prefix, k[:]), v)
  82. return nil
  83. }
  84. // Add implements the method Add of the interface db.Tx
  85. func (tx *StorageTx) Add(atx merkletree.Tx) error {
  86. ldbtx := atx.(*StorageTx)
  87. for _, v := range ldbtx.cache {
  88. tx.cache.Put(v.K, v.V)
  89. }
  90. return nil
  91. }
  92. // Commit implements the method Commit of the interface db.Tx
  93. func (tx *StorageTx) Commit() error {
  94. var batch leveldb.Batch
  95. for _, v := range tx.cache {
  96. batch.Put(v.K, v.V)
  97. }
  98. tx.cache = nil
  99. return tx.ldb.Write(&batch, nil)
  100. }
  101. // Close implements the method Close of the interface db.Tx
  102. func (tx *StorageTx) Close() {
  103. tx.cache = nil
  104. }
  105. // Close implements the method Close of the interface db.Storage
  106. func (l *Storage) Close() {
  107. if err := l.ldb.Close(); err != nil {
  108. panic(err)
  109. }
  110. }
  111. // LevelDB is an extra method that returns the *leveldb.DB
  112. func (l *Storage) LevelDB() *leveldb.DB {
  113. return l.ldb
  114. }
  115. // List implements the method List of the interface db.Storage
  116. func (l *Storage) List(limit int) ([]merkletree.KV, error) {
  117. ret := []merkletree.KV{}
  118. err := l.Iterate(func(key []byte, value []byte) (bool, error) {
  119. ret = append(ret, merkletree.KV{K: merkletree.Clone(key), V: merkletree.Clone(value)})
  120. if len(ret) == limit {
  121. return false, nil
  122. }
  123. return true, nil
  124. })
  125. return ret, err
  126. }