1 const std = @import("std");
2 const lmdb = @cImport(@cInclude("lmdb.h"));
4 pub usingnamespace lmdb;
6 pub const Cursor = struct {
9 pub const Flags = enum(c_uint) {
10 First = lmdb.MDB_FIRST,
11 FirstDup = lmdb.MDB_FIRST_DUP,
12 GetBoth = lmdb.MDB_GET_BOTH,
13 GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
14 GetCurrent = lmdb.MDB_GET_CURRENT,
15 GetMultiple = lmdb.MDB_GET_MULTIPLE,
17 LastDup = lmdb.MDB_LAST_DUP,
19 NextDup = lmdb.MDB_NEXT_DUP,
20 NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
21 NextNodup = lmdb.MDB_NEXT_NODUP,
23 PrevDup = lmdb.MDB_PREV_DUP,
24 PrevNodup = lmdb.MDB_PREV_NODUP,
26 SetKey = lmdb.MDB_SET_KEY,
27 SetRange = lmdb.MDB_SET_RANGE,
30 ptr: ?*lmdb.MDB_cursor = undefined,
32 pub fn close(self: Self) void {
33 lmdb.mdb_cursor_close(self.ptr);
36 pub fn put(self: Self, k: anytype, v: anytype) !void {
37 var key = lmdb.MDB_val{
38 .mv_size = @sizeOf(@TypeOf(k)),
39 .mv_data = @constCast(@ptrCast(&k)),
41 var val = lmdb.MDB_val{
42 .mv_size = @sizeOf(@TypeOf(v)),
43 .mv_data = @constCast(@ptrCast(&v)),
45 switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
49 return error.CursorPut;
54 pub fn get(self: Self, k: anytype, comptime V: type, flags: Flags) !?V {
55 const k_ti = @typeInfo(@TypeOf(k));
56 const K = k_ti.pointer.child;
58 var key = lmdb.MDB_val{
59 .mv_size = @sizeOf(K),
60 .mv_data = @constCast(@ptrCast(k)),
62 var val: lmdb.MDB_val = undefined;
63 return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
65 const ptr = @as(*K, @constCast(k));
66 ptr.* = std.mem.bytesToValue(K, key.mv_data.?);
67 return std.mem.bytesToValue(V, val.mv_data.?);
69 lmdb.MDB_NOTFOUND => null,
72 return error.CursorGet;
77 pub fn del(self: Self, k: anytype) !void {
78 var key = lmdb.MDB_val{
79 .mv_size = @sizeOf(@TypeOf(k)),
80 .mv_data = @constCast(@ptrCast(&k)),
82 switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
86 return error.CursorDel;
91 pub fn has(self: Self, k: anytype, flags: Flags) !bool {
92 const k_ti = @typeInfo(@TypeOf(k));
93 const K = k_ti.pointer.child;
95 var key = lmdb.MDB_val{
96 .mv_size = @sizeOf(K),
97 .mv_data = @constCast(@ptrCast(k)),
99 var val: lmdb.MDB_val = undefined;
100 return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
104 lmdb.MDB_NOTFOUND => {
108 return error.CursorHas;
114 pub const Dbi = struct {
115 const Self = @This();
117 ptr: lmdb.MDB_dbi = undefined,
118 txn: Txn = undefined,
119 env: Env = undefined,
121 pub fn close(self: Self) void {
123 lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
126 pub fn cursor(self: Self) !Cursor {
127 var result = Cursor{};
129 return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
131 else => error.DbiCursor,
135 pub fn put(self: Self, k: anytype, v: anytype) !void {
136 var key = lmdb.MDB_val{
137 .mv_size = @sizeOf(@TypeOf(k)),
138 .mv_data = @constCast(@ptrCast(&k)),
140 var val = lmdb.MDB_val{
141 .mv_size = @sizeOf(@TypeOf(v)),
142 .mv_data = @constCast(@ptrCast(&v)),
144 switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
153 pub fn get(self: Self, k: anytype, comptime V: type) !V {
154 var key = lmdb.MDB_val{
155 .mv_size = @sizeOf(@TypeOf(k)),
156 .mv_data = @constCast(@ptrCast(&k)),
158 var val: lmdb.MDB_val = undefined;
159 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
161 return std.mem.bytesToValue(V, val.mv_data.?);
163 lmdb.MDB_NOTFOUND => error.NotFound,
171 pub fn del(self: Self, k: anytype) !void {
172 var key = lmdb.MDB_val{
173 .mv_size = @sizeOf(@TypeOf(k)),
174 .mv_data = @constCast(@ptrCast(&k)),
176 switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
185 pub fn has(self: Self, k: anytype) !bool {
186 var key = lmdb.MDB_val{
187 .mv_size = @sizeOf(@TypeOf(k)),
188 .mv_data = @constCast(@ptrCast(&k)),
190 var val: lmdb.MDB_val = undefined;
191 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
195 lmdb.MDB_NOTFOUND => {
199 std.debug.print("[{}]\n", .{err});
206 pub const Txn = struct {
207 ptr: ?*lmdb.MDB_txn = undefined,
208 env: Env = undefined,
210 pub fn dbi(self: Txn, name: ?[:0]const u8) !Dbi {
211 var result = Dbi{ .env = self.env, .txn = self };
212 // TODO: lmdb.MDB_INTEGERKEY?
213 switch (lmdb.mdb_dbi_open(self.ptr, @ptrCast(name), lmdb.MDB_CREATE, &result.ptr)) {
217 return error.DbiOpen;
222 pub fn commit(self: Txn) !void {
223 switch (lmdb.mdb_txn_commit(self.ptr)) {
225 lmdb.MDB_MAP_FULL => {
226 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
227 return error.TxnCommitMapFull;
231 return error.TxnCommit;
236 pub fn abort(self: Txn) void {
237 lmdb.mdb_txn_abort(self.ptr);
241 pub const Env = struct {
242 ptr: ?*lmdb.MDB_env = undefined,
244 pub fn open(name: [:0]const u8, size: lmdb.mdb_size_t) !Env {
247 _ = lmdb.mdb_env_create(&result.ptr);
248 _ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
249 _ = lmdb.mdb_env_set_mapsize(result.ptr, size);
250 const res = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP | lmdb.MDB_NOSUBDIR, 0o664);
251 // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
254 return error.EnvOpen;
260 pub fn close(self: Env) void {
261 lmdb.mdb_env_close(self.ptr);
264 pub fn txn(self: Env) !Txn {
265 var result = Txn{ .env = self };
266 switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
270 return error.TxnOpen;
275 pub fn sync(self: Env) !void {
276 switch (lmdb.mdb_env_sync(self.ptr, 1)) {
280 return error.EnvSync;
287 var env = try Env.open("db", 1024 * 1024 * 1);
291 var txn = try env.txn();
292 defer txn.commit() catch {};
294 const Value = struct {
296 s: [16]u8 = undefined,
299 var dbi = try txn.dbi("abc");
303 std.debug.print("has?: {}\n", .{try dbi.has(idx)});
305 var val = dbi.get(idx, Value) catch Value{ .i = 5 };
306 std.debug.print("{}\n", .{val});
310 try dbi.put(idx, val);
314 var env = try Env.open("db", 1024 * 1024 * 1);
318 var txn = try env.txn();
319 defer txn.commit() catch {};
321 const Value = struct {
323 s: [16]u8 = undefined,
326 var dbi = try txn.dbi("def");
329 try dbi.put(@as(u64, i), Value{ .i = @intCast(i + 23) });
332 var cursor = try dbi.cursor();
333 defer cursor.close();
335 var key: u64 = undefined;
337 const val = try cursor.get(&key, Value, .First);
338 std.debug.print("{}: {?}\n", .{ key, val });
341 while (try cursor.get(&key, Value, .Next)) |val| {
342 std.debug.print("{}: {?}\n", .{ key, val });
346 // pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {
347 // var key = lmdb.MDB_val{
348 // .mv_size = @sizeOf(@TypeOf(k)),
349 // .mv_data = @constCast(@ptrCast(&k)),
351 // var val: lmdb.MDB_val = undefined;
352 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
353 // 0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*,
355 // std.debug.print("get err: {}\n", .{err});
361 // pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, v: anytype) void {
362 // var key = lmdb.MDB_val{
363 // .mv_size = @sizeOf(@TypeOf(k)),
364 // .mv_data = @constCast(@ptrCast(&k)),
366 // var val = lmdb.MDB_val{
367 // .mv_size = @sizeOf(@TypeOf(v)),
368 // .mv_data = @constCast(@ptrCast(&v)),
370 // switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
373 // std.debug.print("put err: {}\n", .{err});
378 // pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void {
379 // var key = lmdb.MDB_val{
380 // .mv_size = @sizeOf(@TypeOf(k)),
381 // .mv_data = @constCast(@ptrCast(&k)),
383 // switch (lmdb.mdb_del(txn, dbi, &key, null)) {
386 // std.debug.print("del err: {}\n", .{err});
391 // pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) bool {
392 // var key = lmdb.MDB_val{
393 // .mv_size = @sizeOf(@TypeOf(k)),
394 // .mv_data = @constCast(@ptrCast(&k)),
396 // var val: lmdb.MDB_val = undefined;
397 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
399 // lmdb.MDB_NOTFOUND => false,
401 // std.debug.print("has err: {}\n", .{err});