github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/database/leveldb/db.go (about) 1 // Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package leveldb 6 7 /* 8 #include <stdlib.h> 9 #include <leveldb/c.h> 10 11 // This function exists only to clean up lack-of-const warnings when 12 // leveldb_approximate_sizes is called from Go-land. 13 static void go_leveldb_approximate_sizes( 14 leveldb_t* db, 15 int num_ranges, 16 char** range_start_key, const size_t* range_start_key_len, 17 char** range_limit_key, const size_t* range_limit_key_len, 18 uint64_t* sizes 19 ) { 20 leveldb_approximate_sizes(db, 21 num_ranges, 22 (const char* const*)range_start_key, 23 range_start_key_len, 24 (const char* const*)range_limit_key, 25 range_limit_key_len, 26 sizes 27 ); 28 } 29 */ 30 import "C" 31 32 import ( 33 "unsafe" 34 ) 35 36 // DB is a reusable handle to a LevelDB database on disk, created by Open. 37 // 38 // To avoid memory and file descriptor leaks, call Close when the process no 39 // longer needs the handle. Calls to any DB method made after Close will 40 // panic. 41 // 42 // The DB instance may be shared between goroutines. The usual data race 43 // conditions will occur if the same key is written to from more than one, of 44 // course. 45 type DB struct { 46 db *C.leveldb_t 47 } 48 49 // Range is a range of keys in the database. GetApproximateSizes calls with it 50 // begin at the key Start and end right before the key Limit. 51 type Range struct { 52 Start []byte 53 Limit []byte 54 } 55 56 // Snapshot provides a consistent view of read operations in a DB. It is set 57 // on to a ReadOptions and passed in. It is only created by DB.NewSnapshot. 58 // 59 // To prevent memory leaks and resource strain in the database, the snapshot 60 // returned must be released with DB.ReleaseSnapshot method on the DB that 61 // created it. 62 type Snapshot struct { 63 snap *C.leveldb_snapshot_t 64 } 65 66 // Open opens a database. 67 // 68 // Creating a new database is done by calling SetCreateIfMissing(true) on the 69 // Options passed to Open. 70 // 71 // It is usually wise to set a Cache object on the Options with SetCache to 72 // keep recently used data from that database in memory. 73 func Open(name string, o *Options) (*DB, error) { 74 var errStr *C.char 75 dbname := C.CString(name) 76 defer C.free(unsafe.Pointer(dbname)) 77 78 leveldb := C.leveldb_open(o.opt, dbname, &errStr) 79 if errStr != nil { 80 gs := C.GoString(errStr) 81 C.leveldb_free(unsafe.Pointer(errStr)) 82 return nil, leveldb_error(gs) 83 } 84 return &DB{leveldb}, nil 85 } 86 87 // DestroyDatabase removes a database entirely, removing everything from the 88 // filesystem. 89 func DestroyDatabase(name string, o *Options) error { 90 var errStr *C.char 91 dbname := C.CString(name) 92 defer C.free(unsafe.Pointer(dbname)) 93 94 C.leveldb_destroy_db(o.opt, dbname, &errStr) 95 if errStr != nil { 96 gs := C.GoString(errStr) 97 C.leveldb_free(unsafe.Pointer(errStr)) 98 return leveldb_error(gs) 99 } 100 return nil 101 } 102 103 // RepairDatabase attempts to repair a database. 104 // 105 // If the database is unrepairable, an error is returned. 106 func RepairDatabase(name string, o *Options) error { 107 var errStr *C.char 108 dbname := C.CString(name) 109 defer C.free(unsafe.Pointer(dbname)) 110 111 C.leveldb_repair_db(o.opt, dbname, &errStr) 112 if errStr != nil { 113 gs := C.GoString(errStr) 114 C.leveldb_free(unsafe.Pointer(errStr)) 115 return leveldb_error(gs) 116 } 117 return nil 118 } 119 120 // Put writes data associated with a key to the database. 121 // 122 // If a nil []byte is passed in as value, it will be returned by Get as an 123 // zero-length slice. 124 // 125 // The key and value byte slices may be reused safely. Put takes a copy of 126 // them before returning. 127 func (p *DB) Put(wo *WriteOptions, key, value []byte) error { 128 var errStr *C.char 129 // leveldb_put, _get, and _delete call memcpy() (by way of Memtable::Add) 130 // when called, so we do not need to worry about these []byte being 131 // reclaimed by GC. 132 var k, v *C.char 133 if len(key) != 0 { 134 k = (*C.char)(unsafe.Pointer(&key[0])) 135 } 136 if len(value) != 0 { 137 v = (*C.char)(unsafe.Pointer(&value[0])) 138 } 139 C.leveldb_put( 140 p.db, wo.opt, 141 k, C.size_t(len(key)), 142 v, C.size_t(len(value)), 143 &errStr, 144 ) 145 if errStr != nil { 146 gs := C.GoString(errStr) 147 C.leveldb_free(unsafe.Pointer(errStr)) 148 return leveldb_error(gs) 149 } 150 return nil 151 } 152 153 // Get returns the data associated with the key from the database. 154 // 155 // If the key does not exist in the database, a nil []byte is returned. If the 156 // key does exist, but the data is zero-length in the database, a zero-length 157 // []byte will be returned. 158 // 159 // The key byte slice may be reused safely. Get takes a copy of 160 // them before returning. 161 func (p *DB) Get(ro *ReadOptions, key []byte) ([]byte, error) { 162 var errStr *C.char 163 var vallen C.size_t 164 var k *C.char 165 if len(key) != 0 { 166 k = (*C.char)(unsafe.Pointer(&key[0])) 167 } 168 value := C.leveldb_get( 169 p.db, ro.opt, 170 k, C.size_t(len(key)), 171 &vallen, 172 &errStr, 173 ) 174 if errStr != nil { 175 gs := C.GoString(errStr) 176 C.leveldb_free(unsafe.Pointer(errStr)) 177 return nil, leveldb_error(gs) 178 } 179 // https://code.google.com/p/leveldb/issues/detail?id=207 180 if value == nil { 181 err := "NotFound:" 182 return nil, leveldb_error(err) 183 } 184 185 defer C.leveldb_free(unsafe.Pointer(value)) 186 return C.GoBytes(unsafe.Pointer(value), C.int(vallen)), nil 187 } 188 189 // Delete removes the data associated with the key from the database. 190 // 191 // The key byte slice may be reused safely. Delete takes a copy of 192 // them before returning. 193 func (p *DB) Delete(wo *WriteOptions, key []byte) error { 194 var errStr *C.char 195 var k *C.char 196 if len(key) != 0 { 197 k = (*C.char)(unsafe.Pointer(&key[0])) 198 } 199 C.leveldb_delete( 200 p.db, wo.opt, 201 k, C.size_t(len(key)), 202 &errStr, 203 ) 204 if errStr != nil { 205 gs := C.GoString(errStr) 206 C.leveldb_free(unsafe.Pointer(errStr)) 207 return leveldb_error(gs) 208 } 209 return nil 210 } 211 212 // Write atomically writes a WriteBatch to disk. 213 func (p *DB) Write(wo *WriteOptions, w *WriteBatch) error { 214 var errStr *C.char 215 C.leveldb_write(p.db, wo.opt, w.wbatch, &errStr) 216 if errStr != nil { 217 gs := C.GoString(errStr) 218 C.leveldb_free(unsafe.Pointer(errStr)) 219 return leveldb_error(gs) 220 } 221 return nil 222 } 223 224 // NewIterator returns an Iterator over the the database that uses the 225 // ReadOptions given. 226 // 227 // Often, this is used for large, offline bulk reads while serving live 228 // traffic. In that case, it may be wise to disable caching so that the data 229 // processed by the returned Iterator does not displace the already cached 230 // data. This can be done by calling SetFillCache(false) on the ReadOptions 231 // before passing it here. 232 // 233 // Similiarly, ReadOptions.SetSnapshot is also useful. 234 func (p *DB) NewIterator(ro *ReadOptions) *Iterator { 235 it := C.leveldb_create_iterator(p.db, ro.opt) 236 return &Iterator{iter: it} 237 } 238 239 // GetApproximateSizes returns the approximate number of bytes of file system 240 // space used by one or more key ranges. 241 // 242 // The keys counted will begin at Range.Start and end on the key before 243 // Range.Limit. 244 func (p *DB) GetApproximateSizes(ranges []Range) []uint64 { 245 starts := make([]*C.char, len(ranges)) 246 limits := make([]*C.char, len(ranges)) 247 startLens := make([]C.size_t, len(ranges)) 248 limitLens := make([]C.size_t, len(ranges)) 249 for i, r := range ranges { 250 starts[i] = C.CString(string(r.Start)) 251 defer C.free(unsafe.Pointer(starts[i])) 252 limits[i] = C.CString(string(r.Limit)) 253 defer C.free(unsafe.Pointer(limits[i])) 254 startLens[i] = C.size_t(len(r.Start)) 255 limitLens[i] = C.size_t(len(r.Limit)) 256 } 257 sizes := make([]uint64, len(ranges)) 258 C.go_leveldb_approximate_sizes( 259 p.db, 260 C.int(len(ranges)), 261 &starts[0], &startLens[0], 262 &limits[0], &limitLens[0], 263 (*C.uint64_t)(&sizes[0]), 264 ) 265 return sizes 266 } 267 268 // PropertyValue returns the value of a database property. 269 // 270 // Examples of properties include "leveldb.stats", "leveldb.sstables", 271 // and "leveldb.num-files-at-level0". 272 func (p *DB) PropertyValue(propName string) string { 273 cname := C.CString(propName) 274 defer C.free(unsafe.Pointer(cname)) 275 cval := C.leveldb_property_value(p.db, cname) 276 if cval == nil { 277 return "" 278 } 279 defer C.leveldb_free(unsafe.Pointer(cval)) 280 return C.GoString(cval) 281 } 282 283 // NewSnapshot creates a new snapshot of the database. 284 // 285 // The snapshot, when used in a ReadOptions, provides a consistent view of 286 // state of the database at the the snapshot was created. 287 // 288 // To prevent memory leaks and resource strain in the database, the snapshot 289 // returned must be released with DB.ReleaseSnapshot method on the DB that 290 // created it. 291 // 292 // See the LevelDB documentation for details. 293 func (p *DB) NewSnapshot() *Snapshot { 294 return &Snapshot{C.leveldb_create_snapshot(p.db)} 295 } 296 297 // ReleaseSnapshot removes the snapshot from the database's list of snapshots, 298 // and deallocates it. 299 func (p *DB) ReleaseSnapshot(snap *Snapshot) { 300 C.leveldb_release_snapshot(p.db, snap.snap) 301 } 302 303 // CompactRange runs a manual compaction on the Range of keys given. This is 304 // not likely to be needed for typical usage. 305 func (p *DB) CompactRange(r Range) { 306 var start, limit *C.char 307 if len(r.Start) != 0 { 308 start = (*C.char)(unsafe.Pointer(&r.Start[0])) 309 } 310 if len(r.Limit) != 0 { 311 limit = (*C.char)(unsafe.Pointer(&r.Limit[0])) 312 } 313 C.leveldb_compact_range(p.db, 314 start, C.size_t(len(r.Start)), 315 limit, C.size_t(len(r.Limit)), 316 ) 317 } 318 319 // Close closes the database, rendering it unusable for I/O, by deallocating 320 // the underlying handle. 321 // 322 // Any attempts to use the DB after Close is called will panic. 323 func (p *DB) Close() { 324 C.leveldb_close(p.db) 325 }