github.com/tendermint/tmlibs@v0.9.0/db/c_level_db.go (about)

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