Пример #1
0
// Delete removes a value with given key.
func (db *LevelDB) Delete(ctx storage.Context, tk storage.TKey) error {
	if db == nil {
		return fmt.Errorf("Can't call Delete on nil LevelDB")
	}
	if ctx == nil {
		return fmt.Errorf("Received nil context in Delete()")
	}
	wo := db.options.WriteOptions

	var err error
	key := ctx.ConstructKey(tk)
	if !ctx.Versioned() {
		dvid.StartCgo()
		err = db.ldb.Delete(wo, key)
		dvid.StopCgo()
	} else {
		vctx, ok := ctx.(storage.VersionedCtx)
		if !ok {
			return fmt.Errorf("Non-versioned context that says it's versioned received in Delete(): %v", ctx)
		}
		tombstoneKey := vctx.TombstoneKey(tk)
		batch := db.NewBatch(vctx).(*goBatch)
		batch.WriteBatch.Delete(key)
		batch.WriteBatch.Put(tombstoneKey, dvid.EmptyValue())
		if err = batch.Commit(); err != nil {
			dvid.Criticalf("Error on batch commit of Delete: %v\n", err)
			err = fmt.Errorf("Error on batch commit of Delete: %v", err)
		}
	}

	return err
}
Пример #2
0
// Put writes a value with given key.
func (db *LevelDB) Put(ctx storage.Context, tk storage.TKey, v []byte) error {
	if ctx == nil {
		return fmt.Errorf("Received nil context in Put()")
	}
	wo := db.options.WriteOptions

	var err error
	key := ctx.ConstructKey(tk)
	if !ctx.Versioned() {
		dvid.StartCgo()
		err = db.ldb.Put(wo, key, v)
		dvid.StopCgo()
	} else {
		vctx, ok := ctx.(storage.VersionedCtx)
		if !ok {
			return fmt.Errorf("Non-versioned context that says it's versioned received in Put(): %v", ctx)
		}
		tombstoneKey := vctx.TombstoneKey(tk)
		batch := db.NewBatch(vctx).(*goBatch)
		batch.WriteBatch.Delete(tombstoneKey)
		batch.WriteBatch.Put(key, v)
		if err = batch.Commit(); err != nil {
			batch.Close()
			err = fmt.Errorf("Error on PUT: %v\n", err)
		}
	}

	storage.StoreKeyBytesWritten <- len(key)
	storage.StoreValueBytesWritten <- len(v)
	return err
}
Пример #3
0
// PutRange puts key-value pairs that have been sorted in sequential key order.
func (db *LMDB) PutRange(values []KeyValue) error {
	if db == nil || db.env == nil {
		return fmt.Errorf("Cannot run PutRange() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, 0)
	if err != nil {
		return err
	}
	defer txn.Commit()

	for _, kv := range values {
		kBytes := kv.K.Bytes()
		v := kv.V
		if v == nil || len(v) == 0 {
			v = []byte{0}
		}
		if err := txn.Put(db.dbi, kBytes, v, 0); err != nil {
			return err
		}
		StoreKeyBytesRead <- len(kBytes)
		StoreValueBytesRead <- len(v)
	}
	return nil
}
Пример #4
0
// Get returns a value given a key.
func (db *LevelDB) Get(ctx storage.Context, tk storage.TKey) ([]byte, error) {
	if ctx == nil {
		return nil, fmt.Errorf("Received nil context in Get()")
	}
	if ctx.Versioned() {
		vctx, ok := ctx.(storage.VersionedCtx)
		if !ok {
			return nil, fmt.Errorf("Bad Get(): context is versioned but doesn't fulfill interface: %v", ctx)
		}

		// Get all versions of this key and return the most recent
		// log.Printf("  basholeveldb versioned get of key %v\n", k)
		values, err := db.getSingleKeyVersions(vctx, tk)
		// log.Printf("            got back %v\n", values)
		if err != nil {
			return nil, err
		}
		kv, err := vctx.VersionedKeyValue(values)
		// log.Printf("  after deversioning: %v\n", kv)
		if kv != nil {
			return kv.V, err
		}
		return nil, err
	} else {
		key := ctx.ConstructKey(tk)
		ro := db.options.ReadOptions
		// log.Printf("  basholeveldb unversioned get of key %v\n", key)
		dvid.StartCgo()
		v, err := db.ldb.Get(ro, key)
		dvid.StopCgo()
		storage.StoreValueBytesRead <- len(v)
		return v, err
	}
}
Пример #5
0
func (db *LevelDB) metadataExists() (bool, error) {
	var ctx storage.MetadataContext
	keyBeg, keyEnd := ctx.KeyRange()
	dvid.StartCgo()
	ro := levigo.NewReadOptions()
	it := db.ldb.NewIterator(ro)
	defer func() {
		it.Close()
		dvid.StopCgo()
	}()

	it.Seek(keyBeg)
	for {
		if it.Valid() {
			// Did we pass the final key?
			if bytes.Compare(it.Key(), keyEnd) > 0 {
				break
			}
			return true, nil
		}
		break
	}
	if err := it.GetError(); err != nil {
		return false, err
	}
	dvid.Infof("No metadata found for %s...\n", db)
	return false, nil
}
Пример #6
0
func (batch *goBatch) Commit() error {
	dvid.StartCgo()
	defer dvid.StopCgo()

	err := batch.ldb.Write(batch.wo, batch.WriteBatch)
	batch.WriteBatch.Close()
	return err
}
Пример #7
0
func (b *batch) Commit() error {
	if b == nil {
		return fmt.Errorf("Illegal Commit() on a nil batch")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()
	return b.txn.Commit()
}
Пример #8
0
// RawDelete is a low-level function.  It deletes a key-value pair using full keys
// without any context.  This can be used in conjunction with RawRangeQuery.
func (db *LevelDB) RawDelete(k storage.Key) error {
	if db == nil {
		return fmt.Errorf("Can't call RawDelete on nil LevelDB")
	}
	wo := db.options.WriteOptions
	dvid.StartCgo()
	defer dvid.StopCgo()
	return db.ldb.Delete(wo, k)
}
Пример #9
0
func (b *batch) Delete(k Key) {
	if b != nil {
		dvid.StartCgo()
		defer dvid.StopCgo()
		if err := b.txn.Del(b.dbi, k.Bytes(), nil); err != nil {
			dvid.Error("Error in batch Delete: %s", err.Error())
		}
	}
}
Пример #10
0
// newLevelDB returns a leveldb backend, creating leveldb
// at the path if it doesn't already exist.
func (e Engine) newLevelDB(config dvid.StoreConfig) (*LevelDB, bool, error) {
	path, _, err := parseConfig(config)
	if err != nil {
		return nil, false, err
	}

	// Is there a database already at this path?  If not, create.
	var created bool
	if _, err := os.Stat(path); os.IsNotExist(err) {
		dvid.Infof("Database not already at path (%s). Creating directory...\n", path)
		created = true
		// Make a directory at the path.
		if err := os.MkdirAll(path, 0744); err != nil {
			return nil, true, fmt.Errorf("Can't make directory at %s: %v", path, err)
		}
	} else {
		dvid.Infof("Found directory at %s (err = %v)\n", path, err)
	}

	// Open the database
	dvid.StartCgo()
	defer dvid.StopCgo()

	opt, err := getOptions(config.Config)
	if err != nil {
		return nil, false, err
	}

	leveldb := &LevelDB{
		directory: path,
		config:    config,
		options:   opt,
	}

	dvid.Infof("Opening basholeveldb @ path %s\n", path)
	ldb, err := levigo.Open(path, opt.Options)
	if err != nil {
		return nil, false, err
	}
	leveldb.ldb = ldb

	// if we know it's newly created, just return.
	if created {
		return leveldb, created, nil
	}

	// otherwise, check if there's been any metadata or we need to initialize it.
	metadataExists, err := leveldb.metadataExists()
	if err != nil {
		leveldb.Close()
		return nil, false, err
	}

	return leveldb, !metadataExists, nil
}
Пример #11
0
func (batch *goBatch) Commit() error {
	if batch == nil {
		return fmt.Errorf("Received nil batch in batch.Commit()\n")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	err := batch.ldb.Write(batch.wo, batch.WriteBatch)
	batch.WriteBatch.Close()
	return err
}
Пример #12
0
// OpenFUSE mounts the given directory as a FUSE file system.
// The FUSE system is a singleton with only one FUSE server operable.
func OpenFUSE(dir string, data Mountable, vinfo VersionInfo) error {
	fuseServer.mutex.Lock()
	defer fuseServer.mutex.Unlock()

	// Make sure we haven't switched mount directory.
	if len(fuseServer.dir) > 0 {
		if fuseServer.dir != dir {
			return fmt.Errorf("Cannot open more than one FUSE directory.  Currently open: %s\n",
				fuseServer.dir)
		}
	}

	// Make sure our mount directory is present and a directory.
	finfo, err := os.Stat(dir)
	if err != nil {
		if os.IsNotExist(err) {
			if err = os.MkdirAll(dir, 0744); err != nil {
				return fmt.Errorf("Cannot create mount directory: %s (%s)\n",
					dir, err.Error())
			}
		} else {
			return fmt.Errorf("Cannot access given mount directory: %s\n", dir)
		}
	} else if !finfo.IsDir() {
		return fmt.Errorf("Given mount point (%s) is not a directory\n", dir)
	}

	// Check if data is already mounted at this version.
	mount, found := fuseServer.mounts[vinfo.uuid]
	if found {
		mount.AddData(data, vinfo)
		return nil
	}

	fuseServer.mounts[vinfo.uuid] = Mount{Data{data}, vinfo}

	// Mount and serve if not already served.
	if fuseServer.dir == "" {
		fuseServer.dir = dir
		conn, err := fuse.Mount(dir)
		if err != nil {
			return err
		}

		// Run FUSE system in gothread.
		go func() {
			dvid.StartCgo()
			fs.Serve(conn, fuseServer)
			dvid.StopCgo()
		}()
	}
	return nil
}
Пример #13
0
// unversionedRange sends a range of key-value pairs down a channel.
func (db *LevelDB) unversionedRange(ctx storage.Context, begTKey, endTKey storage.TKey, ch chan errorableKV, done <-chan struct{}, keysOnly bool) {
	dvid.StartCgo()
	ro := levigo.NewReadOptions()
	it := db.ldb.NewIterator(ro)
	defer func() {
		it.Close()
		dvid.StopCgo()
	}()

	// Apply context if applicable
	begKey := ctx.ConstructKey(begTKey)
	endKey := ctx.ConstructKey(endTKey)

	// fmt.Printf("unversionedRange():\n")
	// fmt.Printf("    index beg: %v\n", kStart)
	// fmt.Printf("    index end: %v\n", kEnd)
	// fmt.Printf("    key start: %v\n", keyBeg)
	// fmt.Printf("      key end: %v\n", keyEnd)

	var itValue []byte
	it.Seek(begKey)
	for {
		if it.Valid() {
			// fmt.Printf("unversioned found key %v, %d bytes value\n", it.Key(), len(it.Value()))
			if !keysOnly {
				itValue = it.Value()
				storage.StoreValueBytesRead <- len(itValue)
			}
			itKey := it.Key()
			storage.StoreKeyBytesRead <- len(itKey)
			// Did we pass the final key?
			if bytes.Compare(itKey, endKey) > 0 {
				break
			}
			select {
			case <-done:
				ch <- errorableKV{nil, nil}
				return
			case ch <- errorableKV{&storage.KeyValue{K: itKey, V: itValue}, nil}:
				it.Next()
			}
		} else {
			break
		}
	}
	if err := it.GetError(); err != nil {
		ch <- errorableKV{nil, err}
	} else {
		ch <- errorableKV{nil, nil}
	}
	return
}
Пример #14
0
// RawPut is a low-level function that puts a key-value pair using full keys.
// This can be used in conjunction with RawRangeQuery.
func (db *LevelDB) RawPut(k storage.Key, v []byte) error {
	wo := db.options.WriteOptions
	dvid.StartCgo()
	defer dvid.StopCgo()

	if err := db.ldb.Put(wo, k, v); err != nil {
		return err
	}

	storage.StoreKeyBytesWritten <- len(k)
	storage.StoreValueBytesWritten <- len(v)
	return nil
}
Пример #15
0
// ProcessRange sends a range of key-value pairs to chunk handlers.
func (db *LMDB) ProcessRange(kStart, kEnd Key, op *ChunkOp, f func(*Chunk)) error {
	if db == nil || db.env == nil {
		return fmt.Errorf("Cannot ProcessRange() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, lmdb.RDONLY)
	if err != nil {
		return err
	}
	defer txn.Abort()
	cursor, err := txn.CursorOpen(db.dbi)
	if err != nil {
		return err
	}
	defer cursor.Close()

	seekKey := kStart.Bytes()
	endBytes := kEnd.Bytes()
	var cursorOp uint = lmdb.SET_RANGE
	for {
		k, v, rc := cursor.Get(seekKey, cursorOp)
		if rc != nil {
			break
		}
		seekKey = nil
		cursorOp = lmdb.NEXT
		StoreKeyBytesRead <- len(k)
		StoreValueBytesRead <- len(v)
		if k == nil || bytes.Compare(k, endBytes) > 0 {
			break
		}
		// Convert byte representation of key to storage.Key
		var key Key
		key, err = kStart.BytesToKey(k)
		if err != nil {
			return err
		}
		if op.Wg != nil {
			op.Wg.Add(1)
		}
		chunk := &Chunk{
			op,
			KeyValue{key, v},
		}
		f(chunk)
	}
	return nil
}
Пример #16
0
// Delete removes a value with given key.
// If the key does not exist, it returns without error.
func (db *LMDB) Delete(k Key) error {
	if db == nil || db.env == nil {
		return fmt.Errorf("Cannot GetRange() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, 0)
	if err != nil {
		return err
	}
	defer txn.Commit()
	return txn.Del(db.dbi, k.Bytes(), nil)
}
Пример #17
0
// NewKeyValueStore returns a lmdb backend.
func NewKeyValueStore(path string, create bool, config dvid.Config) (Engine, error) {
	// Create the directory if it doesn't exist.
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if err = os.MkdirAll(path, 0770); err != nil {
			return nil, fmt.Errorf("Datastore (%s) doesn't exist and couldn't be created: %s", err.Error())
		}
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	opt, err := GetOptions(create, config)
	if err != nil {
		return nil, err
	}

	env, err := lmdb.NewEnv()
	if err != nil {
		return nil, err
	}

	if err = env.SetMapSize(uint64(opt.GBytes * dvid.Giga)); err != nil {
		return nil, err
	}

	if err = env.Open(path, lmdb.NOSYNC|lmdb.WRITEMAP, 0664); err != nil {
		return nil, err
	}

	txn, err := env.BeginTxn(nil, 0)
	if err != nil {
		return nil, fmt.Errorf("Cannot begin transaction: %s", err.Error())
	}

	dbi, err := txn.DBIOpen(nil, 0)
	if err != nil {
		return nil, fmt.Errorf("Cannot create DBI: %s", err.Error())
	}

	db := &LMDB{
		path:    path,
		config:  config,
		options: opt,
		env:     env,
		dbi:     dbi,
	}
	txn.Abort()

	return db, nil
}
Пример #18
0
// RepairStore tries to repair a damaged leveldb
func RepairStore(path string, config dvid.Config) error {
	dvid.StartCgo()
	defer dvid.StopCgo()

	opt, err := GetOptions(false, config)
	if err != nil {
		return err
	}

	err = levigo.RepairDatabase(path, opt.Options)
	if err != nil {
		return err
	}
	return nil
}
Пример #19
0
func (batch *goBatch) Delete(tk storage.TKey) {
	if batch == nil || batch.ctx == nil {
		dvid.Criticalf("Received nil batch or nil batch context in batch.Delete()\n")
		return
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	key := batch.ctx.ConstructKey(tk)
	if batch.vctx != nil {
		tombstone := batch.vctx.TombstoneKey(tk) // This will now have current version
		batch.WriteBatch.Put(tombstone, dvid.EmptyValue())
	}
	batch.WriteBatch.Delete(key)
}
Пример #20
0
// Repair tries to repair a damaged leveldb.  Requires "path" string.  Implements
// the RepairableEngine interface.
func (e Engine) Repair(path string) error {
	dvid.StartCgo()
	defer dvid.StopCgo()

	opt, err := getOptions(dvid.Config{})
	if err != nil {
		return err
	}

	err = levigo.RepairDatabase(path, opt.Options)
	if err != nil {
		return err
	}
	return nil
}
Пример #21
0
func (b *batch) Put(k Key, v []byte) {
	if b != nil {
		dvid.StartCgo()
		defer dvid.StopCgo()
		kBytes := k.Bytes()
		if v == nil || len(v) == 0 {
			v = []byte{0}
		}
		if err := b.txn.Put(b.dbi, kBytes, v, 0); err != nil {
			dvid.Error("Error in batch Put: %s", err.Error())
			return
		}
		StoreKeyBytesWritten <- len(kBytes)
		StoreValueBytesWritten <- len(v)
	}
}
Пример #22
0
// NewBatch returns an implementation that allows batch writes
func (db *LevelDB) NewBatch(ctx storage.Context) storage.Batch {
	if ctx == nil {
		dvid.Criticalf("Received nil context in NewBatch()")
		return nil
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	var vctx storage.VersionedCtx
	var ok bool
	vctx, ok = ctx.(storage.VersionedCtx)
	if !ok {
		vctx = nil
	}
	return &goBatch{ctx, vctx, levigo.NewWriteBatch(), db.options.WriteOptions, db.ldb}
}
Пример #23
0
func (batch *goBatch) Put(tk storage.TKey, v []byte) {
	if batch == nil || batch.ctx == nil {
		dvid.Criticalf("Received nil batch or nil batch context in batch.Put()\n")
		return
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	key := batch.ctx.ConstructKey(tk)
	if batch.vctx != nil {
		tombstone := batch.vctx.TombstoneKey(tk) // This will now have current version
		batch.WriteBatch.Delete(tombstone)
	}
	storage.StoreKeyBytesWritten <- len(key)
	storage.StoreValueBytesWritten <- len(v)
	batch.WriteBatch.Put(key, v)
}
Пример #24
0
// KeysInRange returns a range of present keys spanning (kStart, kEnd).
// For lmdb database, values are read but not returned.
func (db *LMDB) KeysInRange(kStart, kEnd Key) ([]Key, error) {
	if db == nil || db.env == nil {
		return nil, fmt.Errorf("Cannot run KeysInRange() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, lmdb.RDONLY)
	if err != nil {
		return nil, err
	}
	defer txn.Abort()
	cursor, err := txn.CursorOpen(db.dbi)
	if err != nil {
		return nil, err
	}
	defer cursor.Close()

	seekKey := kStart.Bytes()
	endBytes := kEnd.Bytes()
	keys := []Key{}
	var cursorOp uint = lmdb.SET_RANGE
	for {
		k, v, rc := cursor.Get(seekKey, cursorOp)
		if rc != nil {
			break
		}
		seekKey = nil
		cursorOp = lmdb.NEXT
		StoreKeyBytesRead <- len(k)
		StoreValueBytesRead <- len(v)
		if k == nil || bytes.Compare(k, endBytes) > 0 {
			break
		}
		// Convert byte representation of key to storage.Key
		var key Key
		key, err = kStart.BytesToKey(k)
		if err != nil {
			return nil, err
		}
		keys = append(keys, key)
	}
	return keys, nil
}
Пример #25
0
// RawRangeQuery sends a range of full keys.  This is to be used for low-level data
// retrieval like DVID-to-DVID communication and should not be used by data type
// implementations if possible.  A nil is sent down the channel when the
// range is complete.
func (db *LevelDB) RawRangeQuery(kStart, kEnd storage.Key, keysOnly bool, out chan *storage.KeyValue, cancel <-chan struct{}) error {
	if db == nil {
		return fmt.Errorf("Can't call RawRangeQuery on nil LevelDB")
	}
	dvid.StartCgo()
	ro := levigo.NewReadOptions()
	it := db.ldb.NewIterator(ro)
	defer func() {
		it.Close()
		dvid.StopCgo()
	}()

	var itValue []byte
	it.Seek(kStart)
	for {
		if it.Valid() {
			if !keysOnly {
				itValue = it.Value()
				storage.StoreValueBytesRead <- len(itValue)
			}
			itKey := it.Key()
			storage.StoreKeyBytesRead <- len(itKey)
			// Did we pass the final key?
			if bytes.Compare(itKey, kEnd) > 0 {
				break
			}
			kv := storage.KeyValue{itKey, itValue}
			select {
			case out <- &kv:
			case <-cancel:
				return nil
			}
			//out <- &kv
			it.Next()
		} else {
			break
		}
	}
	out <- nil
	if err := it.GetError(); err != nil {
		return err
	}
	return nil
}
Пример #26
0
// newLevelDB returns a leveldb backend.  If create is true, the leveldb
// will be created at the path if it doesn't already exist.
func (e Engine) newLevelDB(config dvid.EngineConfig) (*LevelDB, bool, error) {
	// Create path depending on whether it is testing database or not.
	path := config.Path
	if config.Testing {
		path = filepath.Join(os.TempDir(), config.Path)
	}

	// Is there a database already at this path?  If not, create.
	var created bool
	if _, err := os.Stat(path); os.IsNotExist(err) {
		dvid.Infof("Database not already at path (%s). Creating directory...\n", path)
		created = true
		// Make a directory at the path.
		if err := os.MkdirAll(path, 0744); err != nil {
			return nil, true, fmt.Errorf("Can't make directory at %s: %v", path, err)
		}
	} else {
		dvid.Infof("Found directory at %s (err = %v)\n", path, err)
	}

	// Open the database
	dvid.StartCgo()
	defer dvid.StopCgo()

	opt, err := getOptions(config.Config)
	if err != nil {
		return nil, false, err
	}

	leveldb := &LevelDB{
		directory: path,
		config:    config,
		options:   opt,
	}

	ldb, err := levigo.Open(path, opt.Options)
	if err != nil {
		return nil, false, err
	}
	leveldb.ldb = ldb

	return leveldb, created, nil
}
Пример #27
0
// Get returns a value given a key.
func (db *LMDB) Get(k Key) ([]byte, error) {
	if db == nil || db.env == nil {
		return nil, fmt.Errorf("Cannot Get() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, lmdb.RDONLY)
	if err != nil {
		return nil, err
	}
	defer txn.Abort()

	value, err := txn.Get(db.dbi, k.Bytes())
	if err != nil {
		return nil, err
	}
	return value, nil
}
Пример #28
0
// getSingleKeyVersions returns all versions of a key.  These key-value pairs will be sorted
// in ascending key order and could include a tombstone key.
func (db *LevelDB) getSingleKeyVersions(vctx storage.VersionedCtx, tk []byte) ([]*storage.KeyValue, error) {
	dvid.StartCgo()
	ro := levigo.NewReadOptions()
	it := db.ldb.NewIterator(ro)
	defer func() {
		it.Close()
		dvid.StopCgo()
	}()

	values := []*storage.KeyValue{}
	begKey, err := vctx.MinVersionKey(tk)
	if err != nil {
		return nil, err
	}
	endKey, err := vctx.MaxVersionKey(tk)
	if err != nil {
		return nil, err
	}

	it.Seek(begKey)
	for {
		if it.Valid() {
			itKey := it.Key()
			storage.StoreKeyBytesRead <- len(itKey)
			if bytes.Compare(itKey, endKey) > 0 {
				// log.Printf("key past %v\n", kEnd)
				return values, nil
			}
			itValue := it.Value()
			// log.Printf("got value of length %d\n", len(itValue))
			storage.StoreValueBytesRead <- len(itValue)
			values = append(values, &storage.KeyValue{itKey, itValue})
			it.Next()
		} else {
			err = it.GetError()
			// log.Printf("iteration done, err = %v\n", err)
			if err == nil {
				return values, nil
			}
			return nil, err
		}
	}
}
Пример #29
0
// NewBatch returns an implementation that allows batch writes.  This lmdb implementation
// uses a transaction for the batch.
func (db *LMDB) NewBatch() Batch {
	if db == nil || db.env == nil {
		dvid.Error("Cannot do NewBatch() of lmdb with nil database")
		return nil
	}
	b := new(batch)
	b.env = db.env
	b.dbi = db.dbi

	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, 0)
	if err != nil {
		dvid.Error("Error in BeginTxn() for NewBatch() of lmdb")
		return nil
	}
	b.txn = txn

	return b
}
Пример #30
0
// Put writes a value with given key.
func (db *LMDB) Put(k Key, v []byte) error {
	if db == nil || db.env == nil {
		return fmt.Errorf("Cannot Put() on invalid database.")
	}
	dvid.StartCgo()
	defer dvid.StopCgo()

	txn, err := db.env.BeginTxn(nil, 0)
	if err != nil {
		return err
	}
	defer txn.Commit()
	kBytes := k.Bytes()
	if v == nil || len(v) == 0 {
		v = []byte{0}
	}
	if err := txn.Put(db.dbi, kBytes, v, 0); err != nil {
		return err
	}
	StoreKeyBytesWritten <- len(kBytes)
	StoreValueBytesWritten <- len(v)
	return nil
}