Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
Add basic env, txn, and dbi functions and modify examples to use them
use fmt; use io; use lmdb_ffi = lmdb::ffi;
use lmdb;
use strings;
use types;
use types::c;
use os;
export fn main() void = {
if (len(os::args) != 3) {
abort("need two arguments (db dir, key)");
};
const key = lmdb_ffi::val{
const key = lmdb::val{
mv_size = len(strings::toutf8(os::args[2])), mv_data = c::unterminatedstr(os::args[2]): *opaque, };
let val: lmdb_ffi::val = lmdb_ffi::val{
mv_size = 0,
mv_data = null,
};
let env: nullable *lmdb_ffi::env = null;
let rc: int = lmdb_ffi::env_create(&env);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create env");
};
let env: *lmdb_ffi::env = env as *lmdb_ffi::env;
let env = lmdb::env_create()!;
let path = c::fromstr(os::args[1]);
defer free(path);
rc = lmdb_ffi::env_open(env, path, 0, 0o644);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to open env");
};
let txn: nullable *lmdb_ffi::txn = null;
rc = lmdb_ffi::txn_begin(env, null, 0, &txn);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create txn");
};
let txn: *lmdb_ffi::txn = txn as *lmdb_ffi::txn;
lmdb::env_open(env, os::args[1], 0, 0o644)!;
let dbi: lmdb_ffi::dbi = 0;
rc = lmdb_ffi::dbi_open(txn, null, lmdb_ffi::CREATE, &dbi);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create dbi");
};
let txn = lmdb::txn_begin(env, 0)!;
rc = lmdb_ffi::get(txn, dbi, &key, &val);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to get");
};
let dbi = lmdb::dbi_open(txn, null, lmdb_ffi::CREATE)!;
rc = lmdb_ffi::txn_abort(txn);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to abort");
};
let val = lmdb::get(dbi, &key)!;
let data: []u8 = *(&(types::slice {
data = val.mv_data,
length = val.mv_size,
capacity = val.mv_size,
}): *[]u8);
let data = lmdb::val_u8s(&val);
io::write(os::stdout, data)!;
lmdb::txn_abort(txn)!;
};
use fmt; use io;
use lmdb;
use lmdb_ffi = lmdb::ffi;
use strings;
use types;
use types::c;
use os;
export fn main() void = {
if (len(os::args) != 3) {
abort("need two arguments (db dir, key)");
};
const key = lmdb_ffi::val{
const key = lmdb::val {
mv_size = len(strings::toutf8(os::args[2])), mv_data = c::unterminatedstr(os::args[2]): *opaque, }; let v = io::drain(os::stdin)!; defer free(v);
const val = lmdb_ffi::val{
mv_size = len(v),
mv_data = (*(&v: *types::slice)).data: *opaque,
};
const val = lmdb::u8s_val(v);
let env: nullable *lmdb_ffi::env = null;
let rc: int = lmdb_ffi::env_create(&env);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create env");
};
let env: *lmdb_ffi::env = env as *lmdb_ffi::env;
let env = lmdb::env_create()!;
let path = c::fromstr(os::args[1]);
defer free(path);
rc = lmdb_ffi::env_open(env, path, 0, 0o644);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to open env");
};
lmdb::env_open(env, os::args[1], 0, 0o644)!;
let txn: nullable *lmdb_ffi::txn = null;
rc = lmdb_ffi::txn_begin(env, null, 0, &txn);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create txn");
};
let txn: *lmdb_ffi::txn = txn as *lmdb_ffi::txn;
let txn = lmdb::txn_begin(env, 0)!;
let dbi: lmdb_ffi::dbi = 0;
rc = lmdb_ffi::dbi_open(txn, null, lmdb_ffi::CREATE, &dbi);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to create dbi");
};
let dbi = lmdb::dbi_open(txn, null, lmdb_ffi::CREATE)!;
rc = lmdb_ffi::put(txn, dbi, &key, &val, 0);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to put");
};
let val = lmdb::put(dbi, &key, &val, 0)!;
rc = lmdb_ffi::txn_commit(txn);
if (rc != 0) {
fmt::printf("error: {}\n", rc)!;
abort("failed to commit");
};
lmdb::txn_commit(txn)!;
};
use lmdb::ffi;
use types::c;
// An individual LMDB database, i.e. one key-value store.
//
// They are only valid for the lifetime of their parent transaction.
export type dbi = struct {
txn: *ffi::txn,
dbi: ffi::dbi,
};
// Opens a database from a transaction.
export fn dbi_open(txn: *txn, name: nullable *str, flags: uint) (dbi | error) = {
const n: nullable *c::char = match (name) {
case *str => yield c::fromstr(*(name as *str));
case null => yield null;
};
defer free(n);
let d: ffi::dbi = 0;
const rc = ffi::dbi_open(txn: *ffi::txn, n, flags, &d): error;
switch (rc) {
case 0 =>
return dbi {
txn = txn: *ffi::txn,
dbi = d,
};
case =>
return rc;
};
};
// Get a value from the database. The returned value is only valid for the
// lifetime of the transaction associated with the dbi.
export fn get(dbi: dbi, key: *val) (val | error) = {
let data = ffi::val {
mv_size = 0,
mv_data = null,
};
const rc = ffi::get(dbi.txn, dbi.dbi, key: *ffi::val, &data): error;
switch (rc) {
case 0 => return data: val;
case => return rc;
};
};
// Put a value into the database.
export fn put(dbi: dbi, key: *val, data: *val, flags: uint) (void | error) = {
const rc = ffi::put(dbi.txn, dbi.dbi, key: *ffi::val, data: *ffi::val, flags): error;
switch (rc) {
case 0 => return void;
case => return rc;
};
};
use lmdb::ffi;
use types::c;
// Opaque structure for a database environment.
//
// A DB environment supports multiple databases, all residing in the same
// shared-memory map.
export type env = ffi::env;
// Creates an [[env]]. The caller must free it with [[env_close]].
export fn env_create() (*env | error) = {
let e: nullable *ffi::env = null;
const rc = ffi::env_create(&e): error;
switch (rc) {
case 0 => return e: *env;
case => return rc;
};
};
// Closes an [[env]].
export fn env_close(env: *env) void = {
ffi::env_close(env: *ffi::env);
};
// Associates an [[env]] with a on-disk environment.
export fn env_open(env: *env, path: str, flag: uint, mode: u32) (void | error) = {
const p = c::fromstr(path);
defer free(p);
const rc = ffi::env_open(env: *ffi::env, p, flag, mode): error;
return switch (rc) {
case 0 => yield;
case => yield rc;
};
};
// Any error returned by LMDB. export type error = !int;
use lmdb::ffi;
// Opaque structure for a transaction handle.
export type txn = ffi::txn;
// Initiate a transaction.
export fn txn_begin(env: *env, flags: uint, parent: nullable *txn = null) (*txn | error) = {
let t: nullable *ffi::txn = null;
const rc = ffi::txn_begin(env: *ffi::env, parent: nullable *ffi::txn, flags, &t): error;
switch (rc) {
case 0 => return t: *txn;
case => return rc;
};
};
// Abort a transaction, discaring anything it does.
export fn txn_abort(txn: *txn) (void | error) = {
const rc = ffi::txn_abort(txn: *ffi::txn): error;
switch (rc) {
case 0 => return;
case => return rc;
};
};
// Commiting a transaction, writing anything it does.
export fn txn_commit(txn: *txn) (void | error) = {
const rc = ffi::txn_commit(txn: *ffi::txn): error;
switch (rc) {
case 0 => return;
case => return rc;
};
};
use lmdb::ffi;
// Opaque structure for a database environment. // // A DB environment supports multiple databases, all residing in the same // shared-memory map. export type env = ffi::env; // A handle for an individual database in the DB environment. export type dbi = ffi::dbi; // Opaque structure for a transaction handle. export type txn = ffi::txn;
// Opaque structure for navigating through a database. export type cursor = ffi::cursor;
use lmdb::ffi;
use types;
// Generic structure used for passing keys and data in and out
// of the database.
export type val = ffi::val;
// Convert a []u8 to a [[val]].
export fn u8s_val(s: []u8) val = {
let ss = *(&s: *types::slice);
return val {
mv_size = ss.length,
mv_data = ss.data,
};
};
// Convert a [[val]] to a []u8.
export fn val_u8s(s: *val) []u8 = {
return *(&types::slice {
data = s.mv_data,
length = s.mv_size,
capacity = s.mv_size,
}: *[]u8);
};