1 const std = @import("std");
2 const lmdb = @cImport(@cInclude("lmdb.h"));
4 pub usingnamespace lmdb;
6 pub fn Cursor(comptime K: type, comptime V: type) type {
10 pub const Flags = enum(c_uint) {
11 First = lmdb.MDB_FIRST,
12 FirstDup = lmdb.MDB_FIRST_DUP,
13 GetBoth = lmdb.MDB_GET_BOTH,
14 GetBothRange = lmdb.MDB_GET_BOTH_RANGE,
15 GetCurrent = lmdb.MDB_GET_CURRENT,
16 GetMultiple = lmdb.MDB_GET_MULTIPLE,
18 LastDup = lmdb.MDB_LAST_DUP,
20 NextDup = lmdb.MDB_NEXT_DUP,
21 NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
22 NextNodup = lmdb.MDB_NEXT_NODUP,
24 PrevDup = lmdb.MDB_PREV_DUP,
25 PrevNodup = lmdb.MDB_PREV_NODUP,
27 SetKey = lmdb.MDB_SET_KEY,
28 SetRange = lmdb.MDB_SET_RANGE,
31 ptr: ?*lmdb.MDB_cursor = undefined,
33 pub fn close(self: *Self) void {
34 _ = lmdb.mdb_cursor_close(self.ptr);
37 pub fn put(self: *Self, k: K, v: V) void {
38 var key = lmdb.MDB_val{
39 .mv_size = @sizeOf(@TypeOf(k)),
40 .mv_data = @constCast(@ptrCast(&k)),
42 var val = lmdb.MDB_val{
43 .mv_size = @sizeOf(@TypeOf(v)),
44 .mv_data = @constCast(@ptrCast(&v)),
46 switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
49 std.debug.print("put err: {}\n", .{err});
54 pub fn get(self: *Self, k: *K, flags: Flags) ?V {
55 var key = lmdb.MDB_val{
56 .mv_size = @sizeOf(K),
57 .mv_data = @constCast(@ptrCast(k)),
59 var val: lmdb.MDB_val = undefined;
60 return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
62 k.* = std.mem.bytesToValue(K, key.mv_data.?);
63 return std.mem.bytesToValue(V, val.mv_data.?);
64 //k.* = @as(*align(1) K, @ptrCast(key.mv_data)).*;
65 //return @as(?*align(1) V, @ptrCast(val.mv_data)).?.*;
67 lmdb.MDB_NOTFOUND => null,
69 std.debug.print("get err: {}\n", .{err});
75 pub fn del(self: *Self, k: K) 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)) {
83 std.debug.print("del err: {}\n", .{err});
88 pub fn has(self: *Dbi, k: K, flags: Flags) bool {
89 return self.get(k, flags) != null;
94 pub fn Dbi(comptime K: type, comptime V: type) type {
98 ptr: lmdb.MDB_dbi = undefined,
99 txn: *const Txn = undefined,
100 env: *const Env = undefined,
102 pub fn close(self: Self) void {
105 lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
108 pub fn cursor(self: Self) !Cursor(K, V) {
109 var result = Cursor(K, V){};
111 return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
113 else => error.CursorOpen,
117 pub fn put(self: Self, k: K, v: V) void {
118 var key = lmdb.MDB_val{
119 .mv_size = @sizeOf(@TypeOf(k)),
120 .mv_data = @constCast(@ptrCast(&k)),
122 var val = lmdb.MDB_val{
123 .mv_size = @sizeOf(@TypeOf(v)),
124 .mv_data = @constCast(@ptrCast(&v)),
126 switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
129 std.debug.print("put err: {}\n", .{err});
134 pub fn get(self: Self, k: K) ?V {
135 var key = lmdb.MDB_val{
136 .mv_size = @sizeOf(@TypeOf(k)),
137 .mv_data = @constCast(@ptrCast(&k)),
139 var val: lmdb.MDB_val = undefined;
140 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
142 return std.mem.bytesToValue(V, val.mv_data.?);
143 //@as(?*align(1) V, @ptrCast(val.mv_data)).?.*
146 std.debug.print("get err: {}\n", .{err});
152 pub fn del(self: Self, k: K) void {
153 var key = lmdb.MDB_val{
154 .mv_size = @sizeOf(@TypeOf(k)),
155 .mv_data = @constCast(@ptrCast(&k)),
157 switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
160 std.debug.print("del err: {}\n", .{err});
165 pub fn has(self: Self, k: K) bool {
166 return self.get(k) != null;
171 pub const Txn = struct {
172 ptr: ?*lmdb.MDB_txn = undefined,
173 env: *const Env = undefined,
175 pub fn dbi(self: *const Txn, name: [*c]const u8, comptime K: type, comptime V: type) !Dbi(K, V) {
176 var result = Dbi(K, V){ .env = self.env, .txn = self };
177 // TODO: lmdb.MDB_INTEGERKEY?
178 switch (lmdb.mdb_dbi_open(self.ptr, name, lmdb.MDB_CREATE, &result.ptr)) {
181 std.debug.print("dbi err: {}\n", .{err});
182 return error.DbiOpen;
187 pub fn commit(self: Txn) void {
188 switch (lmdb.mdb_txn_commit(self.ptr)) {
190 lmdb.MDB_MAP_FULL => {
191 std.debug.print("resize\n", .{});
192 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
195 std.debug.print("commit err: {}\n", .{err});
200 pub fn abort(self: Txn) void {
201 lmdb.mdb_txn_abort(self.ptr);
205 pub const Env = struct {
206 ptr: ?*lmdb.MDB_env = undefined,
208 pub fn open(name: [*c]const u8, size: lmdb.mdb_size_t) Env {
211 _ = lmdb.mdb_env_create(&result.ptr);
212 _ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
213 _ = lmdb.mdb_env_set_mapsize(result.ptr, size);
214 _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP, 0o664);
215 // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
220 pub fn close(self: Env) void {
221 lmdb.mdb_env_close(self.ptr);
224 pub fn txn(self: *const Env) !Txn {
225 var result = Txn{ .env = self };
226 switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
229 std.debug.print("txn err: {}\n", .{err});
230 return error.TxnOpen;
235 pub fn sync(self: *Env) void {
236 switch (lmdb.mdb_env_sync(self.ptr, 1)) {
239 std.debug.print("sync err: {}\n", .{err});
246 var env = Env.open("db", 1024 * 1024 * 1);
248 var txn = try env.txn();
250 const Value = struct {
252 s: [16]u8 = undefined,
255 var dbi = try txn.dbi("abc", u64, Value);
257 var val = dbi.get(1) orelse Value{ .i = 5 };
258 std.debug.print("{}\n", .{val});
271 var env = Env.open("db", 1024 * 1024 * 1);
273 var txn = try env.txn();
275 const Value = struct {
277 s: [16]u8 = undefined,
280 var dbi = try txn.dbi("def", u64, Value);
283 dbi.put(i, Value{ .i = @intCast(i + 23) });
286 var cursor = try dbi.cursor();
288 var key: u64 = undefined;
290 const val = cursor.get(&key, .First);
291 std.debug.print("{}: {?}\n", .{ key, val });
294 while (cursor.get(&key, .Next)) |val| {
295 std.debug.print("{}: {?}\n", .{ key, val });
306 // pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {
307 // var key = lmdb.MDB_val{
308 // .mv_size = @sizeOf(@TypeOf(k)),
309 // .mv_data = @constCast(@ptrCast(&k)),
311 // var val: lmdb.MDB_val = undefined;
312 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
313 // 0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*,
315 // std.debug.print("get err: {}\n", .{err});
321 // pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, v: anytype) void {
322 // var key = lmdb.MDB_val{
323 // .mv_size = @sizeOf(@TypeOf(k)),
324 // .mv_data = @constCast(@ptrCast(&k)),
326 // var val = lmdb.MDB_val{
327 // .mv_size = @sizeOf(@TypeOf(v)),
328 // .mv_data = @constCast(@ptrCast(&v)),
330 // switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
333 // std.debug.print("put err: {}\n", .{err});
338 // pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void {
339 // var key = lmdb.MDB_val{
340 // .mv_size = @sizeOf(@TypeOf(k)),
341 // .mv_data = @constCast(@ptrCast(&k)),
343 // switch (lmdb.mdb_del(txn, dbi, &key, null)) {
346 // std.debug.print("del err: {}\n", .{err});
351 // pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) bool {
352 // var key = lmdb.MDB_val{
353 // .mv_size = @sizeOf(@TypeOf(k)),
354 // .mv_data = @constCast(@ptrCast(&k)),
356 // var val: lmdb.MDB_val = undefined;
357 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
359 // lmdb.MDB_NOTFOUND => false,
361 // std.debug.print("has err: {}\n", .{err});