github.com/evdatsion/aphelion-dpos-bft@v0.32.1/libs/db/c_level_db.go (about)

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