From: patrick-scho Date: Wed, 13 Nov 2024 21:02:51 +0000 (+0100) Subject: update X-Git-Url: https://gitweb.ps.run/ziglmdb/commitdiff_plain/b093b3271004173309ae5f7c67f1cdafc2cd4b82 update --- diff --git a/src/lmdb.zig b/src/lmdb.zig new file mode 100644 index 0000000..8cc91f4 --- /dev/null +++ b/src/lmdb.zig @@ -0,0 +1,360 @@ +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, + }; + + ptr: ?*lmdb.MDB_cursor = undefined, + + 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 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 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}); + }, + } + } + + pub fn has(self: *Dbi, k: K, flags: Flags) bool { + return self.get(k, flags) != null; + } + }; +} + +pub fn Dbi(comptime K: type, comptime V: type) type { + return struct { + const Self = @This(); + + ptr: lmdb.MDB_dbi = undefined, + txn: *const Txn = undefined, + env: *const Env = undefined, + + pub fn close(self: Self) void { + + // TODO: necessary? + lmdb.mdb_dbi_close(self.env.ptr, self.ptr); + } + + pub fn cursor(self: Self) !Cursor(K, V) { + var result = Cursor(K, V){}; + + return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) { + 0 => result, + else => error.CursorOpen, + }; + } + + 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}); + }, + } + } + + 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 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 has(self: Self, k: K) bool { + return self.get(k) != null; + } + }; +} + +pub const Txn = struct { + ptr: ?*lmdb.MDB_txn = undefined, + env: *const 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 }; + // TODO: lmdb.MDB_INTEGERKEY? + switch (lmdb.mdb_dbi_open(self.ptr, name, lmdb.MDB_CREATE, &result.ptr)) { + 0 => return result, + else => |err| { + std.debug.print("dbi err: {}\n", .{err}); + return error.DbiOpen; + }, + } + } + + 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); + }, + else => |err| { + std.debug.print("commit err: {}\n", .{err}); + }, + } + } + + pub fn abort(self: Txn) void { + lmdb.mdb_txn_abort(self.ptr); + } +}; + +pub const Env = struct { + ptr: ?*lmdb.MDB_env = undefined, + + pub fn open(name: [*c]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); + // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664); + + return result; + } + + pub fn close(self: Env) void { + lmdb.mdb_env_close(self.ptr); + } + + pub fn txn(self: *const 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}); + return error.TxnOpen; + }, + } + } + + pub fn sync(self: *Env) void { + switch (lmdb.mdb_env_sync(self.ptr, 1)) { + 0 => {}, + else => |err| { + std.debug.print("sync err: {}\n", .{err}); + }, + } + } +}; + +test "basic" { + var env = Env.open("db", 1024 * 1024 * 1); + + var txn = try env.txn(); + + const Value = struct { + i: i64 = 123, + s: [16]u8 = undefined, + }; + + var dbi = try txn.dbi("abc", u64, Value); + + var val = dbi.get(1) orelse Value{ .i = 5 }; + std.debug.print("{}\n", .{val}); + + val.i += 1; + + dbi.put(1, val); + + txn.commit(); + dbi.close(); + env.sync(); + env.close(); +} + +test "cursor" { + var env = Env.open("db", 1024 * 1024 * 1); + + var txn = try env.txn(); + + const Value = struct { + i: i64 = 123, + s: [16]u8 = undefined, + }; + + var dbi = try txn.dbi("def", u64, Value); + + for (0..10) |i| { + dbi.put(i, Value{ .i = @intCast(i + 23) }); + } + + var cursor = try dbi.cursor(); + + var key: u64 = undefined; + { + const val = cursor.get(&key, .First); + std.debug.print("{}: {?}\n", .{ key, val }); + } + + while (cursor.get(&key, .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 { +// 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(txn, dbi, &key, &val)) { +// 0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*, +// else => |err| { +// std.debug.print("get err: {}\n", .{err}); +// return null; +// }, +// }; +// } + +// pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, 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(txn, dbi, &key, &val, 0)) { +// 0 => {}, +// else => |err| { +// std.debug.print("put err: {}\n", .{err}); +// }, +// } +// } + +// pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void { +// var key = lmdb.MDB_val{ +// .mv_size = @sizeOf(@TypeOf(k)), +// .mv_data = @constCast(@ptrCast(&k)), +// }; +// switch (lmdb.mdb_del(txn, dbi, &key, null)) { +// 0 => {}, +// else => |err| { +// std.debug.print("del err: {}\n", .{err}); +// }, +// } +// } + +// pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, 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(txn, dbi, &key, &val)) { +// 0 => true, +// lmdb.MDB_NOTFOUND => false, +// else => |err| { +// std.debug.print("has err: {}\n", .{err}); +// return false; +// }, +// }; +// } diff --git a/src/main.zig b/src/main.zig deleted file mode 100644 index a9ad1ba..0000000 --- a/src/main.zig +++ /dev/null @@ -1,148 +0,0 @@ -const std = @import("std"); -const lmdb = @cImport(@cInclude("lmdb.h")); - -const print = std.debug.print; - -fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T { - 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(txn, dbi, &key, &val)) { - 0 => @as(*T, @ptrFromInt(@intFromPtr(val.mv_data))).*, - else => |err| { - _ = err; - // print("get err: {}\n", .{err}); - return null; - }, - }; -} - -fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, 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(txn, dbi, &key, &val, 0)) { - 0 => {}, - else => |err| { - print("put err: {}\n", .{err}); - }, - } -} - -pub fn main() void { - var env: ?*lmdb.MDB_env = undefined; - _ = lmdb.mdb_env_create(&env); - _ = lmdb.mdb_env_set_maxdbs(env, 10); - _ = lmdb.mdb_env_set_mapsize(env, 1024 * 1024 * 120); - _ = lmdb.mdb_env_open(env, "./db1", lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664); - defer lmdb.mdb_env_close(env); - - for (0..1000000) |i| { - var txn: ?*lmdb.MDB_txn = undefined; - switch (lmdb.mdb_txn_begin(env, null, 0, &txn)) { - 0 => {}, - else => |err| { - print("txn err: {}\n", .{err}); - }, - } - - var db: lmdb.MDB_dbi = undefined; - _ = lmdb.mdb_dbi_open(txn, "subdb2", lmdb.MDB_CREATE | lmdb.MDB_INTEGERKEY, &db); - if (i == 0) { - var db_stat: lmdb.MDB_stat = undefined; - _ = lmdb.mdb_stat(txn, db, &db_stat); - // print("{}\n", .{db_stat}); - } - defer lmdb.mdb_dbi_close(env, db); - - const Val = struct { - a: u64, - b: i64, - c: [16]u8, - }; - - var new_val = Val{ - .a = 123, - .b = -123, - .c = undefined, - }; - std.mem.copyForwards(u8, &new_val.c, "a c efghabcdefgh"); - - const key: u64 = i + 1000; - if (get(txn, db, key, Val)) |val| { - if (i % 100000 == 0) { - print("{}: {}\n", .{ i, val }); - } - new_val = val; - new_val.a += 1; - new_val.b -= 1; - std.mem.copyForwards(u8, &new_val.c, "a c efghabcdefgh"); - } else { - if (i % 100000 == 0) { - print("not found\n", .{}); - } - } - - put(txn, db, key, new_val); - - switch (lmdb.mdb_txn_commit(txn)) { - 0 => {}, - lmdb.MDB_MAP_FULL => { - print("resize\n", .{}); - _ = lmdb.mdb_env_set_mapsize(env, 0); - }, - else => |err| { - print("commit err: {}\n", .{err}); - }, - } - } - - switch (lmdb.mdb_env_sync(env, 1)) { - 0 => {}, - else => |err| { - print("sync err: {}\n", .{err}); - }, - } - - // var env_info: lmdb.MDB_envinfo = undefined; - // _ = lmdb.mdb_env_info(env, &env_info); - - // var env_stat: lmdb.MDB_stat = undefined; - // _ = lmdb.mdb_env_stat(env, &env_stat); - - // print("{}\n", .{env_info}); - // print("{}\n", .{env_stat}); - - print("done!\n", .{}); -} - -test "hash" { - const pw = "affeaffe"; - - var hash_buffer: [128]u8 = undefined; - - var buffer: [1024 * 1024]u8 = undefined; - var alloc = std.heap.FixedBufferAllocator.init(&buffer); - - const result = try std.crypto.pwhash.argon2.strHash(pw, .{ - .allocator = alloc.allocator(), - .params = std.crypto.pwhash.argon2.Params.fromLimits(1000, 1024 * 10), - }, &hash_buffer); - - print("{s}\n", .{result}); - - if (std.crypto.pwhash.argon2.strVerify(result, "affeaffe", .{ - .allocator = alloc.allocator(), - })) { - print("verified\n", .{}); - } else |err| { - print("not verified: {}\n", .{err}); - } -}