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  }