ledisdb/vendor/gomdb/env.go

230 lines
6.0 KiB
Go

// +build lmdb
package mdb
/*
#cgo CFLAGS: -pthread -W -Wall -Wno-unused-parameter -Wbad-function-cast -O2 -g
#cgo freebsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo openbsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo netbsd CFLAGS: -DMDB_DSYNC=O_SYNC
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"
import (
"errors"
"fmt"
"syscall"
"unsafe"
)
const SUCCESS = C.MDB_SUCCESS
// mdb_env Environment Flags
const (
FIXEDMAP = C.MDB_FIXEDMAP // mmap at a fixed address (experimental)
NOSUBDIR = C.MDB_NOSUBDIR // no environment directory
NOSYNC = C.MDB_NOSYNC // don't fsync after commit
RDONLY = C.MDB_RDONLY // read only
NOMETASYNC = C.MDB_NOMETASYNC // don't fsync metapage after commit
WRITEMAP = C.MDB_WRITEMAP // use writable mmap
MAPASYNC = C.MDB_MAPASYNC // use asynchronous msync when MDB_WRITEMAP is use
NOTLS = C.MDB_NOTLS // tie reader locktable slots to Txn objects instead of threads
)
type DBI uint
type Errno C.int
// minimum and maximum values produced for the Errno type. syscall.Errnos of
// other values may still be produced.
const minErrno, maxErrno C.int = C.MDB_KEYEXIST, C.MDB_LAST_ERRCODE
func (e Errno) Error() string {
s := C.GoString(C.mdb_strerror(C.int(e)))
if s == "" {
return fmt.Sprint("mdb errno:", int(e))
}
return s
}
// for tests that can't import C
func _errno(ret int) error {
return errno(C.int(ret))
}
func errno(ret C.int) error {
if ret == C.MDB_SUCCESS {
return nil
}
if minErrno <= ret && ret <= maxErrno {
return Errno(ret)
}
return syscall.Errno(ret)
}
// error codes
const (
KeyExist = Errno(C.MDB_KEYEXIST)
NotFound = Errno(C.MDB_NOTFOUND)
PageNotFound = Errno(C.MDB_PAGE_NOTFOUND)
Corrupted = Errno(C.MDB_CORRUPTED)
Panic = Errno(C.MDB_PANIC)
VersionMismatch = Errno(C.MDB_VERSION_MISMATCH)
Invalid = Errno(C.MDB_INVALID)
MapFull = Errno(C.MDB_MAP_FULL)
DbsFull = Errno(C.MDB_DBS_FULL)
ReadersFull = Errno(C.MDB_READERS_FULL)
TlsFull = Errno(C.MDB_TLS_FULL)
TxnFull = Errno(C.MDB_TXN_FULL)
CursorFull = Errno(C.MDB_CURSOR_FULL)
PageFull = Errno(C.MDB_PAGE_FULL)
MapResized = Errno(C.MDB_MAP_RESIZED)
Incompatibile = Errno(C.MDB_INCOMPATIBLE)
)
func Version() string {
var major, minor, patch *C.int
ver_str := C.mdb_version(major, minor, patch)
return C.GoString(ver_str)
}
// Env is opaque structure for a database environment.
// A DB environment supports multiple databases, all residing in the
// same shared-memory map.
type Env struct {
_env *C.MDB_env
}
// Create an MDB environment handle.
func NewEnv() (*Env, error) {
var _env *C.MDB_env
ret := C.mdb_env_create(&_env)
if ret != SUCCESS {
return nil, errno(ret)
}
return &Env{_env}, nil
}
// Open an environment handle. If this function fails Close() must be called to discard the Env handle.
func (env *Env) Open(path string, flags uint, mode uint) error {
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
ret := C.mdb_env_open(env._env, cpath, C.uint(NOTLS|flags), C.mdb_mode_t(mode))
return errno(ret)
}
func (env *Env) Close() error {
if env._env == nil {
return errors.New("Environment already closed")
}
C.mdb_env_close(env._env)
env._env = nil
return nil
}
func (env *Env) Copy(path string) error {
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
ret := C.mdb_env_copy(env._env, cpath)
return errno(ret)
}
// Statistics for a database in the environment
type Stat struct {
PSize uint // Size of a database page. This is currently the same for all databases.
Depth uint // Depth (height) of the B-tree
BranchPages uint64 // Number of internal (non-leaf) pages
LeafPages uint64 // Number of leaf pages
OverflowPages uint64 // Number of overflow pages
Entries uint64 // Number of data items
}
func (env *Env) Stat() (*Stat, error) {
var _stat C.MDB_stat
ret := C.mdb_env_stat(env._env, &_stat)
if ret != SUCCESS {
return nil, errno(ret)
}
stat := Stat{PSize: uint(_stat.ms_psize),
Depth: uint(_stat.ms_depth),
BranchPages: uint64(_stat.ms_branch_pages),
LeafPages: uint64(_stat.ms_leaf_pages),
OverflowPages: uint64(_stat.ms_overflow_pages),
Entries: uint64(_stat.ms_entries)}
return &stat, nil
}
type Info struct {
MapSize uint64 // Size of the data memory map
LastPNO uint64 // ID of the last used page
LastTxnID uint64 // ID of the last committed transaction
MaxReaders uint // maximum number of threads for the environment
NumReaders uint // maximum number of threads used in the environment
}
func (env *Env) Info() (*Info, error) {
var _info C.MDB_envinfo
ret := C.mdb_env_info(env._env, &_info)
if ret != SUCCESS {
return nil, errno(ret)
}
info := Info{MapSize: uint64(_info.me_mapsize),
LastPNO: uint64(_info.me_last_pgno),
LastTxnID: uint64(_info.me_last_txnid),
MaxReaders: uint(_info.me_maxreaders),
NumReaders: uint(_info.me_numreaders)}
return &info, nil
}
func (env *Env) Sync(force int) error {
ret := C.mdb_env_sync(env._env, C.int(force))
return errno(ret)
}
func (env *Env) SetFlags(flags uint, onoff int) error {
ret := C.mdb_env_set_flags(env._env, C.uint(flags), C.int(onoff))
return errno(ret)
}
func (env *Env) Flags() (uint, error) {
var _flags C.uint
ret := C.mdb_env_get_flags(env._env, &_flags)
if ret != SUCCESS {
return 0, errno(ret)
}
return uint(_flags), nil
}
func (env *Env) Path() (string, error) {
var path string
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
ret := C.mdb_env_get_path(env._env, &cpath)
if ret != SUCCESS {
return "", errno(ret)
}
return C.GoString(cpath), nil
}
func (env *Env) SetMapSize(size uint64) error {
ret := C.mdb_env_set_mapsize(env._env, C.size_t(size))
return errno(ret)
}
func (env *Env) SetMaxReaders(size uint) error {
ret := C.mdb_env_set_maxreaders(env._env, C.uint(size))
return errno(ret)
}
func (env *Env) SetMaxDBs(size DBI) error {
ret := C.mdb_env_set_maxdbs(env._env, C.MDB_dbi(size))
return errno(ret)
}
func (env *Env) DBIClose(dbi DBI) {
C.mdb_dbi_close(env._env, C.MDB_dbi(dbi))
}