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.

187 lines
4.1 KiB

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