1 const std = @import("std");
2 const lmdb = @cImport(@cInclude("lmdb.h"));
4 pub const Cursor = struct {
7 pub const Flags = enum(c_uint) {
8 First = lmdb.MDB_FIRST,
9 FirstDup = lmdb.MDB_FIRST_DUP,
10 GetBoth = lmdb.MDB_GET_BOTH,
11 GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
12 GetCurrent = lmdb.MDB_GET_CURRENT,
13 GetMultiple = lmdb.MDB_GET_MULTIPLE,
15 LastDup = lmdb.MDB_LAST_DUP,
17 NextDup = lmdb.MDB_NEXT_DUP,
18 NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
19 NextNodup = lmdb.MDB_NEXT_NODUP,
21 PrevDup = lmdb.MDB_PREV_DUP,
22 PrevNodup = lmdb.MDB_PREV_NODUP,
24 SetKey = lmdb.MDB_SET_KEY,
25 SetRange = lmdb.MDB_SET_RANGE,
28 ptr: ?*lmdb.MDB_cursor = undefined,
30 pub fn close(self: Self) void {
31 lmdb.mdb_cursor_close(self.ptr);
34 pub fn put(self: Self, k: anytype, v: anytype) !void {
35 var key = lmdb.MDB_val{
36 .mv_size = @sizeOf(@TypeOf(k)),
37 .mv_data = @constCast(@ptrCast(&k)),
39 var val = lmdb.MDB_val{
40 .mv_size = @sizeOf(@TypeOf(v)),
41 .mv_data = @constCast(@ptrCast(&v)),
43 switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
47 return error.CursorPut;
52 pub fn get(self: Self, k: anytype, comptime V: type, flags: Flags) !?V {
53 const k_ti = @typeInfo(@TypeOf(k));
54 const K = k_ti.pointer.child;
56 var key = lmdb.MDB_val{
57 .mv_size = @sizeOf(K),
58 .mv_data = @constCast(@ptrCast(k)),
60 var val: lmdb.MDB_val = undefined;
61 return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
63 const ptr = @as(*K, @constCast(k));
64 ptr.* = std.mem.bytesToValue(K, key.mv_data.?);
65 return std.mem.bytesToValue(V, val.mv_data.?);
67 lmdb.MDB_NOTFOUND => null,
70 return error.CursorGet;
75 pub fn del(self: Self, k: anytype) !void {
76 var key = lmdb.MDB_val{
77 .mv_size = @sizeOf(@TypeOf(k)),
78 .mv_data = @constCast(@ptrCast(&k)),
80 switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
84 return error.CursorDel;
89 pub fn has(self: Self, k: anytype, flags: Flags) !bool {
90 const k_ti = @typeInfo(@TypeOf(k));
91 const K = k_ti.pointer.child;
93 var key = lmdb.MDB_val{
94 .mv_size = @sizeOf(K),
95 .mv_data = @constCast(@ptrCast(k)),
97 var val: lmdb.MDB_val = undefined;
98 return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
102 lmdb.MDB_NOTFOUND => {
106 return error.CursorHas;
112 pub const Dbi = struct {
113 const Self = @This();
115 ptr: lmdb.MDB_dbi = undefined,
116 txn: Txn = undefined,
117 env: Env = undefined,
119 pub fn close(self: Self) void {
121 lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
124 pub fn cursor(self: Self) !Cursor {
125 var result = Cursor{};
127 return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
129 else => error.DbiCursor,
133 pub fn put(self: Self, k: anytype, v: anytype) !void {
134 var key = lmdb.MDB_val{
135 .mv_size = @sizeOf(@TypeOf(k)),
136 .mv_data = @constCast(@ptrCast(&k)),
138 var val = lmdb.MDB_val{
139 .mv_size = @sizeOf(@TypeOf(v)),
140 .mv_data = @constCast(@ptrCast(&v)),
142 switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
151 pub fn get(self: Self, k: anytype, comptime V: type) !V {
152 var key = lmdb.MDB_val{
153 .mv_size = @sizeOf(@TypeOf(k)),
154 .mv_data = @constCast(@ptrCast(&k)),
156 var val: lmdb.MDB_val = undefined;
157 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
159 return std.mem.bytesToValue(V, val.mv_data.?);
161 lmdb.MDB_NOTFOUND => error.NotFound,
169 pub fn del(self: Self, k: anytype) !void {
170 var key = lmdb.MDB_val{
171 .mv_size = @sizeOf(@TypeOf(k)),
172 .mv_data = @constCast(@ptrCast(&k)),
174 switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
183 pub fn has(self: Self, k: anytype) !bool {
184 var key = lmdb.MDB_val{
185 .mv_size = @sizeOf(@TypeOf(k)),
186 .mv_data = @constCast(@ptrCast(&k)),
188 var val: lmdb.MDB_val = undefined;
189 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
193 lmdb.MDB_NOTFOUND => {
197 std.debug.print("[{}]\n", .{err});
204 pub const Txn = struct {
205 ptr: ?*lmdb.MDB_txn = undefined,
206 env: Env = undefined,
208 pub fn dbi(self: Txn, name: ?[:0]const u8) !Dbi {
209 var result = Dbi{ .env = self.env, .txn = self };
210 // TODO: lmdb.MDB_INTEGERKEY?
211 switch (lmdb.mdb_dbi_open(self.ptr, @ptrCast(name), lmdb.MDB_CREATE, &result.ptr)) {
215 return error.DbiOpen;
220 pub fn commit(self: Txn) !void {
221 switch (lmdb.mdb_txn_commit(self.ptr)) {
223 lmdb.MDB_MAP_FULL => {
224 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
225 return error.TxnCommitMapFull;
229 return error.TxnCommit;
234 pub fn abort(self: Txn) void {
235 lmdb.mdb_txn_abort(self.ptr);
239 pub const Env = struct {
240 ptr: ?*lmdb.MDB_env = undefined,
242 pub fn open(name: [:0]const u8, size: lmdb.mdb_size_t) !Env {
245 _ = lmdb.mdb_env_create(&result.ptr);
246 _ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
247 _ = lmdb.mdb_env_set_mapsize(result.ptr, size);
248 const res = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP | lmdb.MDB_NOSUBDIR, 0o664);
249 // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
252 return error.EnvOpen;
258 pub fn close(self: Env) void {
259 lmdb.mdb_env_close(self.ptr);
262 pub fn txn(self: Env) !Txn {
263 var result = Txn{ .env = self };
264 switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
268 return error.TxnOpen;
273 pub fn sync(self: Env) !void {
274 switch (lmdb.mdb_env_sync(self.ptr, 1)) {
278 return error.EnvSync;
285 var env = try Env.open("db", 1024 * 1024 * 1);
289 var txn = try env.txn();
290 defer txn.commit() catch {};
292 const Value = struct {
294 s: [16]u8 = undefined,
297 var dbi = try txn.dbi("abc");
301 std.debug.print("has?: {}\n", .{try dbi.has(idx)});
303 var val = dbi.get(idx, Value) catch Value{ .i = 5 };
304 std.debug.print("{}\n", .{val});
308 try dbi.put(idx, val);
312 var env = try Env.open("db", 1024 * 1024 * 1);
316 var txn = try env.txn();
317 defer txn.commit() catch {};
319 const Value = struct {
321 s: [16]u8 = undefined,
324 var dbi = try txn.dbi("def");
327 try dbi.put(@as(u64, i), Value{ .i = @intCast(i + 23) });
330 var cursor = try dbi.cursor();
331 defer cursor.close();
333 var key: u64 = undefined;
335 const val = try cursor.get(&key, Value, .First);
336 std.debug.print("{}: {?}\n", .{ key, val });
339 while (try cursor.get(&key, Value, .Next)) |val| {
340 std.debug.print("{}: {}\n", .{ key, val });
344 // pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {
345 // var key = lmdb.MDB_val{
346 // .mv_size = @sizeOf(@TypeOf(k)),
347 // .mv_data = @constCast(@ptrCast(&k)),
349 // var val: lmdb.MDB_val = undefined;
350 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
351 // 0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*,
353 // std.debug.print("get err: {}\n", .{err});
359 // pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, v: anytype) void {
360 // var key = lmdb.MDB_val{
361 // .mv_size = @sizeOf(@TypeOf(k)),
362 // .mv_data = @constCast(@ptrCast(&k)),
364 // var val = lmdb.MDB_val{
365 // .mv_size = @sizeOf(@TypeOf(v)),
366 // .mv_data = @constCast(@ptrCast(&v)),
368 // switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
371 // std.debug.print("put err: {}\n", .{err});
376 // pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void {
377 // var key = lmdb.MDB_val{
378 // .mv_size = @sizeOf(@TypeOf(k)),
379 // .mv_data = @constCast(@ptrCast(&k)),
381 // switch (lmdb.mdb_del(txn, dbi, &key, null)) {
384 // std.debug.print("del err: {}\n", .{err});
389 // pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) bool {
390 // var key = lmdb.MDB_val{
391 // .mv_size = @sizeOf(@TypeOf(k)),
392 // .mv_data = @constCast(@ptrCast(&k)),
394 // var val: lmdb.MDB_val = undefined;
395 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
397 // lmdb.MDB_NOTFOUND => false,
399 // std.debug.print("has err: {}\n", .{err});