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  }