ledisdb/store/mdb/mdb.go

278 lines
4.7 KiB
Go
Raw Normal View History

2014-07-25 13:58:00 +04:00
package mdb
import (
"github.com/siddontang/ledisdb/config"
2014-07-25 13:58:00 +04:00
"github.com/siddontang/ledisdb/store/driver"
2014-08-04 04:48:06 +04:00
mdb "github.com/szferi/gomdb"
2014-07-25 13:58:00 +04:00
"os"
)
type Store struct {
}
func (s Store) String() string {
return "lmdb"
2014-07-25 13:58:00 +04:00
}
type MDB struct {
env *mdb.Env
db mdb.DBI
path string
cfg *config.Config
2014-07-25 13:58:00 +04:00
}
func (s Store) Open(path string, c *config.Config) (driver.IDB, error) {
mapSize := c.LMDB.MapSize
noSync := c.LMDB.NoSync
if mapSize <= 0 {
mapSize = 500 * 1024 * 1024
2014-07-25 13:58:00 +04:00
}
env, err := mdb.NewEnv()
if err != nil {
return MDB{}, err
}
// TODO: max dbs should be configurable
if err := env.SetMaxDBs(1); err != nil {
return MDB{}, err
}
2014-07-30 18:03:24 +04:00
if err := env.SetMapSize(uint64(mapSize)); err != nil {
2014-07-25 13:58:00 +04:00
return MDB{}, err
}
if _, err := os.Stat(path); err != nil {
err = os.MkdirAll(path, 0755)
if err != nil {
return MDB{}, err
}
}
var flags uint = mdb.CREATE
if noSync {
flags |= mdb.NOSYNC | mdb.NOMETASYNC | mdb.WRITEMAP | mdb.MAPASYNC
}
err = env.Open(path, flags, 0755)
2014-07-25 13:58:00 +04:00
if err != nil {
return MDB{}, err
}
tx, err := env.BeginTxn(nil, 0)
if err != nil {
return MDB{}, err
}
dbi, err := tx.DBIOpen(nil, mdb.CREATE)
if err != nil {
return MDB{}, err
}
if err := tx.Commit(); err != nil {
return MDB{}, err
}
db := MDB{
env: env,
db: dbi,
path: path,
}
return db, nil
}
func (s Store) Repair(path string, c *config.Config) error {
2014-07-25 13:58:00 +04:00
println("llmd not supports repair")
return nil
}
func (db MDB) Put(key, value []byte) error {
2014-07-25 19:40:10 +04:00
itr := db.iterator(false)
itr.err = itr.c.Put(key, value, 0)
itr.setState()
2014-07-30 18:03:24 +04:00
return itr.Close()
2014-07-25 13:58:00 +04:00
}
2014-08-02 11:16:16 +04:00
func (db MDB) BatchPut(writes []driver.Write) error {
2014-07-25 13:58:00 +04:00
itr := db.iterator(false)
for _, w := range writes {
if w.Value == nil {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(w.Key, nil, mdb.SET)
2014-07-25 13:58:00 +04:00
if itr.err == nil {
itr.err = itr.c.Del(0)
}
} else {
itr.err = itr.c.Put(w.Key, w.Value, 0)
}
if itr.err != nil && itr.err != mdb.NotFound {
break
}
}
itr.setState()
return itr.Close()
}
func (db MDB) Get(key []byte) ([]byte, error) {
tx, err := db.env.BeginTxn(nil, mdb.RDONLY)
if err != nil {
return nil, err
}
defer tx.Commit()
v, err := tx.Get(db.db, key)
if err == mdb.NotFound {
return nil, nil
}
return v, err
}
func (db MDB) Delete(key []byte) error {
itr := db.iterator(false)
2014-07-25 19:40:10 +04:00
defer itr.Close()
2014-07-25 13:58:00 +04:00
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(key, nil, mdb.SET)
2014-07-25 13:58:00 +04:00
if itr.err == nil {
itr.err = itr.c.Del(0)
}
itr.setState()
2014-07-25 19:40:10 +04:00
return itr.Error()
2014-07-25 13:58:00 +04:00
}
type MDBIterator struct {
key []byte
value []byte
c *mdb.Cursor
tx *mdb.Txn
valid bool
err error
2014-07-29 13:29:51 +04:00
closeAutoCommit bool
2014-07-25 13:58:00 +04:00
}
func (itr *MDBIterator) Key() []byte {
return itr.key
}
func (itr *MDBIterator) Value() []byte {
return itr.value
}
func (itr *MDBIterator) Valid() bool {
return itr.valid
}
func (itr *MDBIterator) Error() error {
return itr.err
}
func (itr *MDBIterator) getCurrent() {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(nil, nil, mdb.GET_CURRENT)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) Seek(key []byte) {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(key, nil, mdb.SET_RANGE)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) Next() {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(nil, nil, mdb.NEXT)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) Prev() {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(nil, nil, mdb.PREV)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) First() {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(nil, nil, mdb.FIRST)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) Last() {
2014-08-04 04:48:06 +04:00
itr.key, itr.value, itr.err = itr.c.Get(nil, nil, mdb.LAST)
2014-07-25 13:58:00 +04:00
itr.setState()
}
func (itr *MDBIterator) setState() {
if itr.err != nil {
if itr.err == mdb.NotFound {
itr.err = nil
}
itr.valid = false
}
}
func (itr *MDBIterator) Close() error {
if err := itr.c.Close(); err != nil {
itr.tx.Abort()
return err
}
2014-07-29 13:29:51 +04:00
if !itr.closeAutoCommit {
return itr.err
}
2014-07-25 13:58:00 +04:00
if itr.err != nil {
itr.tx.Abort()
return itr.err
}
return itr.tx.Commit()
}
func (_ MDB) Name() string {
return "lmdb"
}
func (db MDB) Path() string {
return db.path
}
func (db MDB) Compact() {
}
func (db MDB) iterator(rdonly bool) *MDBIterator {
flags := uint(0)
if rdonly {
flags = mdb.RDONLY
}
tx, err := db.env.BeginTxn(nil, flags)
if err != nil {
2014-07-29 13:29:51 +04:00
return &MDBIterator{nil, nil, nil, nil, false, err, true}
2014-07-25 13:58:00 +04:00
}
c, err := tx.CursorOpen(db.db)
if err != nil {
tx.Abort()
2014-07-29 13:29:51 +04:00
return &MDBIterator{nil, nil, nil, nil, false, err, true}
2014-07-25 13:58:00 +04:00
}
2014-07-29 13:29:51 +04:00
return &MDBIterator{nil, nil, c, tx, true, nil, true}
2014-07-25 13:58:00 +04:00
}
func (db MDB) Close() error {
db.env.DBIClose(db.db)
if err := db.env.Close(); err != nil {
panic(err)
}
return nil
}
func (db MDB) NewIterator() driver.IIterator {
return db.iterator(true)
}
func (db MDB) NewWriteBatch() driver.IWriteBatch {
2014-08-02 11:16:16 +04:00
return driver.NewWriteBatch(db)
2014-07-25 13:58:00 +04:00
}
2014-07-29 13:29:51 +04:00
func (db MDB) Begin() (driver.Tx, error) {
return newTx(db)
}