const std = @import("std");
const lmdb = @cImport(@cInclude("lmdb.h"));
-pub usingnamespace lmdb;
-
-pub fn Cursor(comptime K: type, comptime V: type) type {
- return struct {
- const Self = @This();
-
- pub const Flags = enum(c_uint) {
- First = lmdb.MDB_FIRST,
- FirstDup = lmdb.MDB_FIRST_DUP,
- GetBoth = lmdb.MDB_GET_BOTH,
- GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
- GetCurrent = lmdb.MDB_GET_CURRENT,
- GetMultiple = lmdb.MDB_GET_MULTIPLE,
- Last = lmdb.MDB_LAST,
- LastDup = lmdb.MDB_LAST_DUP,
- Next = lmdb.MDB_NEXT,
- NextDup = lmdb.MDB_NEXT_DUP,
- NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
- NextNodup = lmdb.MDB_NEXT_NODUP,
- Prev = lmdb.MDB_PREV,
- PrevDup = lmdb.MDB_PREV_DUP,
- PrevNodup = lmdb.MDB_PREV_NODUP,
- Set = lmdb.MDB_SET,
- SetKey = lmdb.MDB_SET_KEY,
- SetRange = lmdb.MDB_SET_RANGE,
- };
+pub const Cursor = struct {
+ const Self = @This();
+
+ pub const Flags = enum(c_uint) {
+ First = lmdb.MDB_FIRST,
+ FirstDup = lmdb.MDB_FIRST_DUP,
+ GetBoth = lmdb.MDB_GET_BOTH,
+ GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
+ GetCurrent = lmdb.MDB_GET_CURRENT,
+ GetMultiple = lmdb.MDB_GET_MULTIPLE,
+ Last = lmdb.MDB_LAST,
+ LastDup = lmdb.MDB_LAST_DUP,
+ Next = lmdb.MDB_NEXT,
+ NextDup = lmdb.MDB_NEXT_DUP,
+ NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
+ NextNodup = lmdb.MDB_NEXT_NODUP,
+ Prev = lmdb.MDB_PREV,
+ PrevDup = lmdb.MDB_PREV_DUP,
+ PrevNodup = lmdb.MDB_PREV_NODUP,
+ Set = lmdb.MDB_SET,
+ SetKey = lmdb.MDB_SET_KEY,
+ SetRange = lmdb.MDB_SET_RANGE,
+ };
- ptr: ?*lmdb.MDB_cursor = undefined,
+ ptr: ?*lmdb.MDB_cursor = undefined,
- pub fn close(self: *Self) void {
- _ = lmdb.mdb_cursor_close(self.ptr);
- }
+ pub fn close(self: Self) void {
+ lmdb.mdb_cursor_close(self.ptr);
+ }
- pub fn put(self: *Self, k: K, v: V) void {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(k)),
- .mv_data = @constCast(@ptrCast(&k)),
- };
- var val = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(v)),
- .mv_data = @constCast(@ptrCast(&v)),
- };
- switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
- 0 => {},
- else => |err| {
- std.debug.print("put err: {}\n", .{err});
- },
- }
+ pub fn put(self: Self, k: anytype, v: anytype) !void {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ var val = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(v)),
+ .mv_data = @constCast(@ptrCast(&v)),
+ };
+ switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
+ 0 => {},
+ else => |err| {
+ _ = err;
+ return error.CursorPut;
+ },
}
+ }
- pub fn get(self: *Self, k: *K, flags: Flags) ?V {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(K),
- .mv_data = @constCast(@ptrCast(k)),
- };
- var val: lmdb.MDB_val = undefined;
- return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
- 0 => {
- k.* = @as(*align(1) K, @ptrCast(key.mv_data)).*;
- return @as(?*align(1) V, @ptrCast(val.mv_data)).?.*;
- },
- lmdb.MDB_NOTFOUND => null,
- else => |err| {
- std.debug.print("get err: {}\n", .{err});
- return null;
- },
- };
- }
+ pub fn get(self: Self, k: anytype, comptime V: type, flags: Flags) !?V {
+ const k_ti = @typeInfo(@TypeOf(k));
+ const K = k_ti.pointer.child;
- pub fn del(self: *Self, k: K) void {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(k)),
- .mv_data = @constCast(@ptrCast(&k)),
- };
- switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
- 0 => {},
- else => |err| {
- std.debug.print("del err: {}\n", .{err});
- },
- }
- }
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(K),
+ .mv_data = @constCast(@ptrCast(k)),
+ };
+ var val: lmdb.MDB_val = undefined;
+ return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
+ 0 => {
+ const ptr = @as(*K, @constCast(k));
+ ptr.* = std.mem.bytesToValue(K, key.mv_data.?);
+ return std.mem.bytesToValue(V, val.mv_data.?);
+ },
+ lmdb.MDB_NOTFOUND => null,
+ else => |err| {
+ _ = err;
+ return error.CursorGet;
+ },
+ };
+ }
- pub fn has(self: *Dbi, k: K, flags: Flags) bool {
- return self.get(k, flags) != null;
+ pub fn del(self: Self, k: anytype) !void {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
+ 0 => {},
+ else => |err| {
+ _ = err;
+ return error.CursorDel;
+ },
}
- };
-}
+ }
-pub fn Dbi(comptime K: type, comptime V: type) type {
- return struct {
- const Self = @This();
+ pub fn has(self: Self, k: anytype, flags: Flags) !bool {
+ const k_ti = @typeInfo(@TypeOf(k));
+ const K = k_ti.pointer.child;
- ptr: lmdb.MDB_dbi = undefined,
- txn: *const Txn = undefined,
- env: *const Env = undefined,
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(K),
+ .mv_data = @constCast(@ptrCast(k)),
+ };
+ var val: lmdb.MDB_val = undefined;
+ return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
+ 0 => {
+ return true;
+ },
+ lmdb.MDB_NOTFOUND => {
+ return false;
+ },
+ else => {
+ return error.CursorHas;
+ },
+ };
+ }
+};
- pub fn close(self: Self) void {
+pub const Dbi = struct {
+ const Self = @This();
- // TODO: necessary?
- lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
- }
+ ptr: lmdb.MDB_dbi = undefined,
+ txn: Txn = undefined,
+ env: Env = undefined,
- pub fn cursor(self: Self) !Cursor(K, V) {
- var result = Cursor(K, V){};
+ pub fn close(self: Self) void {
+ // TODO: necessary?
+ lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
+ }
- return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
- 0 => result,
- else => error.CursorOpen,
- };
- }
+ pub fn cursor(self: Self) !Cursor {
+ var result = Cursor{};
- pub fn put(self: Self, k: K, v: V) void {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(k)),
- .mv_data = @constCast(@ptrCast(&k)),
- };
- var val = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(v)),
- .mv_data = @constCast(@ptrCast(&v)),
- };
- switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
- 0 => {},
- else => |err| {
- std.debug.print("put err: {}\n", .{err});
- },
- }
- }
+ return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
+ 0 => result,
+ else => error.DbiCursor,
+ };
+ }
- pub fn get(self: Self, k: K) ?V {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(k)),
- .mv_data = @constCast(@ptrCast(&k)),
- };
- var val: lmdb.MDB_val = undefined;
- return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
- 0 => @as(?*align(1) V, @ptrCast(val.mv_data)).?.*,
- else => |err| {
- std.debug.print("get err: {}\n", .{err});
- return null;
- },
- };
+ pub fn put(self: Self, k: anytype, v: anytype) !void {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ var val = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(v)),
+ .mv_data = @constCast(@ptrCast(&v)),
+ };
+ switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
+ 0 => {},
+ else => |err| {
+ _ = err;
+ return error.DbiPut;
+ },
}
+ }
- pub fn del(self: Self, k: K) void {
- var key = lmdb.MDB_val{
- .mv_size = @sizeOf(@TypeOf(k)),
- .mv_data = @constCast(@ptrCast(&k)),
- };
- switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
- 0 => {},
- else => |err| {
- std.debug.print("del err: {}\n", .{err});
- },
- }
- }
+ pub fn get(self: Self, k: anytype, comptime V: type) !V {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ var val: lmdb.MDB_val = undefined;
+ return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
+ 0 => {
+ return std.mem.bytesToValue(V, val.mv_data.?);
+ },
+ lmdb.MDB_NOTFOUND => error.NotFound,
+ else => |err| {
+ _ = err;
+ return error.DbiGet;
+ },
+ };
+ }
- pub fn has(self: Self, k: K) bool {
- return self.get(k) != null;
+ pub fn del(self: Self, k: anytype) !void {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
+ 0 => {},
+ else => |err| {
+ _ = err;
+ return error.DbiDel;
+ },
}
- };
-}
+ }
+
+ pub fn has(self: Self, k: anytype) !bool {
+ var key = lmdb.MDB_val{
+ .mv_size = @sizeOf(@TypeOf(k)),
+ .mv_data = @constCast(@ptrCast(&k)),
+ };
+ var val: lmdb.MDB_val = undefined;
+ return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
+ 0 => {
+ return true;
+ },
+ lmdb.MDB_NOTFOUND => {
+ return false;
+ },
+ else => |err| {
+ std.debug.print("[{}]\n", .{err});
+ return error.DbiHas;
+ },
+ };
+ }
+};
pub const Txn = struct {
ptr: ?*lmdb.MDB_txn = undefined,
- env: *const Env = undefined,
+ env: Env = undefined,
- pub fn dbi(self: *const Txn, name: [*c]const u8, comptime K: type, comptime V: type) !Dbi(K, V) {
- var result = Dbi(K, V){ .env = self.env, .txn = self };
+ pub fn dbi(self: Txn, name: ?[:0]const u8) !Dbi {
+ var result = Dbi{ .env = self.env, .txn = self };
// TODO: lmdb.MDB_INTEGERKEY?
- switch (lmdb.mdb_dbi_open(self.ptr, name, lmdb.MDB_CREATE, &result.ptr)) {
+ switch (lmdb.mdb_dbi_open(self.ptr, @ptrCast(name), lmdb.MDB_CREATE, &result.ptr)) {
0 => return result,
else => |err| {
- std.debug.print("dbi err: {}\n", .{err});
+ _ = err;
return error.DbiOpen;
},
}
}
- pub fn commit(self: Txn) void {
+ pub fn commit(self: Txn) !void {
switch (lmdb.mdb_txn_commit(self.ptr)) {
0 => {},
lmdb.MDB_MAP_FULL => {
- std.debug.print("resize\n", .{});
_ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
+ return error.TxnCommitMapFull;
},
else => |err| {
- std.debug.print("commit err: {}\n", .{err});
+ _ = err;
+ return error.TxnCommit;
},
}
}
pub const Env = struct {
ptr: ?*lmdb.MDB_env = undefined,
- pub fn open(name: [*c]const u8, size: lmdb.mdb_size_t) Env {
+ pub fn open(name: [:0]const u8, size: lmdb.mdb_size_t) !Env {
var result = Env{};
_ = lmdb.mdb_env_create(&result.ptr);
_ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
_ = lmdb.mdb_env_set_mapsize(result.ptr, size);
- _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP, 0o664);
+ const res = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP | lmdb.MDB_NOSUBDIR, 0o664);
// _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
- return result;
+ if (res != 0) {
+ return error.EnvOpen;
+ } else {
+ return result;
+ }
}
pub fn close(self: Env) void {
lmdb.mdb_env_close(self.ptr);
}
- pub fn txn(self: *const Env) !Txn {
+ pub fn txn(self: Env) !Txn {
var result = Txn{ .env = self };
switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
0 => return result,
else => |err| {
- std.debug.print("txn err: {}\n", .{err});
+ _ = err;
return error.TxnOpen;
},
}
}
- pub fn sync(self: *Env) void {
+ pub fn sync(self: Env) !void {
switch (lmdb.mdb_env_sync(self.ptr, 1)) {
0 => {},
else => |err| {
- std.debug.print("sync err: {}\n", .{err});
+ _ = err;
+ return error.EnvSync;
},
}
}
};
test "basic" {
- var env = Env.open("db", 1024 * 1024 * 1);
+ var env = try Env.open("db", 1024 * 1024 * 1);
+ // env.sync();
+ defer env.close();
var txn = try env.txn();
+ defer txn.commit() catch {};
const Value = struct {
i: i64 = 123,
s: [16]u8 = undefined,
};
- var dbi = try txn.dbi("abc", u64, Value);
+ var dbi = try txn.dbi("abc");
+
+ const idx: u64 = 1;
+
+ std.debug.print("has?: {}\n", .{try dbi.has(idx)});
- var val = dbi.get(1) orelse Value{ .i = 5 };
+ var val = dbi.get(idx, Value) catch Value{ .i = 5 };
std.debug.print("{}\n", .{val});
val.i += 1;
- dbi.put(1, val);
-
- txn.commit();
- dbi.close();
- env.sync();
- env.close();
+ try dbi.put(idx, val);
}
test "cursor" {
- var env = Env.open("db", 1024 * 1024 * 1);
+ var env = try Env.open("db", 1024 * 1024 * 1);
+ // env.sync();
+ defer env.close();
var txn = try env.txn();
+ defer txn.commit() catch {};
const Value = struct {
i: i64 = 123,
s: [16]u8 = undefined,
};
- var dbi = try txn.dbi("def", u64, Value);
+ var dbi = try txn.dbi("def");
for (0..10) |i| {
- dbi.put(i, Value{ .i = @intCast(i + 23) });
+ try dbi.put(@as(u64, i), Value{ .i = @intCast(i + 23) });
}
var cursor = try dbi.cursor();
+ defer cursor.close();
var key: u64 = undefined;
{
- const val = cursor.get(&key, .First);
+ const val = try cursor.get(&key, Value, .First);
std.debug.print("{}: {?}\n", .{ key, val });
}
- while (cursor.get(&key, .Next)) |val| {
- std.debug.print("{}: {?}\n", .{ key, val });
+ while (try cursor.get(&key, Value, .Next)) |val| {
+ std.debug.print("{}: {}\n", .{ key, val });
}
-
- cursor.close();
-
- txn.commit();
- dbi.close();
- env.sync();
- env.close();
}
// pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {