github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/db/goleveldb/go_level_db.go (about) 1 package goleveldb 2 3 import ( 4 "bytes" 5 goerrors "errors" 6 "fmt" 7 "path/filepath" 8 9 "github.com/gnolang/gno/tm2/pkg/db" 10 "github.com/gnolang/gno/tm2/pkg/db/internal" 11 "github.com/syndtr/goleveldb/leveldb" 12 "github.com/syndtr/goleveldb/leveldb/errors" 13 "github.com/syndtr/goleveldb/leveldb/iterator" 14 "github.com/syndtr/goleveldb/leveldb/opt" 15 ) 16 17 func init() { 18 dbCreator := func(name string, dir string) (db.DB, error) { 19 return NewGoLevelDB(name, dir) 20 } 21 db.InternalRegisterDBCreator(db.GoLevelDBBackend, dbCreator, false) 22 } 23 24 var _ db.DB = (*GoLevelDB)(nil) 25 26 type GoLevelDB struct { 27 db *leveldb.DB 28 } 29 30 func NewGoLevelDB(name string, dir string) (*GoLevelDB, error) { 31 return NewGoLevelDBWithOpts(name, dir, nil) 32 } 33 34 func NewGoLevelDBWithOpts(name string, dir string, o *opt.Options) (*GoLevelDB, error) { 35 dbPath := filepath.Join(dir, name+".db") 36 db, err := leveldb.OpenFile(dbPath, o) 37 if err != nil { 38 return nil, err 39 } 40 database := &GoLevelDB{ 41 db: db, 42 } 43 return database, nil 44 } 45 46 // Implements DB. 47 func (db *GoLevelDB) Get(key []byte) []byte { 48 key = internal.NonNilBytes(key) 49 res, err := db.db.Get(key, nil) 50 if err != nil { 51 if goerrors.Is(err, errors.ErrNotFound) { 52 return nil 53 } 54 panic(err) 55 } 56 return res 57 } 58 59 // Implements DB. 60 func (db *GoLevelDB) Has(key []byte) bool { 61 return db.Get(key) != nil 62 } 63 64 // Implements DB. 65 func (db *GoLevelDB) Set(key []byte, value []byte) { 66 key = internal.NonNilBytes(key) 67 value = internal.NonNilBytes(value) 68 err := db.db.Put(key, value, nil) 69 if err != nil { 70 panic(err) 71 } 72 } 73 74 // Implements DB. 75 func (db *GoLevelDB) SetSync(key []byte, value []byte) { 76 key = internal.NonNilBytes(key) 77 value = internal.NonNilBytes(value) 78 err := db.db.Put(key, value, &opt.WriteOptions{Sync: true}) 79 if err != nil { 80 panic(err) 81 } 82 } 83 84 // Implements DB. 85 func (db *GoLevelDB) Delete(key []byte) { 86 key = internal.NonNilBytes(key) 87 err := db.db.Delete(key, nil) 88 if err != nil { 89 panic(err) 90 } 91 } 92 93 // Implements DB. 94 func (db *GoLevelDB) DeleteSync(key []byte) { 95 key = internal.NonNilBytes(key) 96 err := db.db.Delete(key, &opt.WriteOptions{Sync: true}) 97 if err != nil { 98 panic(err) 99 } 100 } 101 102 func (db *GoLevelDB) DB() *leveldb.DB { 103 return db.db 104 } 105 106 // Implements DB. 107 func (db *GoLevelDB) Close() { 108 db.db.Close() 109 } 110 111 // Implements DB. 112 func (db *GoLevelDB) Print() { 113 str, _ := db.db.GetProperty("leveldb.stats") 114 fmt.Printf("%v\n", str) 115 116 itr := db.db.NewIterator(nil, nil) 117 for itr.Next() { 118 key := itr.Key() 119 value := itr.Value() 120 fmt.Printf("[%X]:\t[%X]\n", key, value) 121 } 122 } 123 124 // Implements DB. 125 func (db *GoLevelDB) Stats() map[string]string { 126 keys := []string{ 127 "leveldb.num-files-at-level{n}", 128 "leveldb.stats", 129 "leveldb.sstables", 130 "leveldb.blockpool", 131 "leveldb.cachedblock", 132 "leveldb.openedtables", 133 "leveldb.alivesnaps", 134 "leveldb.aliveiters", 135 } 136 137 stats := make(map[string]string) 138 for _, key := range keys { 139 str, err := db.db.GetProperty(key) 140 if err == nil { 141 stats[key] = str 142 } 143 } 144 return stats 145 } 146 147 // ---------------------------------------- 148 // Batch 149 150 // Implements DB. 151 func (db *GoLevelDB) NewBatch() db.Batch { 152 batch := new(leveldb.Batch) 153 return &goLevelDBBatch{db, batch} 154 } 155 156 type goLevelDBBatch struct { 157 db *GoLevelDB 158 batch *leveldb.Batch 159 } 160 161 // Implements Batch. 162 func (mBatch *goLevelDBBatch) Set(key, value []byte) { 163 mBatch.batch.Put(key, value) 164 } 165 166 // Implements Batch. 167 func (mBatch *goLevelDBBatch) Delete(key []byte) { 168 mBatch.batch.Delete(key) 169 } 170 171 // Implements Batch. 172 func (mBatch *goLevelDBBatch) Write() { 173 err := mBatch.db.db.Write(mBatch.batch, &opt.WriteOptions{Sync: false}) 174 if err != nil { 175 panic(err) 176 } 177 } 178 179 // Implements Batch. 180 func (mBatch *goLevelDBBatch) WriteSync() { 181 err := mBatch.db.db.Write(mBatch.batch, &opt.WriteOptions{Sync: true}) 182 if err != nil { 183 panic(err) 184 } 185 } 186 187 // Implements Batch. 188 // Close is no-op for goLevelDBBatch. 189 func (mBatch *goLevelDBBatch) Close() {} 190 191 // ---------------------------------------- 192 // Iterator 193 // NOTE This is almost identical to db/c_level_db.Iterator 194 // Before creating a third version, refactor. 195 196 // Implements DB. 197 func (db *GoLevelDB) Iterator(start, end []byte) db.Iterator { 198 itr := db.db.NewIterator(nil, nil) 199 return newGoLevelDBIterator(itr, start, end, false) 200 } 201 202 // Implements DB. 203 func (db *GoLevelDB) ReverseIterator(start, end []byte) db.Iterator { 204 itr := db.db.NewIterator(nil, nil) 205 return newGoLevelDBIterator(itr, start, end, true) 206 } 207 208 type goLevelDBIterator struct { 209 source iterator.Iterator 210 start []byte 211 end []byte 212 isReverse bool 213 isInvalid bool 214 } 215 216 var _ db.Iterator = (*goLevelDBIterator)(nil) 217 218 func newGoLevelDBIterator(source iterator.Iterator, start, end []byte, isReverse bool) *goLevelDBIterator { 219 if isReverse { 220 if end == nil { 221 source.Last() 222 } else { 223 valid := source.Seek(end) 224 if valid { 225 eoakey := source.Key() // end or after key 226 if bytes.Compare(end, eoakey) <= 0 { 227 source.Prev() 228 } 229 } else { 230 source.Last() 231 } 232 } 233 } else { 234 if start == nil { 235 source.First() 236 } else { 237 source.Seek(start) 238 } 239 } 240 return &goLevelDBIterator{ 241 source: source, 242 start: start, 243 end: end, 244 isReverse: isReverse, 245 isInvalid: false, 246 } 247 } 248 249 // Implements Iterator. 250 func (itr *goLevelDBIterator) Domain() ([]byte, []byte) { 251 return itr.start, itr.end 252 } 253 254 // Implements Iterator. 255 func (itr *goLevelDBIterator) Valid() bool { 256 // Once invalid, forever invalid. 257 if itr.isInvalid { 258 return false 259 } 260 261 // Panic on DB error. No way to recover. 262 itr.assertNoError() 263 264 // If source is invalid, invalid. 265 if !itr.source.Valid() { 266 itr.isInvalid = true 267 return false 268 } 269 270 // If key is end or past it, invalid. 271 start := itr.start 272 end := itr.end 273 key := itr.source.Key() 274 275 if itr.isReverse { 276 if start != nil && bytes.Compare(key, start) < 0 { 277 itr.isInvalid = true 278 return false 279 } 280 } else { 281 if end != nil && bytes.Compare(end, key) <= 0 { 282 itr.isInvalid = true 283 return false 284 } 285 } 286 287 // Valid 288 return true 289 } 290 291 // Implements Iterator. 292 func (itr *goLevelDBIterator) Key() []byte { 293 // Key returns a copy of the current key. 294 // See https://github.com/syndtr/goleveldb/blob/52c212e6c196a1404ea59592d3f1c227c9f034b2/leveldb/iterator/iter.go#L88 295 itr.assertNoError() 296 itr.assertIsValid() 297 return append([]byte{}, itr.source.Key()...) 298 } 299 300 // Implements Iterator. 301 func (itr *goLevelDBIterator) Value() []byte { 302 // Value returns a copy of the current value. 303 // See https://github.com/syndtr/goleveldb/blob/52c212e6c196a1404ea59592d3f1c227c9f034b2/leveldb/iterator/iter.go#L88 304 itr.assertNoError() 305 itr.assertIsValid() 306 return append([]byte{}, itr.source.Value()...) 307 } 308 309 // Implements Iterator. 310 func (itr *goLevelDBIterator) Next() { 311 itr.assertNoError() 312 itr.assertIsValid() 313 if itr.isReverse { 314 itr.source.Prev() 315 } else { 316 itr.source.Next() 317 } 318 } 319 320 // Implements Iterator. 321 func (itr *goLevelDBIterator) Close() { 322 itr.source.Release() 323 } 324 325 func (itr *goLevelDBIterator) assertNoError() { 326 if err := itr.source.Error(); err != nil { 327 panic(err) 328 } 329 } 330 331 func (itr goLevelDBIterator) assertIsValid() { 332 if !itr.Valid() { 333 panic("goLevelDBIterator is invalid") 334 } 335 }