From d0e9caa81fae915259cfdfa962daa150492f6f62 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Fri, 6 May 2022 22:06:13 +0800 Subject: [PATCH 01/10] Use anyopaque instead of c_void --- lmdb.zig | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lmdb.zig b/lmdb.zig index a60c4bc..c6c15e5 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -388,7 +388,7 @@ pub const Transaction = packed struct { try call(c.mdb_set_dupsort, .{ self.inner, db.inner, S.cmp }); } pub inline fn get(self: Self, db: Database, key: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_get, .{ self.inner, db.inner, k, &v }); @@ -414,13 +414,13 @@ pub const Transaction = packed struct { return self.put(db, key, bytes, flags); } pub inline fn put(self: Self, db: Database, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; try call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }); } pub inline fn getOrPut(self: Self, db: Database, key: []const u8, val: []const u8) !?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; call(c.mdb_put, .{ self.inner, db.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], @@ -446,7 +446,7 @@ pub const Transaction = packed struct { found_existing: []const u8, }; pub inline fn reserve(self: Self, db: Database, key: []const u8, val_len: usize, flags: ReserveFlags) !ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }) catch |err| switch (err) { @@ -461,12 +461,12 @@ pub const Transaction = packed struct { }; } pub inline fn del(self: Self, db: Database, key: []const u8, op: union(enum) { key: void, item: []const u8 }) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v: ?*c.MDB_val = switch (op) { .key => null, .item => |item| &c.MDB_val{ .mv_size = item.len, - .mv_data = @intToPtr(?*c_void, @ptrToInt(item.ptr)), + .mv_data = @intToPtr(?*anyopaque, @ptrToInt(item.ptr)), }, }; try call(c.mdb_del, .{ self.inner, db.inner, k, v }); @@ -484,7 +484,7 @@ pub const Transaction = packed struct { try call(c.mdb_txn_renew, .{self.inner}); } pub inline fn reset(self: Self) !void { - try call(c.mdb_txn_reset, .{self.inner}); + call(c.mdb_txn_reset, .{self.inner}); } }; @@ -530,14 +530,14 @@ pub const Cursor = packed struct { } pub fn updateInPlace(self: Self, current_key: []const u8, new_val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(current_key.ptr)) }; - var v = &c.MDB_val{ .mv_size = new_val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(new_val.ptr)) }; + var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(current_key.ptr)) }; + var v = &c.MDB_val{ .mv_size = new_val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(new_val.ptr)) }; try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT }); } /// May not be used with databases supporting duplicate keys. pub fn reserveInPlace(self: Self, current_key: []const u8, new_val_len: usize) ![]u8 { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(current_key.ptr)) }; + var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(current_key.ptr)) }; var v = &c.MDB_val{ .mv_size = new_val_len, .mv_data = null }; try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT | c.MDB_RESERVE }); return @ptrCast([*]u8, v.mv_data)[0..v.mv_size]; @@ -562,16 +562,16 @@ pub const Cursor = packed struct { return self.put(key, bytes, flags); } pub inline fn put(self: Self, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }); } pub inline fn putBatch(self: Self, key: []const u8, batch: anytype, flags: PutFlags) !usize { comptime assert(meta.trait.isIndexable(@TypeOf(batch))); - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v = [_]c.MDB_val{ - .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = @intToPtr(?*c_void, @ptrToInt(&batch[0])) }, + .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = @intToPtr(?*anyopaque, @ptrToInt(&batch[0])) }, .{ .mv_size = mem.len(batch), .mv_data = undefined }, }; try call(c.mdb_cursor_put, .{ self.inner, k, &v, @intCast(c_uint, c.MDB_MULTIPLE) | flags.into() }); @@ -579,8 +579,8 @@ pub const Cursor = packed struct { return @intCast(usize, v[1].mv_size); } pub inline fn getOrPut(self: Self, key: []const u8, val: []const u8) !?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], @@ -606,7 +606,7 @@ pub const Cursor = packed struct { found_existing: []const u8, }; pub inline fn reserve(self: Self, key: []const u8, val_len: usize, flags: ReserveFlags) !ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }) catch |err| switch (err) { @@ -672,24 +672,24 @@ pub const Cursor = packed struct { }; } pub inline fn seekToItem(self: Self, key: []const u8, val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_get, .{ self.inner, k, v, .MDB_GET_BOTH }); } pub inline fn seekFromItem(self: Self, key: []const u8, val: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_get, .{ self.inner, k, v, c.MDB_GET_BOTH_RANGE }); return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; } pub inline fn seekTo(self: Self, key: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_KEY }); return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; } pub inline fn seekFrom(self: Self, key: []const u8) !Entry { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*anyopaque, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_RANGE }); return Entry{ From 13ccd3a40dae5d9fa4e7d3e3a8559d56b42b7c1d Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 5 Dec 2022 01:28:11 +0000 Subject: [PATCH 02/10] Fix code and let tests run --- .gitignore | 5 ++- .gitmodules | 3 ++ build.zig | 5 +-- lmdb | 1 + lmdb.zig | 90 ++++++++++++++++++++++++++++++++++++----------------- zig.mod | 2 +- 6 files changed, 73 insertions(+), 33 deletions(-) create mode 100644 .gitmodules create mode 160000 lmdb diff --git a/.gitignore b/.gitignore index f2d1c98..08260ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ zig-cache/ -deps.zig \ No newline at end of file +zig-out/ +deps.zig +.zigmod/ +zigmod.lock diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f17bff6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lmdb"] + path = lmdb + url = https://github.com/LMDB/lmdb diff --git a/build.zig b/build.zig index 3498edb..de8722f 100644 --- a/build.zig +++ b/build.zig @@ -9,11 +9,12 @@ pub fn build(b: *Builder) void { const mode = b.standardReleaseOptions(); - const tests = b.addTest("lmdb.zig"); + const tests = b.addTestExe("test", "lmdb.zig"); tests.setTarget(target); tests.setBuildMode(mode); + tests.install(); deps.addAllTo(tests); const test_step = b.step("test", "Run libary tests"); - test_step.dependOn(&tests.step); + test_step.dependOn(&tests.run().step); } diff --git a/lmdb b/lmdb new file mode 160000 index 0000000..3947014 --- /dev/null +++ b/lmdb @@ -0,0 +1 @@ +Subproject commit 3947014aed7ffe39a79991fa7fb5b234da47ad1a diff --git a/lmdb.zig b/lmdb.zig index a60c4bc..3a750e1 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -388,7 +388,7 @@ pub const Transaction = packed struct { try call(c.mdb_set_dupsort, .{ self.inner, db.inner, S.cmp }); } pub inline fn get(self: Self, db: Database, key: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_get, .{ self.inner, db.inner, k, &v }); @@ -414,13 +414,13 @@ pub const Transaction = packed struct { return self.put(db, key, bytes, flags); } pub inline fn put(self: Self, db: Database, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; try call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }); } - pub inline fn getOrPut(self: Self, db: Database, key: []const u8, val: []const u8) !?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + pub inline fn getOrPut(self: Self, db: Database, key: []const u8, val: []const u8) MDB_errorset!?[]const u8 { + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; call(c.mdb_put, .{ self.inner, db.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], @@ -445,8 +445,8 @@ pub const Transaction = packed struct { successful: []u8, found_existing: []const u8, }; - pub inline fn reserve(self: Self, db: Database, key: []const u8, val_len: usize, flags: ReserveFlags) !ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + pub inline fn reserve(self: Self, db: Database, key: []const u8, val_len: usize, flags: ReserveFlags) MDB_errorset!ReserveResult { + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }) catch |err| switch (err) { @@ -461,12 +461,12 @@ pub const Transaction = packed struct { }; } pub inline fn del(self: Self, db: Database, key: []const u8, op: union(enum) { key: void, item: []const u8 }) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v: ?*c.MDB_val = switch (op) { .key => null, .item => |item| &c.MDB_val{ .mv_size = item.len, - .mv_data = @intToPtr(?*c_void, @ptrToInt(item.ptr)), + .mv_data = @intToPtr(?*void, @ptrToInt(item.ptr)), }, }; try call(c.mdb_del, .{ self.inner, db.inner, k, v }); @@ -530,14 +530,14 @@ pub const Cursor = packed struct { } pub fn updateInPlace(self: Self, current_key: []const u8, new_val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(current_key.ptr)) }; - var v = &c.MDB_val{ .mv_size = new_val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(new_val.ptr)) }; + var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*void, @ptrToInt(current_key.ptr)) }; + var v = &c.MDB_val{ .mv_size = new_val.len, .mv_data = @intToPtr(?*void, @ptrToInt(new_val.ptr)) }; try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT }); } /// May not be used with databases supporting duplicate keys. pub fn reserveInPlace(self: Self, current_key: []const u8, new_val_len: usize) ![]u8 { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(current_key.ptr)) }; + var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*void, @ptrToInt(current_key.ptr)) }; var v = &c.MDB_val{ .mv_size = new_val_len, .mv_data = null }; try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT | c.MDB_RESERVE }); return @ptrCast([*]u8, v.mv_data)[0..v.mv_size]; @@ -562,16 +562,16 @@ pub const Cursor = packed struct { return self.put(key, bytes, flags); } pub inline fn put(self: Self, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }); } pub inline fn putBatch(self: Self, key: []const u8, batch: anytype, flags: PutFlags) !usize { comptime assert(meta.trait.isIndexable(@TypeOf(batch))); - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v = [_]c.MDB_val{ - .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = @intToPtr(?*c_void, @ptrToInt(&batch[0])) }, + .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = @intToPtr(?*void, @ptrToInt(&batch[0])) }, .{ .mv_size = mem.len(batch), .mv_data = undefined }, }; try call(c.mdb_cursor_put, .{ self.inner, k, &v, @intCast(c_uint, c.MDB_MULTIPLE) | flags.into() }); @@ -579,8 +579,8 @@ pub const Cursor = packed struct { return @intCast(usize, v[1].mv_size); } pub inline fn getOrPut(self: Self, key: []const u8, val: []const u8) !?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], @@ -606,7 +606,7 @@ pub const Cursor = packed struct { found_existing: []const u8, }; pub inline fn reserve(self: Self, key: []const u8, val_len: usize, flags: ReserveFlags) !ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }) catch |err| switch (err) { @@ -620,7 +620,7 @@ pub const Cursor = packed struct { .successful = @ptrCast([*]u8, v.mv_data)[0..v.mv_size], }; } - pub inline fn del(self: Self, op: enum(c_uint) { key = c.MDB_NODUPDATA, item = 0 }) !void { + pub inline fn del(self: Self, op: enum(c_uint) { key = c.MDB_NODUPDATA, item = 0 }) MDB_errorset!void { call(c.mdb_cursor_del, .{ self.inner, @enumToInt(op) }) catch |err| switch (err) { error.InvalidParameter => return error.NotFound, else => return err, @@ -659,7 +659,7 @@ pub const Cursor = packed struct { next = c.MDB_NEXT_MULTIPLE, prev = c.MDB_PREV_MULTIPLE, }; - pub inline fn getPage(self: Self, comptime T: type, pos: PagePosition) !?Page(T) { + pub inline fn getPage(self: Self, comptime T: type, pos: PagePosition) MDB_errorset!?Page(T) { var k: c.MDB_val = undefined; var v: c.MDB_val = undefined; call(c.mdb_cursor_get, .{ self.inner, &k, &v, @enumToInt(pos) }) catch |err| switch (err) { @@ -672,24 +672,25 @@ pub const Cursor = packed struct { }; } pub inline fn seekToItem(self: Self, key: []const u8, val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_get, .{ self.inner, k, v, .MDB_GET_BOTH }); } pub inline fn seekFromItem(self: Self, key: []const u8, val: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(val.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; try call(c.mdb_cursor_get, .{ self.inner, k, v, c.MDB_GET_BOTH_RANGE }); return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; } pub inline fn seekTo(self: Self, key: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + @setEvalBranchQuota(10000); + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_KEY }); return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; } pub inline fn seekFrom(self: Self, key: []const u8) !Entry { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*c_void, @ptrToInt(key.ptr)) }; + var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; var v: c.MDB_val = undefined; try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_RANGE }); return Entry{ @@ -741,8 +742,39 @@ pub const Cursor = packed struct { } }; +pub const MDB_errorset = error { + AlreadyExists, + NotFound, + PageNotFound, + PageCorrupted, + Panic, + VersionMismatch, + FileNotDatabase, + MapSizeLimitReached, + MaxNumDatabasesLimitReached, + MaxNumReadersLimitReached, + TooManyEnvironmentsOpen, + TransactionTooBig, + CursorStackLimitReached, + OutOfPageMemory, + DatabaseExceedsMapSizeLimit, + IncompatibleOperation, + InvalidReaderLocktableSlotReuse, + TransactionNotAborted, + UnsupportedSize, + BadDatabaseHandle, + NoSuchFileOrDirectory, + InputOutputError, + OutOfMemory, + ReadOnly, + DeviceOrResourceBusy, + InvalidParameter, + NoSpaceLeftOnDevice, + FileAlreadyExists, +}; + inline fn ResultOf(comptime function: anytype) type { - return if (@typeInfo(@TypeOf(function)).Fn.return_type == c_int) anyerror!void else void; + return if (@typeInfo(@TypeOf(function)).Fn.return_type == c_int) MDB_errorset!void else void; } inline fn call(comptime function: anytype, args: anytype) ResultOf(function) { diff --git a/zig.mod b/zig.mod index 017f85c..5c5a02c 100644 --- a/zig.mod +++ b/zig.mod @@ -3,7 +3,7 @@ name: lmdb main: lmdb.zig dependencies: - type: git - path: https://git.openldap.org/openldap/openldap + path: lmdb version: tag-LMDB_0.9.29 c_include_dirs: - libraries/liblmdb From 8c2970775db50ec33b9eb665bda28d3530380e84 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:15:05 +0000 Subject: [PATCH 03/10] Update lmdb & build.zig --- build.zig | 37 ++++++++++++++++++++++++++----------- lmdb | 2 +- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/build.zig b/build.zig index de8722f..1cc2baf 100644 --- a/build.zig +++ b/build.zig @@ -1,20 +1,35 @@ const std = @import("std"); -const deps = @import("deps.zig"); -const Builder = std.build.Builder; - -pub fn build(b: *Builder) void { +pub fn build(b: *std.Build) void { var target = b.standardTargetOptions(.{}); if (target.isGnuLibC()) target.abi = .musl; - const mode = b.standardReleaseOptions(); + const optimize = b.standardOptimizeOption(.{}); + + const lib = b.addStaticLibrary(.{ + .name = "lmdb", + .target = target, + .optimize = optimize, + }); + lib.linkLibC(); + lib.addCSourceFiles(&.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, &.{}); + // .c_source_flags = &.{ "-fno-sanitize=undefined" }, + + const pkg = b.addModule("lmdb", .{ + .source_file = .{ .path = "lmdb.zig" }, + }); + + const tests = b.addTest(.{ + .name = "test", + .root_source_file = pkg.source_file, + .target = target, + .optimize = optimize, + }); + tests.addIncludePath("lmdb/libraries/liblmdb"); + tests.linkLibrary(lib); - const tests = b.addTestExe("test", "lmdb.zig"); - tests.setTarget(target); - tests.setBuildMode(mode); - tests.install(); - deps.addAllTo(tests); + b.installArtifact(tests); const test_step = b.step("test", "Run libary tests"); - test_step.dependOn(&tests.run().step); + test_step.dependOn(&b.addRunArtifact(tests).step); } diff --git a/lmdb b/lmdb index 3947014..c7b3cc4 160000 --- a/lmdb +++ b/lmdb @@ -1 +1 @@ -Subproject commit 3947014aed7ffe39a79991fa7fb5b234da47ad1a +Subproject commit c7b3cc4df6dfe8f0772fb509bdc74777667caa43 From 1490d003e4ce25d81edcbfff744e2a6c2943351f Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:53:42 +0000 Subject: [PATCH 04/10] Update lmdb.zig to Zig 0.11 --- build.zig | 3 +- lmdb.zig | 222 +++++++++++++++++++++++++++--------------------------- 2 files changed, 110 insertions(+), 115 deletions(-) diff --git a/build.zig b/build.zig index 1cc2baf..e220f26 100644 --- a/build.zig +++ b/build.zig @@ -12,8 +12,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); lib.linkLibC(); - lib.addCSourceFiles(&.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, &.{}); - // .c_source_flags = &.{ "-fno-sanitize=undefined" }, + lib.addCSourceFiles(&.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, &.{"-fno-sanitize=undefined"}); const pkg = b.addModule("lmdb", .{ .source_file = .{ .path = "lmdb.zig" }, diff --git a/lmdb.zig b/lmdb.zig index 3a750e1..3d35475 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -78,10 +78,10 @@ pub const Environment = packed struct { try call(c.mdb_env_set_mapsize, .{ inner, map_size }); } if (flags.max_num_readers) |max_num_readers| { - try call(c.mdb_env_set_maxreaders, .{ inner, @intCast(c_uint, max_num_readers) }); + try call(c.mdb_env_set_maxreaders, .{ inner, @as(c_uint, @intCast(max_num_readers)) }); } if (flags.max_num_dbs) |max_num_dbs| { - try call(c.mdb_env_set_maxdbs, .{ inner, @intCast(c_uint, max_num_dbs) }); + try call(c.mdb_env_set_maxdbs, .{ inner, @as(c_uint, @intCast(max_num_dbs)) }); } if (!mem.endsWith(u8, env_path, &[_]u8{0})) { @@ -127,14 +127,14 @@ pub const Environment = packed struct { try call(c.mdb_env_copyfd2, .{ self.inner, fd_handle, flags.into() }); } pub inline fn getMaxKeySize(self: Self) usize { - return @intCast(usize, c.mdb_env_get_maxkeysize(self.inner)); + return @as(usize, @intCast(c.mdb_env_get_maxkeysize(self.inner))); } pub inline fn getMaxNumReaders(self: Self) usize { var max_num_readers: c_uint = 0; call(c.mdb_env_get_maxreaders, .{ self.inner, &max_num_readers }) catch |err| { panic("Environment.getMaxNumReaders(): {}", .{err}); }; - return @intCast(usize, max_num_readers); + return @as(usize, @intCast(max_num_readers)); } pub inline fn setMapSize(self: Self, map_size: ?usize) !void { try call(c.mdb_env_set_mapsize, .{ self.inner, if (map_size) |size| size else 0 }); @@ -217,11 +217,11 @@ pub const Environment = packed struct { } pub inline fn path(self: Self) []const u8 { var env_path: [:0]const u8 = undefined; - call(c.mdb_env_get_path, .{ self.inner, @ptrCast([*c][*c]const u8, &env_path.ptr) }) catch |err| { + call(c.mdb_env_get_path, .{ self.inner, @as([*c][*c]const u8, @ptrCast(&env_path.ptr)) }) catch |err| { panic("Environment.path(): {}", .{err}); }; env_path.len = mem.indexOfSentinel(u8, 0, env_path.ptr); - return mem.span(env_path); + return env_path; } pub inline fn stat(self: Self) Statistics { var inner: c.MDB_stat = undefined; @@ -229,12 +229,12 @@ pub const Environment = packed struct { panic("Environment.stat(): {}", .{err}); }; return Statistics{ - .page_size = @intCast(usize, inner.ms_psize), - .tree_height = @intCast(usize, inner.ms_depth), - .num_branch_pages = @intCast(usize, inner.ms_branch_pages), - .num_leaf_pages = @intCast(usize, inner.ms_leaf_pages), - .num_overflow_pages = @intCast(usize, inner.ms_overflow_pages), - .num_entries = @intCast(usize, inner.ms_entries), + .page_size = @as(usize, @intCast(inner.ms_psize)), + .tree_height = @as(usize, @intCast(inner.ms_depth)), + .num_branch_pages = @as(usize, @intCast(inner.ms_branch_pages)), + .num_leaf_pages = @as(usize, @intCast(inner.ms_leaf_pages)), + .num_overflow_pages = @as(usize, @intCast(inner.ms_overflow_pages)), + .num_entries = @as(usize, @intCast(inner.ms_entries)), }; } pub inline fn fd(self: Self) os.fd_t { @@ -250,12 +250,12 @@ pub const Environment = packed struct { panic("Environment.info(): {}", .{err}); }; return Info{ - .map_address = @ptrCast(?[*]u8, inner.me_mapaddr), - .map_size = @intCast(usize, inner.me_mapsize), - .last_page_num = @intCast(usize, inner.me_last_pgno), - .last_tx_id = @intCast(usize, inner.me_last_txnid), - .max_num_reader_slots = @intCast(usize, inner.me_maxreaders), - .num_used_reader_slots = @intCast(usize, inner.me_numreaders), + .map_address = @as(?[*]u8, @ptrCast(inner.me_mapaddr)), + .map_size = @as(usize, @intCast(inner.me_mapsize)), + .last_page_num = @as(usize, @intCast(inner.me_last_pgno)), + .last_tx_id = @as(usize, @intCast(inner.me_last_txnid)), + .max_num_reader_slots = @as(usize, @intCast(inner.me_maxreaders)), + .num_used_reader_slots = @as(usize, @intCast(inner.me_numreaders)), }; } pub inline fn begin(self: Self, flags: Transaction.Flags) !Transaction { @@ -270,7 +270,7 @@ pub const Environment = packed struct { pub inline fn purge(self: Self) !usize { var count: c_int = undefined; try call(c.mdb_reader_check, .{ self.inner, &count }); - return @intCast(usize, count); + return @as(usize, @intCast(count)); } }; @@ -342,7 +342,7 @@ pub const Transaction = packed struct { inner: ?*c.MDB_txn, pub inline fn id(self: Self) usize { - return @intCast(usize, c.mdb_txn_id(self.inner)); + return @as(usize, @intCast(c.mdb_txn_id(self.inner))); } pub inline fn open(self: Self, flags: Database.OpenFlags) !Database { var inner: c.MDB_dbi = 0; @@ -362,8 +362,8 @@ pub const Transaction = packed struct { pub inline fn setKeyOrder(self: Self, db: Database, comptime order: fn (a: []const u8, b: []const u8) math.Order) !void { const S = struct { fn cmp(a: ?*const c.MDB_val, b: ?*const c.MDB_val) callconv(.C) c_int { - const slice_a = @ptrCast([*]const u8, a.?.mv_data)[0..a.?.mv_size]; - const slice_b = @ptrCast([*]const u8, b.?.mv_data)[0..b.?.mv_size]; + const slice_a = @as([*]const u8, @ptrCast(a.?.mv_data))[0..a.?.mv_size]; + const slice_b = @as([*]const u8, @ptrCast(b.?.mv_data))[0..b.?.mv_size]; return switch (order(slice_a, slice_b)) { .eq => 0, .lt => -1, @@ -376,8 +376,8 @@ pub const Transaction = packed struct { pub inline fn setItemOrder(self: Self, db: Database, comptime order: fn (a: []const u8, b: []const u8) math.Order) !void { const S = struct { fn cmp(a: ?*const c.MDB_val, b: ?*const c.MDB_val) callconv(.C) c_int { - const slice_a = @ptrCast([*]const u8, a.?.mv_data)[0..a.?.mv_size]; - const slice_b = @ptrCast([*]const u8, b.?.mv_data)[0..b.?.mv_size]; + const slice_a = @as([*]const u8, @ptrCast(a.?.mv_data))[0..a.?.mv_size]; + const slice_b = @as([*]const u8, @ptrCast(b.?.mv_data))[0..b.?.mv_size]; return switch (order(slice_a, slice_b)) { .eq => 0, .lt => -1, @@ -388,11 +388,11 @@ pub const Transaction = packed struct { try call(c.mdb_set_dupsort, .{ self.inner, db.inner, S.cmp }); } pub inline fn get(self: Self, db: Database, key: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; var v: c.MDB_val = undefined; - try call(c.mdb_get, .{ self.inner, db.inner, k, &v }); + try call(c.mdb_get, .{ self.inner, db.inner, &k, &v }); - return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; + return @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size]; } pub const PutFlags = packed struct { @@ -409,21 +409,17 @@ pub const Transaction = packed struct { return flags; } }; - pub inline fn putItem(self: Self, db: Database, key: []const u8, val: anytype, flags: PutFlags) !void { - const bytes = if (meta.trait.isIndexable(@TypeOf(val))) mem.span(val) else mem.asBytes(&val); - return self.put(db, key, bytes, flags); - } pub inline fn put(self: Self, db: Database, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; - try call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }); + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; + try call(c.mdb_put, .{ self.inner, db.inner, &k, &v, flags.into() }); } pub inline fn getOrPut(self: Self, db: Database, key: []const u8, val: []const u8) MDB_errorset!?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; - call(c.mdb_put, .{ self.inner, db.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { - error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], + call(c.mdb_put, .{ self.inner, db.inner, &k, &v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { + error.AlreadyExists => return @as([*]u8, @ptrCast(v.mv_data))[0..v.mv_size], else => return err, }; @@ -446,33 +442,33 @@ pub const Transaction = packed struct { found_existing: []const u8, }; pub inline fn reserve(self: Self, db: Database, key: []const u8, val_len: usize, flags: ReserveFlags) MDB_errorset!ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val_len, .mv_data = null }; - call(c.mdb_put, .{ self.inner, db.inner, k, v, flags.into() }) catch |err| switch (err) { + call(c.mdb_put, .{ self.inner, db.inner, &k, &v, flags.into() }) catch |err| switch (err) { error.AlreadyExists => return ReserveResult{ - .found_existing = @ptrCast([*]const u8, v.mv_data)[0..v.mv_size], + .found_existing = @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size], }, else => return err, }; return ReserveResult{ - .successful = @ptrCast([*]u8, v.mv_data)[0..v.mv_size], + .successful = @as([*]u8, @ptrCast(v.mv_data))[0..v.mv_size], }; } pub inline fn del(self: Self, db: Database, key: []const u8, op: union(enum) { key: void, item: []const u8 }) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; var v: ?*c.MDB_val = switch (op) { .key => null, .item => |item| &c.MDB_val{ .mv_size = item.len, - .mv_data = @intToPtr(?*void, @ptrToInt(item.ptr)), + .mv_data = @ptrFromInt(@intFromPtr(item.ptr)), }, }; - try call(c.mdb_del, .{ self.inner, db.inner, k, v }); + try call(c.mdb_del, .{ self.inner, db.inner, &k, @as([*c]c.MDB_val, @constCast(v)) }); } pub inline fn drop(self: Self, db: Database, method: enum(c_int) { empty = 0, delete = 1 }) !void { - try call(c.mdb_drop, .{ self.inner, db.inner, @enumToInt(method) }); + try call(c.mdb_drop, .{ self.inner, db.inner, @intFromEnum(method) }); } pub inline fn deinit(self: Self) void { call(c.mdb_txn_abort, .{self.inner}); @@ -521,7 +517,7 @@ pub const Cursor = packed struct { call(c.mdb_cursor_count, .{ self.inner, &inner }) catch |err| { panic("cursor is initialized, or database does not support duplicate keys: {}", .{err}); }; - return @intCast(usize, inner); + return @as(usize, @intCast(inner)); } pub fn updateItemInPlace(self: Self, current_key: []const u8, new_val: anytype) !void { @@ -530,17 +526,17 @@ pub const Cursor = packed struct { } pub fn updateInPlace(self: Self, current_key: []const u8, new_val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*void, @ptrToInt(current_key.ptr)) }; - var v = &c.MDB_val{ .mv_size = new_val.len, .mv_data = @intToPtr(?*void, @ptrToInt(new_val.ptr)) }; - try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT }); + var k = c.MDB_val{ .mv_size = current_key.len, .mv_data = @constCast(current_key.ptr) }; + var v = c.MDB_val{ .mv_size = new_val.len, .mv_data = @constCast(new_val.ptr) }; + try call(c.mdb_cursor_put, .{ self.inner, &k, &v, c.MDB_CURRENT }); } /// May not be used with databases supporting duplicate keys. pub fn reserveInPlace(self: Self, current_key: []const u8, new_val_len: usize) ![]u8 { - var k = &c.MDB_val{ .mv_size = current_key.len, .mv_data = @intToPtr(?*void, @ptrToInt(current_key.ptr)) }; - var v = &c.MDB_val{ .mv_size = new_val_len, .mv_data = null }; - try call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_CURRENT | c.MDB_RESERVE }); - return @ptrCast([*]u8, v.mv_data)[0..v.mv_size]; + var k = c.MDB_val{ .mv_size = current_key.len, .mv_data = @constCast(current_key.ptr) }; + var v = c.MDB_val{ .mv_size = new_val_len, .mv_data = null }; + try call(c.mdb_cursor_put, .{ self.inner, &k, &v, c.MDB_CURRENT | c.MDB_RESERVE }); + return @as([*]u8, @ptrCast(v.mv_data))[0..v.mv_size]; } pub const PutFlags = packed struct { @@ -557,33 +553,33 @@ pub const Cursor = packed struct { return flags; } }; - pub inline fn putItem(self: Self, key: []const u8, val: anytype, flags: PutFlags) !void { - const bytes = if (meta.trait.isIndexable(@TypeOf(val))) mem.span(val) else mem.asBytes(&val); - return self.put(key, bytes, flags); - } pub inline fn put(self: Self, key: []const u8, val: []const u8, flags: PutFlags) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; - try call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }); - } + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; + try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); + } + // pub inline fn putItem(self: Self, key: []const u8, value: anytype, flags: PutFlags) !usize { + // var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + // var v = c.MDB_val{ .mv_size = @sizeOf(@TypeOf(value)), .mv_data = @as(*anyopaque, @constCast(&value)) }; + // try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); + // } + /// Insert multiple values for a key + /// value must be contiguous in memory, like []Foo pub inline fn putBatch(self: Self, key: []const u8, batch: anytype, flags: PutFlags) !usize { comptime assert(meta.trait.isIndexable(@TypeOf(batch))); - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = [_]c.MDB_val{ - .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = @intToPtr(?*void, @ptrToInt(&batch[0])) }, - .{ .mv_size = mem.len(batch), .mv_data = undefined }, - }; - try call(c.mdb_cursor_put, .{ self.inner, k, &v, @intCast(c_uint, c.MDB_MULTIPLE) | flags.into() }); + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = [_]c.MDB_val{ .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = &batch[0] }, .{ .mv_size = batch.len, .mv_data = undefined } }; + try call(c.mdb_cursor_put, .{ self.inner, &k, &v, @as(c_uint, @intCast(c.MDB_MULTIPLE)) | flags.into() }); - return @intCast(usize, v[1].mv_size); + return @as(usize, @intCast(v[1].mv_size)); } pub inline fn getOrPut(self: Self, key: []const u8, val: []const u8) !?[]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = key.ptr }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; - call(c.mdb_cursor_put, .{ self.inner, k, v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { - error.AlreadyExists => return @ptrCast([*]u8, v.mv_data)[0..v.mv_size], + call(c.mdb_cursor_put, .{ self.inner, &k, &v, c.MDB_NOOVERWRITE }) catch |err| switch (err) { + error.AlreadyExists => return @as([*]u8, @ptrCast(v.mv_data))[0..v.mv_size], else => return err, }; @@ -606,22 +602,22 @@ pub const Cursor = packed struct { found_existing: []const u8, }; pub inline fn reserve(self: Self, key: []const u8, val_len: usize, flags: ReserveFlags) !ReserveResult { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val_len, .mv_data = null }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val_len, .mv_data = null }; - call(c.mdb_cursor_put, .{ self.inner, k, v, flags.into() }) catch |err| switch (err) { + call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }) catch |err| switch (err) { error.AlreadyExists => return ReserveResult{ - .found_existing = @ptrCast([*]const u8, v.mv_data)[0..v.mv_size], + .found_existing = @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size], }, else => return err, }; return ReserveResult{ - .successful = @ptrCast([*]u8, v.mv_data)[0..v.mv_size], + .successful = @as([*]u8, @ptrCast(v.mv_data))[0..v.mv_size], }; } pub inline fn del(self: Self, op: enum(c_uint) { key = c.MDB_NODUPDATA, item = 0 }) MDB_errorset!void { - call(c.mdb_cursor_del, .{ self.inner, @enumToInt(op) }) catch |err| switch (err) { + call(c.mdb_cursor_del, .{ self.inner, @intFromEnum(op) }) catch |err| switch (err) { error.InvalidParameter => return error.NotFound, else => return err, }; @@ -643,14 +639,14 @@ pub const Cursor = packed struct { pub inline fn get(self: Self, pos: Position) !?Entry { var k: c.MDB_val = undefined; var v: c.MDB_val = undefined; - call(c.mdb_cursor_get, .{ self.inner, &k, &v, @enumToInt(pos) }) catch |err| switch (err) { + call(c.mdb_cursor_get, .{ self.inner, &k, &v, @intFromEnum(pos) }) catch |err| switch (err) { error.InvalidParameter => return if (pos == .current) null else err, error.NotFound => return null, else => return err, }; return Entry{ - .key = @ptrCast([*]const u8, k.mv_data)[0..k.mv_size], - .val = @ptrCast([*]const u8, v.mv_data)[0..v.mv_size], + .key = @as([*]const u8, @ptrCast(k.mv_data))[0..k.mv_size], + .val = @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size], }; } @@ -662,40 +658,40 @@ pub const Cursor = packed struct { pub inline fn getPage(self: Self, comptime T: type, pos: PagePosition) MDB_errorset!?Page(T) { var k: c.MDB_val = undefined; var v: c.MDB_val = undefined; - call(c.mdb_cursor_get, .{ self.inner, &k, &v, @enumToInt(pos) }) catch |err| switch (err) { + call(c.mdb_cursor_get, .{ self.inner, &k, &v, @intFromEnum(pos) }) catch |err| switch (err) { error.NotFound => return null, else => return err, }; return Page(T){ - .key = @ptrCast([*]const u8, k.mv_data)[0..k.mv_size], - .items = mem.bytesAsSlice(T, @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]), + .key = @as([*]const u8, @ptrCast(k.mv_data))[0..k.mv_size], + .items = mem.bytesAsSlice(T, @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size]), }; } pub inline fn seekToItem(self: Self, key: []const u8, val: []const u8) !void { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; - try call(c.mdb_cursor_get, .{ self.inner, k, v, .MDB_GET_BOTH }); + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; + try call(c.mdb_cursor_get, .{ self.inner, &k, &v, .MDB_GET_BOTH }); } pub inline fn seekFromItem(self: Self, key: []const u8, val: []const u8) ![]const u8 { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; - var v = &c.MDB_val{ .mv_size = val.len, .mv_data = @intToPtr(?*void, @ptrToInt(val.ptr)) }; - try call(c.mdb_cursor_get, .{ self.inner, k, v, c.MDB_GET_BOTH_RANGE }); - return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; + try call(c.mdb_cursor_get, .{ self.inner, &k, &v, c.MDB_GET_BOTH_RANGE }); + return @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size]; } pub inline fn seekTo(self: Self, key: []const u8) ![]const u8 { @setEvalBranchQuota(10000); - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; var v: c.MDB_val = undefined; - try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_KEY }); - return @ptrCast([*]const u8, v.mv_data)[0..v.mv_size]; + try call(c.mdb_cursor_get, .{ self.inner, &k, &v, c.MDB_SET_KEY }); + return @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size]; } pub inline fn seekFrom(self: Self, key: []const u8) !Entry { - var k = &c.MDB_val{ .mv_size = key.len, .mv_data = @intToPtr(?*void, @ptrToInt(key.ptr)) }; + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; var v: c.MDB_val = undefined; - try call(c.mdb_cursor_get, .{ self.inner, k, &v, c.MDB_SET_RANGE }); + try call(c.mdb_cursor_get, .{ self.inner, &k, &v, c.MDB_SET_RANGE }); return Entry{ - .key = @ptrCast([*]const u8, k.mv_data)[0..k.mv_size], - .val = @ptrCast([*]const u8, v.mv_data)[0..v.mv_size], + .key = @as([*]const u8, @ptrCast(k.mv_data))[0..k.mv_size], + .val = @as([*]const u8, @ptrCast(v.mv_data))[0..v.mv_size], }; } pub inline fn first(self: Self) !?Entry { @@ -742,7 +738,7 @@ pub const Cursor = packed struct { } }; -pub const MDB_errorset = error { +pub const MDB_errorset = error{ AlreadyExists, NotFound, PageNotFound, @@ -778,7 +774,7 @@ inline fn ResultOf(comptime function: anytype) type { } inline fn call(comptime function: anytype, args: anytype) ResultOf(function) { - const rc = @call(.{}, function, args); + const rc = @call(.auto, function, args); if (ResultOf(function) == void) return rc; return switch (rc) { @@ -803,14 +799,14 @@ inline fn call(comptime function: anytype, args: anytype) ResultOf(function) { c.MDB_BAD_TXN => error.TransactionNotAborted, c.MDB_BAD_VALSIZE => error.UnsupportedSize, c.MDB_BAD_DBI => error.BadDatabaseHandle, - @enumToInt(os.E.NOENT) => error.NoSuchFileOrDirectory, - @enumToInt(os.E.IO) => error.InputOutputError, - @enumToInt(os.E.NOMEM) => error.OutOfMemory, - @enumToInt(os.E.ACCES) => error.ReadOnly, - @enumToInt(os.E.BUSY) => error.DeviceOrResourceBusy, - @enumToInt(os.E.INVAL) => error.InvalidParameter, - @enumToInt(os.E.NOSPC) => error.NoSpaceLeftOnDevice, - @enumToInt(os.E.EXIST) => error.FileAlreadyExists, + @intFromEnum(os.E.NOENT) => error.NoSuchFileOrDirectory, + @intFromEnum(os.E.IO) => error.InputOutputError, + @intFromEnum(os.E.NOMEM) => error.OutOfMemory, + @intFromEnum(os.E.ACCES) => error.ReadOnly, + @intFromEnum(os.E.BUSY) => error.DeviceOrResourceBusy, + @intFromEnum(os.E.INVAL) => error.InvalidParameter, + @intFromEnum(os.E.NOSPC) => error.NoSpaceLeftOnDevice, + @intFromEnum(os.E.EXIST) => error.FileAlreadyExists, else => panic("({}) {s}", .{ rc, c.mdb_strerror(rc) }), }; } @@ -1327,7 +1323,7 @@ test "Cursor: interact with variable-sized items in a database with duplicate ke inline for (expected) |entry| { inline for (entry[1]) |val| { - try tx.putItem(db, entry[0], val, .{ .dont_overwrite_item = true }); + try tx.put(db, entry[0], val, .{ .dont_overwrite_item = true }); } } @@ -1387,7 +1383,7 @@ test "Cursor: interact with batches of fixed-sized items in a database with dupl try tx.setItemOrder(db, U64.order); comptime var items: [512]u64 = undefined; - inline for (items) |*item, i| item.* = @as(u64, i); + inline for (&items, 0..) |*item, i| item.* = @as(u64, i); const expected = comptime .{ .{ "Set A", &items }, @@ -1399,7 +1395,7 @@ test "Cursor: interact with batches of fixed-sized items in a database with dupl defer cursor.deinit(); inline for (expected) |entry| { - try testing.expectEqual(entry[1].len, try cursor.putBatch(entry[0], entry[1], .{})); + try testing.expectEqual(entry[1].len, try cursor.putBatch(entry[0], @as(*[512][8]u8, @ptrCast(entry[1])), .{})); } } From f8a4888c2e73137d1453c1a7ac642bf16dc96e69 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:07:21 +0000 Subject: [PATCH 05/10] Fix build.zig. Now it can be used as dependency --- README.md | 23 ++++++++++------------- build.zig | 2 ++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ffb1db3..e667387 100644 --- a/README.md +++ b/README.md @@ -24,19 +24,16 @@ As a result, extensive effort was put into exposing and testing as many differen ## Setup -These bindings were built with first-class support for the [zigmod](https://github.com/nektro/zigmod) package manager. - -To incorporate these bindings into your project, include the following into your project's `zig.mod`: - -```yml -- type: git - path: https://github.com/lithdew/lmdb-zig -``` - -Afterwards, run: - -```shell -zigmod fetch +1. Add this repo as git submodule +2. Add the following code to your `build.zig` + +```zig +pub fn build(b: *std.Build) void { + ... + const dep_lmdb = b.anonymousDependency("lib/lmdb-zig", @import("lib/lmdb-zig/build.zig"), .{}); + exe.linkLibrary(dep_lmdb.artifact("lmdb")); + exe.addModule("lmdb", dep_lmdb.module("lmdb")); +} ``` ## Status diff --git a/build.zig b/build.zig index e220f26..573220b 100644 --- a/build.zig +++ b/build.zig @@ -14,6 +14,8 @@ pub fn build(b: *std.Build) void { lib.linkLibC(); lib.addCSourceFiles(&.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, &.{"-fno-sanitize=undefined"}); + b.installArtifact(lib); + const pkg = b.addModule("lmdb", .{ .source_file = .{ .path = "lmdb.zig" }, }); From 49f7dd71dfb490c9a3127755b7083f37a42e9424 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:51:17 +0000 Subject: [PATCH 06/10] Unify tx.open and tx.use --- lmdb.zig | 63 ++++++++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/lmdb.zig b/lmdb.zig index 3d35475..e17c68e 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -282,27 +282,9 @@ pub const Database = struct { duplicate_entries_are_fixed_size: bool = false, duplicate_keys_are_integers: bool = false, compare_duplicate_keys_in_reverse_order: bool = false, - pub inline fn into(self: Self.OpenFlags) c_uint { - var flags: c_uint = 0; - if (self.compare_keys_in_reverse_order) flags |= c.MDB_REVERSEKEY; - if (self.allow_duplicate_keys) flags |= c.MDB_DUPSORT; - if (self.keys_are_integers) flags |= c.MDB_INTEGERKEY; - if (self.duplicate_entries_are_fixed_size) flags |= c.MDB_DUPFIXED; - if (self.duplicate_keys_are_integers) flags |= c.MDB_INTEGERDUP; - if (self.compare_duplicate_keys_in_reverse_order) flags |= c.MDB_REVERSEDUP; - return flags; - } - }; - - pub const UseFlags = packed struct { - compare_keys_in_reverse_order: bool = false, - allow_duplicate_keys: bool = false, - keys_are_integers: bool = false, - duplicate_entries_are_fixed_size: bool = false, - duplicate_keys_are_integers: bool = false, - compare_duplicate_keys_in_reverse_order: bool = false, + /// only use with named database create_if_not_exists: bool = false, - pub inline fn into(self: Self.UseFlags) c_uint { + pub inline fn into(self: @This()) c_uint { var flags: c_uint = 0; if (self.compare_keys_in_reverse_order) flags |= c.MDB_REVERSEKEY; if (self.allow_duplicate_keys) flags |= c.MDB_DUPSORT; @@ -344,14 +326,9 @@ pub const Transaction = packed struct { pub inline fn id(self: Self) usize { return @as(usize, @intCast(c.mdb_txn_id(self.inner))); } - pub inline fn open(self: Self, flags: Database.OpenFlags) !Database { - var inner: c.MDB_dbi = 0; - try call(c.mdb_dbi_open, .{ self.inner, null, flags.into(), &inner }); - return Database{ .inner = inner }; - } - pub inline fn use(self: Self, name: []const u8, flags: Database.UseFlags) !Database { + pub inline fn open(self: Self, name: ?[]const u8, flags: Database.OpenFlags) !Database { var inner: c.MDB_dbi = 0; - try call(c.mdb_dbi_open, .{ self.inner, name.ptr, flags.into(), &inner }); + try call(c.mdb_dbi_open, .{ self.inner, if (name) |s| s.ptr else null, flags.into(), &inner }); return Database{ .inner = inner }; } pub inline fn cursor(self: Self, db: Database) !Cursor { @@ -889,7 +866,7 @@ test "Environment.copyTo(): backup environment and check environment integrity" const tx = try env_a.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env_a); var i: u8 = 0; @@ -909,7 +886,7 @@ test "Environment.copyTo(): backup environment and check environment integrity" const tx = try env_b.begin(.{}); defer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env_b); var i: u8 = 0; @@ -937,7 +914,7 @@ test "Environment.sync(): manually flush system buffers" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); var i: u8 = 0; @@ -954,7 +931,7 @@ test "Environment.sync(): manually flush system buffers" { const tx = try env.begin(.{}); defer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); var i: u8 = 0; @@ -977,7 +954,7 @@ test "Transaction: get(), put(), reserve(), delete(), and commit() several entri const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); // Transaction.put() / Transaction.get() @@ -1033,7 +1010,7 @@ test "Transaction: reserve, write, and attempt to reserve again with dont_overwr const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); switch (try tx.reserve(db, "hello", "world!".len, .{ .dont_overwrite_key = true })) { @@ -1062,7 +1039,7 @@ test "Transaction: getOrPut() twice" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); try testing.expectEqual(@as(?[]const u8, null), try tx.getOrPut(db, "hello", "world")); @@ -1086,10 +1063,10 @@ test "Transaction: use multiple named databases in a single transaction" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const a = try tx.use("A", .{ .create_if_not_exists = true }); + const a = try tx.open("A", .{ .create_if_not_exists = true }); defer a.close(env); - const b = try tx.use("B", .{ .create_if_not_exists = true }); + const b = try tx.open("B", .{ .create_if_not_exists = true }); defer b.close(env); try tx.put(a, "hello", "this is in A!", .{}); @@ -1102,10 +1079,10 @@ test "Transaction: use multiple named databases in a single transaction" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const a = try tx.use("A", .{}); + const a = try tx.open("A", .{}); defer a.close(env); - const b = try tx.use("B", .{}); + const b = try tx.open("B", .{}); defer b.close(env); try testing.expectEqualStrings("this is in A!", try tx.get(a, "hello")); @@ -1128,7 +1105,7 @@ test "Transaction: nest transaction inside transaction" { const parent = try env.begin(.{}); errdefer parent.deinit(); - const db = try parent.open(.{}); + const db = try parent.open(null, .{}); defer db.close(env); { @@ -1176,7 +1153,7 @@ test "Transaction: custom key comparator" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); const items = [_][]const u8{ "a", "b", "c" }; @@ -1214,7 +1191,7 @@ test "Cursor: move around a database and add / delete some entries" { const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{}); + const db = try tx.open(null, .{}); defer db.close(env); { @@ -1312,7 +1289,7 @@ test "Cursor: interact with variable-sized items in a database with duplicate ke const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{ .allow_duplicate_keys = true }); + const db = try tx.open(null, .{ .allow_duplicate_keys = true }); defer db.close(env); const expected = comptime .{ @@ -1374,7 +1351,7 @@ test "Cursor: interact with batches of fixed-sized items in a database with dupl const tx = try env.begin(.{}); errdefer tx.deinit(); - const db = try tx.open(.{ + const db = try tx.open(null, .{ .allow_duplicate_keys = true, .duplicate_entries_are_fixed_size = true, }); From cc50b611160ecb2815760e1642a41ac59f309c2f Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:54:46 +0000 Subject: [PATCH 07/10] Upgrade to Zig 0.12.0-dev.1849+bb0f7d55e --- build.zig | 4 ++-- lmdb.zig | 59 ++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/build.zig b/build.zig index 573220b..24c84f1 100644 --- a/build.zig +++ b/build.zig @@ -12,7 +12,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); lib.linkLibC(); - lib.addCSourceFiles(&.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, &.{"-fno-sanitize=undefined"}); + lib.addCSourceFiles(.{ .files = &.{ "lmdb/libraries/liblmdb/mdb.c", "lmdb/libraries/liblmdb/midl.c" }, .flags = &.{"-fno-sanitize=undefined"} }); b.installArtifact(lib); @@ -26,7 +26,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); - tests.addIncludePath("lmdb/libraries/liblmdb"); + tests.addIncludePath(.{ .path = "lmdb/libraries/liblmdb" }); tests.linkLibrary(lib); b.installArtifact(tests); diff --git a/lmdb.zig b/lmdb.zig index e17c68e..b834def 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -88,7 +88,7 @@ pub const Environment = packed struct { assert(env_path.len + 1 <= fs.MAX_PATH_BYTES); var fixed_path: [fs.MAX_PATH_BYTES + 1]u8 = undefined; - mem.copy(u8, &fixed_path, env_path); + @memcpy(fixed_path[0..env_path.len], env_path); fixed_path[env_path.len] = 0; try call(c.mdb_env_open, .{ inner, fixed_path[0 .. env_path.len + 1].ptr, flags.into(), flags.mode }); @@ -115,7 +115,7 @@ pub const Environment = packed struct { assert(backup_path.len + 1 <= fs.MAX_PATH_BYTES); var fixed_path: [fs.MAX_PATH_BYTES + 1]u8 = undefined; - mem.copy(u8, &fixed_path, backup_path); + @memcpy(fixed_path[0..backup_path.len], backup_path); fixed_path[backup_path.len] = 0; try call(c.mdb_env_copy2, .{ self.inner, fixed_path[0 .. backup_path.len + 1].ptr, flags.into() }); @@ -435,7 +435,7 @@ pub const Transaction = packed struct { } pub inline fn del(self: Self, db: Database, key: []const u8, op: union(enum) { key: void, item: []const u8 }) !void { var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; - var v: ?*c.MDB_val = switch (op) { + const v: ?*c.MDB_val = switch (op) { .key => null, .item => |item| &c.MDB_val{ .mv_size = item.len, @@ -535,6 +535,25 @@ pub const Cursor = packed struct { var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); } + + // functions std.meta.trait that are no longer there + fn is(comptime expected: std.meta.Tag(std.builtin.Type), comptime T: type) bool { + const actual = std.meta.activeTag(@typeInfo(T)); + return expected == actual; + } + fn isTuple(comptime T: type) bool { + return is(.Struct, T) and @typeInfo(T).Struct.is_tuple; + } + fn isIndexable(comptime T: type) bool { + if (is(.Pointer, T)) { + if (@typeInfo(T).Pointer.size == .One) { + return (is(.Array, meta.Child(T))); + } + return true; + } + return is(.Array, T) or is(.Vector, T) or isTuple(T); + } + // pub inline fn putItem(self: Self, key: []const u8, value: anytype, flags: PutFlags) !usize { // var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; // var v = c.MDB_val{ .mv_size = @sizeOf(@TypeOf(value)), .mv_data = @as(*anyopaque, @constCast(&value)) }; @@ -543,7 +562,7 @@ pub const Cursor = packed struct { /// Insert multiple values for a key /// value must be contiguous in memory, like []Foo pub inline fn putBatch(self: Self, key: []const u8, batch: anytype, flags: PutFlags) !usize { - comptime assert(meta.trait.isIndexable(@TypeOf(batch))); + comptime assert(isIndexable(@TypeOf(batch))); var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; var v = [_]c.MDB_val{ .{ .mv_size = @sizeOf(meta.Elem(@TypeOf(batch))), .mv_data = &batch[0] }, .{ .mv_size = batch.len, .mv_data = undefined } }; @@ -797,7 +816,7 @@ test "Environment.init() / Environment.deinit(): query environment stats, flags, defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .use_writable_memory_map = true, @@ -856,8 +875,8 @@ test "Environment.copyTo(): backup environment and check environment integrity" var buf_a: [fs.MAX_PATH_BYTES]u8 = undefined; var buf_b: [fs.MAX_PATH_BYTES]u8 = undefined; - var path_a = try tmp_a.dir.realpath("./", &buf_a); - var path_b = try tmp_b.dir.realpath("./", &buf_b); + const path_a = try tmp_a.dir.realpath("./", &buf_a); + const path_b = try tmp_b.dir.realpath("./", &buf_b); const env_a = try Environment.init(path_a, .{}); { @@ -901,7 +920,7 @@ test "Environment.sync(): manually flush system buffers" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .dont_sync = true, @@ -946,7 +965,7 @@ test "Transaction: get(), put(), reserve(), delete(), and commit() several entri defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{}); defer env.deinit(); @@ -978,7 +997,7 @@ test "Transaction: get(), put(), reserve(), delete(), and commit() several entri { const result = try tx.reserve(db, "hello", "new_value".len, .{}); try testing.expectEqual("new_value".len, result.successful.len); - mem.copy(u8, result.successful, "new_value"); + @memcpy(result.successful, "new_value"); } try testing.expectEqualStrings("new_value", try tx.get(db, "hello")); @@ -1002,7 +1021,7 @@ test "Transaction: reserve, write, and attempt to reserve again with dont_overwr defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{}); defer env.deinit(); @@ -1015,7 +1034,7 @@ test "Transaction: reserve, write, and attempt to reserve again with dont_overwr switch (try tx.reserve(db, "hello", "world!".len, .{ .dont_overwrite_key = true })) { .found_existing => try testing.expect(false), - .successful => |dst| std.mem.copy(u8, dst, "world!"), + .successful => |dst| @memcpy(dst, "world!"), } switch (try tx.reserve(db, "hello", "world!".len, .{ .dont_overwrite_key = true })) { @@ -1031,7 +1050,7 @@ test "Transaction: getOrPut() twice" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{}); defer env.deinit(); @@ -1054,7 +1073,7 @@ test "Transaction: use multiple named databases in a single transaction" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .max_num_dbs = 2 }); defer env.deinit(); @@ -1097,7 +1116,7 @@ test "Transaction: nest transaction inside transaction" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{}); defer env.deinit(); @@ -1145,7 +1164,7 @@ test "Transaction: custom key comparator" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .max_num_dbs = 2 }); defer env.deinit(); @@ -1183,7 +1202,7 @@ test "Cursor: move around a database and add / delete some entries" { defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{}); defer env.deinit(); @@ -1256,7 +1275,7 @@ test "Cursor: move around a database and add / delete some entries" { try cursor.updateInPlace(item, "???"); try testing.expectEqualStrings("???", (try cursor.current()).?.val); - mem.copy(u8, try cursor.reserveInPlace(item, item.len), item); + @memcpy(try cursor.reserveInPlace(item, item.len), item); try testing.expectEqualStrings(item, (try cursor.current()).?.val); } @@ -1281,7 +1300,7 @@ test "Cursor: interact with variable-sized items in a database with duplicate ke defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .max_num_dbs = 1 }); defer env.deinit(); @@ -1343,7 +1362,7 @@ test "Cursor: interact with batches of fixed-sized items in a database with dupl defer tmp.cleanup(); var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - var path = try tmp.dir.realpath("./", &buf); + const path = try tmp.dir.realpath("./", &buf); const env = try Environment.init(path, .{ .max_num_dbs = 1 }); defer env.deinit(); From 5ca51061964e8510c3c83d73cf658df6d078c8e0 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:56:41 +0000 Subject: [PATCH 08/10] Add readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e667387..e66f8b9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Refer to the 12 extensive unit tests provided [here](lmdb.zig#L874) for usage in Built and tested against Zig's master branch over all possible optimization modes. +For Zig 0.11, see the branch `0.11`. ## Motivation From ebd68640aea5cfede6496649129239daf7437352 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Fri, 29 Dec 2023 14:11:20 +0000 Subject: [PATCH 09/10] Cleanup --- lmdb.zig | 80 +++++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/lmdb.zig b/lmdb.zig index b834def..d23259d 100644 --- a/lmdb.zig +++ b/lmdb.zig @@ -12,6 +12,35 @@ const testing = std.testing; const panic = debug.panic; const assert = debug.assert; +threadlocal var _addZ_buffer: [fs.MAX_PATH_BYTES + 1]u8 = undefined; +fn addZ(slice: []const u8) [*:0]const u8 { + if (slice.ptr[slice.len] == 0) { + return @ptrCast(slice.ptr); + } + + @memcpy(_addZ_buffer[0..slice.len], slice); + _addZ_buffer[slice.len] = 0; + return @ptrCast(&_addZ_buffer); +} + +// functions std.meta.trait that are no longer there +fn is(comptime expected: std.meta.Tag(std.builtin.Type), comptime T: type) bool { + const actual = std.meta.activeTag(@typeInfo(T)); + return expected == actual; +} +fn isTuple(comptime T: type) bool { + return is(.Struct, T) and @typeInfo(T).Struct.is_tuple; +} +fn isIndexable(comptime T: type) bool { + if (is(.Pointer, T)) { + if (@typeInfo(T).Pointer.size == .One) { + return (is(.Array, meta.Child(T))); + } + return true; + } + return is(.Array, T) or is(.Vector, T) or isTuple(T); +} + pub const Environment = packed struct { pub const Statistics = struct { page_size: usize, @@ -84,17 +113,7 @@ pub const Environment = packed struct { try call(c.mdb_env_set_maxdbs, .{ inner, @as(c_uint, @intCast(max_num_dbs)) }); } - if (!mem.endsWith(u8, env_path, &[_]u8{0})) { - assert(env_path.len + 1 <= fs.MAX_PATH_BYTES); - - var fixed_path: [fs.MAX_PATH_BYTES + 1]u8 = undefined; - @memcpy(fixed_path[0..env_path.len], env_path); - fixed_path[env_path.len] = 0; - - try call(c.mdb_env_open, .{ inner, fixed_path[0 .. env_path.len + 1].ptr, flags.into(), flags.mode }); - } else { - try call(c.mdb_env_open, .{ inner, env_path.ptr, flags.into(), flags.mode }); - } + try call(c.mdb_env_open, .{ inner, addZ(env_path), flags.into(), flags.mode }); return Self{ .inner = inner }; } @@ -111,17 +130,7 @@ pub const Environment = packed struct { } }; pub inline fn copyTo(self: Self, backup_path: []const u8, flags: CopyFlags) !void { - if (!mem.endsWith(u8, backup_path, &[_]u8{0})) { - assert(backup_path.len + 1 <= fs.MAX_PATH_BYTES); - - var fixed_path: [fs.MAX_PATH_BYTES + 1]u8 = undefined; - @memcpy(fixed_path[0..backup_path.len], backup_path); - fixed_path[backup_path.len] = 0; - - try call(c.mdb_env_copy2, .{ self.inner, fixed_path[0 .. backup_path.len + 1].ptr, flags.into() }); - } else { - try call(c.mdb_env_copy2, .{ self.inner, backup_path.ptr, flags.into() }); - } + try call(c.mdb_env_copy2, .{ self.inner, addZ(backup_path), flags.into() }); } pub inline fn pipeTo(self: Self, fd_handle: os.fd_t, flags: CopyFlags) !void { try call(c.mdb_env_copyfd2, .{ self.inner, fd_handle, flags.into() }); @@ -535,30 +544,11 @@ pub const Cursor = packed struct { var v = c.MDB_val{ .mv_size = val.len, .mv_data = @constCast(val.ptr) }; try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); } - - // functions std.meta.trait that are no longer there - fn is(comptime expected: std.meta.Tag(std.builtin.Type), comptime T: type) bool { - const actual = std.meta.activeTag(@typeInfo(T)); - return expected == actual; - } - fn isTuple(comptime T: type) bool { - return is(.Struct, T) and @typeInfo(T).Struct.is_tuple; - } - fn isIndexable(comptime T: type) bool { - if (is(.Pointer, T)) { - if (@typeInfo(T).Pointer.size == .One) { - return (is(.Array, meta.Child(T))); - } - return true; - } - return is(.Array, T) or is(.Vector, T) or isTuple(T); + pub inline fn putItem(self: Self, key: []const u8, value: anytype, flags: PutFlags) !usize { + var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; + var v = c.MDB_val{ .mv_size = @sizeOf(@TypeOf(value)), .mv_data = @as(*anyopaque, @constCast(&value)) }; + try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); } - - // pub inline fn putItem(self: Self, key: []const u8, value: anytype, flags: PutFlags) !usize { - // var k = c.MDB_val{ .mv_size = key.len, .mv_data = @constCast(key.ptr) }; - // var v = c.MDB_val{ .mv_size = @sizeOf(@TypeOf(value)), .mv_data = @as(*anyopaque, @constCast(&value)) }; - // try call(c.mdb_cursor_put, .{ self.inner, &k, &v, flags.into() }); - // } /// Insert multiple values for a key /// value must be contiguous in memory, like []Foo pub inline fn putBatch(self: Self, key: []const u8, batch: anytype, flags: PutFlags) !usize { From 27958114cef5bf647f8866398510e7817a090208 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+iacore@users.noreply.github.com> Date: Fri, 29 Dec 2023 14:11:52 +0000 Subject: [PATCH 10/10] update lmdb --- lmdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lmdb b/lmdb index c7b3cc4..30288c7 160000 --- a/lmdb +++ b/lmdb @@ -1 +1 @@ -Subproject commit c7b3cc4df6dfe8f0772fb509bdc74777667caa43 +Subproject commit 30288c72573ceac719627183f1058cad1dd08b74