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.* = @as(*align(1) K, @ptrCast(key.mv_data)).*;
63 return @as(?*align(1) V, @ptrCast(val.mv_data)).?.*;
65 lmdb.MDB_NOTFOUND => null,
67 std.debug.print("get err: {}\n", .{err});
73 pub fn del(self: *Self, k: K) void {
74 var key = lmdb.MDB_val{
75 .mv_size = @sizeOf(@TypeOf(k)),
76 .mv_data = @constCast(@ptrCast(&k)),
78 switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
81 std.debug.print("del err: {}\n", .{err});
86 pub fn has(self: *Dbi, k: K, flags: Flags) bool {
87 return self.get(k, flags) != null;
92 pub fn Dbi(comptime K: type, comptime V: type) type {
96 ptr: lmdb.MDB_dbi = undefined,
97 txn: *const Txn = undefined,
98 env: *const Env = undefined,
100 pub fn close(self: Self) void {
103 lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
106 pub fn cursor(self: Self) !Cursor(K, V) {
107 var result = Cursor(K, V){};
109 return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
111 else => error.CursorOpen,
115 pub fn put(self: Self, k: K, v: V) void {
116 var key = lmdb.MDB_val{
117 .mv_size = @sizeOf(@TypeOf(k)),
118 .mv_data = @constCast(@ptrCast(&k)),
120 var val = lmdb.MDB_val{
121 .mv_size = @sizeOf(@TypeOf(v)),
122 .mv_data = @constCast(@ptrCast(&v)),
124 switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
127 std.debug.print("put err: {}\n", .{err});
132 pub fn get(self: Self, k: K) ?V {
133 var key = lmdb.MDB_val{
134 .mv_size = @sizeOf(@TypeOf(k)),
135 .mv_data = @constCast(@ptrCast(&k)),
137 var val: lmdb.MDB_val = undefined;
138 return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
139 0 => @as(?*align(1) V, @ptrCast(val.mv_data)).?.*,
141 std.debug.print("get err: {}\n", .{err});
147 pub fn del(self: Self, k: K) void {
148 var key = lmdb.MDB_val{
149 .mv_size = @sizeOf(@TypeOf(k)),
150 .mv_data = @constCast(@ptrCast(&k)),
152 switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
155 std.debug.print("del err: {}\n", .{err});
160 pub fn has(self: Self, k: K) bool {
161 return self.get(k) != null;
166 pub const Txn = struct {
167 ptr: ?*lmdb.MDB_txn = undefined,
168 env: *const Env = undefined,
170 pub fn dbi(self: *const Txn, name: [*c]const u8, comptime K: type, comptime V: type) !Dbi(K, V) {
171 var result = Dbi(K, V){ .env = self.env, .txn = self };
172 // TODO: lmdb.MDB_INTEGERKEY?
173 switch (lmdb.mdb_dbi_open(self.ptr, name, lmdb.MDB_CREATE, &result.ptr)) {
176 std.debug.print("dbi err: {}\n", .{err});
177 return error.DbiOpen;
182 pub fn commit(self: Txn) void {
183 switch (lmdb.mdb_txn_commit(self.ptr)) {
185 lmdb.MDB_MAP_FULL => {
186 std.debug.print("resize\n", .{});
187 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
190 std.debug.print("commit err: {}\n", .{err});
195 pub fn abort(self: Txn) void {
196 lmdb.mdb_txn_abort(self.ptr);
200 pub const Env = struct {
201 ptr: ?*lmdb.MDB_env = undefined,
203 pub fn open(name: [*c]const u8, size: lmdb.mdb_size_t) Env {
206 _ = lmdb.mdb_env_create(&result.ptr);
207 _ = lmdb.mdb_env_set_maxdbs(result.ptr, 10);
208 _ = lmdb.mdb_env_set_mapsize(result.ptr, size);
209 _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_WRITEMAP, 0o664);
210 // _ = lmdb.mdb_env_open(result.ptr, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664);
215 pub fn close(self: Env) void {
216 lmdb.mdb_env_close(self.ptr);
219 pub fn txn(self: *const Env) !Txn {
220 var result = Txn{ .env = self };
221 switch (lmdb.mdb_txn_begin(self.ptr, null, 0, &result.ptr)) {
224 std.debug.print("txn err: {}\n", .{err});
225 return error.TxnOpen;
230 pub fn sync(self: *Env) void {
231 switch (lmdb.mdb_env_sync(self.ptr, 1)) {
234 std.debug.print("sync err: {}\n", .{err});
241 var env = Env.open("db", 1024 * 1024 * 1);
243 var txn = try env.txn();
245 const Value = struct {
247 s: [16]u8 = undefined,
250 var dbi = try txn.dbi("abc", u64, Value);
252 var val = dbi.get(1) orelse Value{ .i = 5 };
253 std.debug.print("{}\n", .{val});
266 var env = Env.open("db", 1024 * 1024 * 1);
268 var txn = try env.txn();
270 const Value = struct {
272 s: [16]u8 = undefined,
275 var dbi = try txn.dbi("def", u64, Value);
278 dbi.put(i, Value{ .i = @intCast(i + 23) });
281 var cursor = try dbi.cursor();
283 var key: u64 = undefined;
285 const val = cursor.get(&key, .First);
286 std.debug.print("{}: {?}\n", .{ key, val });
289 while (cursor.get(&key, .Next)) |val| {
290 std.debug.print("{}: {?}\n", .{ key, val });
301 // pub fn get(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, comptime T: type) ?T {
302 // var key = lmdb.MDB_val{
303 // .mv_size = @sizeOf(@TypeOf(k)),
304 // .mv_data = @constCast(@ptrCast(&k)),
306 // var val: lmdb.MDB_val = undefined;
307 // return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
308 // 0 => @as(?*align(1) T, @alignCast(@ptrCast(val.mv_data))).?.*,
310 // std.debug.print("get err: {}\n", .{err});
316 // pub fn put(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype, v: anytype) void {
317 // var key = lmdb.MDB_val{
318 // .mv_size = @sizeOf(@TypeOf(k)),
319 // .mv_data = @constCast(@ptrCast(&k)),
321 // var val = lmdb.MDB_val{
322 // .mv_size = @sizeOf(@TypeOf(v)),
323 // .mv_data = @constCast(@ptrCast(&v)),
325 // switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
328 // std.debug.print("put err: {}\n", .{err});
333 // pub fn del(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) void {
334 // var key = lmdb.MDB_val{
335 // .mv_size = @sizeOf(@TypeOf(k)),
336 // .mv_data = @constCast(@ptrCast(&k)),
338 // switch (lmdb.mdb_del(txn, dbi, &key, null)) {
341 // std.debug.print("del err: {}\n", .{err});
346 // pub fn has(txn: ?*lmdb.MDB_txn, dbi: lmdb.MDB_dbi, k: anytype) bool {
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)) {
354 // lmdb.MDB_NOTFOUND => false,
356 // std.debug.print("has err: {}\n", .{err});