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.

149 lines
3.5 KiB

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