X-Git-Url: https://gitweb.ps.run/ziglmdb/blobdiff_plain/65ff097a0515b2c55064f36ddaaa000f4b9db1a7..87d8e6da9faf6c68255ee8668cb08319f2b273a2:/src/lmdb.zig diff --git a/src/lmdb.zig b/src/lmdb.zig index 3802ec6..637bd26 100644 --- a/src/lmdb.zig +++ b/src/lmdb.zig @@ -3,196 +3,232 @@ 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.* = std.mem.bytesToValue(K, key.mv_data.?); - return std.mem.bytesToValue(V, val.mv_data.?); - //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 => { - return std.mem.bytesToValue(V, val.mv_data.?); - //@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; }, } } @@ -205,102 +241,106 @@ pub const Txn = struct { 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, 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; - var val = dbi.get(1) orelse Value{ .i = 5 }; + std.debug.print("has?: {}\n", .{try dbi.has(idx)}); + + 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| { + 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 {