]> gitweb.ps.run Git - ziglmdb/blob - src/lmdb.zig
idkkkkk
[ziglmdb] / src / lmdb.zig
1 const std = @import("std");
2 const lmdb = @cImport(@cInclude("lmdb.h"));
3
4 pub usingnamespace lmdb;
5
6 pub fn Cursor(comptime K: type, comptime V: type) type {
7     return struct {
8         const Self = @This();
9
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,
17             Last = lmdb.MDB_LAST,
18             LastDup = lmdb.MDB_LAST_DUP,
19             Next = lmdb.MDB_NEXT,
20             NextDup = lmdb.MDB_NEXT_DUP,
21             NextMultiple = lmdb.MDB_NEXT_MULTIPLE,
22             NextNodup = lmdb.MDB_NEXT_NODUP,
23             Prev = lmdb.MDB_PREV,
24             PrevDup = lmdb.MDB_PREV_DUP,
25             PrevNodup = lmdb.MDB_PREV_NODUP,
26             Set = lmdb.MDB_SET,
27             SetKey = lmdb.MDB_SET_KEY,
28             SetRange = lmdb.MDB_SET_RANGE,
29         };
30
31         ptr: ?*lmdb.MDB_cursor = undefined,
32
33         pub fn close(self: *Self) void {
34             _ = lmdb.mdb_cursor_close(self.ptr);
35         }
36
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)),
41             };
42             var val = lmdb.MDB_val{
43                 .mv_size = @sizeOf(@TypeOf(v)),
44                 .mv_data = @constCast(@ptrCast(&v)),
45             };
46             switch (lmdb.mdb_cursor_put(self.ptr, &key, &val, 0)) {
47                 0 => {},
48                 else => |err| {
49                     std.debug.print("put err: {}\n", .{err});
50                 },
51             }
52         }
53
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)),
58             };
59             var val: lmdb.MDB_val = undefined;
60             return switch (lmdb.mdb_cursor_get(self.ptr, &key, &val, @intFromEnum(flags))) {
61                 0 => {
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)).?.*;
66                 },
67                 lmdb.MDB_NOTFOUND => null,
68                 else => |err| {
69                     std.debug.print("get err: {}\n", .{err});
70                     return null;
71                 },
72             };
73         }
74
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)),
79             };
80             switch (lmdb.mdb_cursor_del(self.ptr, &key, 0)) {
81                 0 => {},
82                 else => |err| {
83                     std.debug.print("del err: {}\n", .{err});
84                 },
85             }
86         }
87
88         pub fn has(self: *Dbi, k: K, flags: Flags) bool {
89             return self.get(k, flags) != null;
90         }
91     };
92 }
93
94 pub fn Dbi(comptime K: type, comptime V: type) type {
95     return struct {
96         const Self = @This();
97
98         ptr: lmdb.MDB_dbi = undefined,
99         txn: *const Txn = undefined,
100         env: *const Env = undefined,
101
102         pub fn close(self: Self) void {
103
104             // TODO: necessary?
105             lmdb.mdb_dbi_close(self.env.ptr, self.ptr);
106         }
107
108         pub fn cursor(self: Self) !Cursor(K, V) {
109             var result = Cursor(K, V){};
110
111             return switch (lmdb.mdb_cursor_open(self.txn.ptr, self.ptr, &result.ptr)) {
112                 0 => result,
113                 else => error.CursorOpen,
114             };
115         }
116
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)),
121             };
122             var val = lmdb.MDB_val{
123                 .mv_size = @sizeOf(@TypeOf(v)),
124                 .mv_data = @constCast(@ptrCast(&v)),
125             };
126             switch (lmdb.mdb_put(self.txn.ptr, self.ptr, &key, &val, 0)) {
127                 0 => {},
128                 else => |err| {
129                     std.debug.print("put err: {}\n", .{err});
130                 },
131             }
132         }
133
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)),
138             };
139             var val: lmdb.MDB_val = undefined;
140             return switch (lmdb.mdb_get(self.txn.ptr, self.ptr, &key, &val)) {
141                 0 => {
142                     return std.mem.bytesToValue(V, val.mv_data.?);
143                     //@as(?*align(1) V, @ptrCast(val.mv_data)).?.*
144                 },
145                 else => |err| {
146                     std.debug.print("get err: {}\n", .{err});
147                     return null;
148                 },
149             };
150         }
151
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)),
156             };
157             switch (lmdb.mdb_del(self.txn.ptr, self.ptr, &key, null)) {
158                 0 => {},
159                 else => |err| {
160                     std.debug.print("del err: {}\n", .{err});
161                 },
162             }
163         }
164
165         pub fn has(self: Self, k: K) bool {
166             return self.get(k) != null;
167         }
168     };
169 }
170
171 pub const Txn = struct {
172     ptr: ?*lmdb.MDB_txn = undefined,
173     env: *const Env = undefined,
174
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)) {
179             0 => return result,
180             else => |err| {
181                 std.debug.print("dbi err: {}\n", .{err});
182                 return error.DbiOpen;
183             },
184         }
185     }
186
187     pub fn commit(self: Txn) void {
188         switch (lmdb.mdb_txn_commit(self.ptr)) {
189             0 => {},
190             lmdb.MDB_MAP_FULL => {
191                 std.debug.print("resize\n", .{});
192                 _ = lmdb.mdb_env_set_mapsize(self.env.ptr, 0);
193             },
194             else => |err| {
195                 std.debug.print("commit err: {}\n", .{err});
196             },
197         }
198     }
199
200     pub fn abort(self: Txn) void {
201         lmdb.mdb_txn_abort(self.ptr);
202     }
203 };
204
205 pub const Env = struct {
206     ptr: ?*lmdb.MDB_env = undefined,
207
208     pub fn open(name: [*c]const u8, size: lmdb.mdb_size_t) Env {
209         var result = Env{};
210
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);
216
217         return result;
218     }
219
220     pub fn close(self: Env) void {
221         lmdb.mdb_env_close(self.ptr);
222     }
223
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)) {
227             0 => return result,
228             else => |err| {
229                 std.debug.print("txn err: {}\n", .{err});
230                 return error.TxnOpen;
231             },
232         }
233     }
234
235     pub fn sync(self: *Env) void {
236         switch (lmdb.mdb_env_sync(self.ptr, 1)) {
237             0 => {},
238             else => |err| {
239                 std.debug.print("sync err: {}\n", .{err});
240             },
241         }
242     }
243 };
244
245 test "basic" {
246     var env = Env.open("db", 1024 * 1024 * 1);
247
248     var txn = try env.txn();
249
250     const Value = struct {
251         i: i64 = 123,
252         s: [16]u8 = undefined,
253     };
254
255     var dbi = try txn.dbi("abc", u64, Value);
256
257     var val = dbi.get(1) orelse Value{ .i = 5 };
258     std.debug.print("{}\n", .{val});
259
260     val.i += 1;
261
262     dbi.put(1, val);
263
264     txn.commit();
265     dbi.close();
266     env.sync();
267     env.close();
268 }
269
270 test "cursor" {
271     var env = Env.open("db", 1024 * 1024 * 1);
272
273     var txn = try env.txn();
274
275     const Value = struct {
276         i: i64 = 123,
277         s: [16]u8 = undefined,
278     };
279
280     var dbi = try txn.dbi("def", u64, Value);
281
282     for (0..10) |i| {
283         dbi.put(i, Value{ .i = @intCast(i + 23) });
284     }
285
286     var cursor = try dbi.cursor();
287
288     var key: u64 = undefined;
289     {
290         const val = cursor.get(&key, .First);
291         std.debug.print("{}: {?}\n", .{ key, val });
292     }
293
294     while (cursor.get(&key, .Next)) |val| {
295         std.debug.print("{}: {?}\n", .{ key, val });
296     }
297
298     cursor.close();
299
300     txn.commit();
301     dbi.close();
302     env.sync();
303     env.close();
304 }
305
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)),
310 //     };
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))).?.*,
314 //         else => |err| {
315 //             std.debug.print("get err: {}\n", .{err});
316 //             return null;
317 //         },
318 //     };
319 // }
320
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)),
325 //     };
326 //     var val = lmdb.MDB_val{
327 //         .mv_size = @sizeOf(@TypeOf(v)),
328 //         .mv_data = @constCast(@ptrCast(&v)),
329 //     };
330 //     switch (lmdb.mdb_put(txn, dbi, &key, &val, 0)) {
331 //         0 => {},
332 //         else => |err| {
333 //             std.debug.print("put err: {}\n", .{err});
334 //         },
335 //     }
336 // }
337
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)),
342 //     };
343 //     switch (lmdb.mdb_del(txn, dbi, &key, null)) {
344 //         0 => {},
345 //         else => |err| {
346 //             std.debug.print("del err: {}\n", .{err});
347 //         },
348 //     }
349 // }
350
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)),
355 //     };
356 //     var val: lmdb.MDB_val = undefined;
357 //     return switch (lmdb.mdb_get(txn, dbi, &key, &val)) {
358 //         0 => true,
359 //         lmdb.MDB_NOTFOUND => false,
360 //         else => |err| {
361 //             std.debug.print("has err: {}\n", .{err});
362 //             return false;
363 //         },
364 //     };
365 // }