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 }