1 const std = @import("std");
2 const lmdb = @import("lmdb");
6 pub fn Db(comptime K: type, comptime V: type) type {
12 pub fn init(txn: lmdb.Txn, name: [:0]const u8) !Self {
14 .dbi = try txn.dbi(name),
17 pub fn put(self: Self, k: K, v: V) !void {
18 try self.dbi.put(k, v);
20 pub fn get(self: Self, k: K) !V {
21 return try self.dbi.get(k, V);
23 pub fn del(self: Self, k: K) !void {
26 pub fn has(self: Self, k: K) !bool {
27 return try self.dbi.has(k);
29 pub const Iterator = struct {
30 pub const Result = struct { key: K, val: V };
32 dir: enum { Forward, Backward },
36 pub fn next(self: *Iterator) ?Result {
37 if (self.k != null and self.v != null) {
38 const result = Result{ .key = self.k.?, .val = self.v.? };
41 if (self.dir == .Forward) {
42 self.v = self.cursor.get(&k, V, .Next) catch return null;
44 self.v = self.cursor.get(&k, V, .Prev) catch return null;
55 pub fn iterator(self: Self) !Iterator {
56 var cursor = try self.dbi.cursor();
59 const v = try cursor.get(&k, V, .First);
60 return .{ .cursor = cursor, .dir = .Forward, .k = k, .v = v };
62 pub fn reverse_iterator(self: Self) !Iterator {
63 var cursor = try self.dbi.cursor();
66 const v = try cursor.get(&k, V, .Last);
67 return .{ .cursor = cursor, .dir = .Backward, .k = k, .v = v };
72 pub const Prng = struct {
73 var prng = std.Random.DefaultPrng.init(PRNG_SEED);
75 pub fn gen(dbi: lmdb.Dbi, comptime T: type) !T {
76 var buf: [@sizeOf(T)]u8 = undefined;
80 const t = std.mem.bytesToValue(T, &buf);
81 if (!try dbi.has(t)) {
88 fn SetListBase(comptime K: type, comptime V: type) type {
91 pub const Index = u64;
94 pub const View = SetListViewBase(K, V);
98 fn open_dbi(txn: lmdb.Txn) !lmdb.Dbi {
99 return try txn.dbi("SetList");
101 pub fn init(txn: lmdb.Txn) !Self {
102 const head = View.Head{};
103 const dbi = try open_dbi(txn);
104 const idx = try Prng.gen(dbi, Index);
105 try dbi.put(idx, head);
106 return .{ .idx = idx };
108 pub fn open(self: Self, txn: lmdb.Txn) !View {
110 if (self.idx == null) {
111 return error.NotInitialized;
114 const dbi = try open_dbi(txn);
115 const head = try dbi.get(self.idx.?, View.Head);
125 fn SetListViewBase(comptime K: type, comptime V: type) type {
127 const Self = @This();
128 pub const ItemIndex = struct { SetListBase(K, V).Index, Key };
132 pub const Head = struct {
137 pub const Item = struct {
144 idx: SetListBase(K, V).Index,
147 fn item_idx(self: Self, k: K) ItemIndex {
148 return .{ self.idx, k };
150 fn item_get(self: Self, k: K) !Item {
151 return try self.dbi.get(self.item_idx(k), Item);
153 fn item_put(self: Self, k: K, item: Item) !void {
154 try self.dbi.put(self.item_idx(k), item);
156 fn head_update(self: Self) !void {
157 try self.dbi.put(self.idx, self.head);
159 pub fn del(self: *Self, k: K) !void {
160 const item = try self.item_get(k);
162 if (item.prev != null) {
163 var prev = try self.item_get(item.prev.?);
164 prev.next = item.next;
165 try self.item_put(item.prev.?, prev);
168 if (item.next != null) {
169 var next = try self.item_get(item.next.?);
170 next.prev = item.prev;
171 try self.item_put(item.next.?, next);
174 if (self.head.first == k) self.head.first = item.next;
175 if (self.head.last == k) self.head.last = item.prev;
177 try self.head_update();
179 try self.dbi.del(self.item_idx(k));
181 pub fn clear(self: *Self) !void {
182 var it = self.iterator();
183 while (it.next()) |kv| {
184 try self.del(kv.key);
187 pub fn len(self: Self) usize {
188 return self.head.len;
190 pub fn append(self: *Self, key: Key, val: Val) !void {
191 if (self.head.len == 0) {
192 const item = Item{ .data = val };
193 try self.item_put(key, item);
196 self.head.first = key;
197 self.head.last = key;
198 try self.head_update();
200 const prev_idx = self.head.last.?;
201 var prev = try self.item_get(prev_idx);
203 const item = Item{ .prev = prev_idx, .data = val };
204 try self.item_put(key, item);
207 try self.item_put(prev_idx, prev);
209 self.head.last = key;
211 try self.head_update();
214 pub fn get(self: Self, key: Key) !Val {
215 const item = try self.item_get(key);
218 pub fn has(self: Self, key: Key) !bool {
219 return self.dbi.has(self.item_idx(key));
221 pub const Iterator = struct {
222 pub const Result = struct { key: K, val: V };
224 slv: SetListViewBase(K, V),
226 dir: enum { Forward, Backward },
228 pub fn next(self: *Iterator) ?Result {
229 if (self.idx != null) {
230 const k = self.idx.?;
231 const item = self.slv.item_get(k) catch return null;
232 self.idx = switch (self.dir) {
233 .Forward => item.next,
234 .Backward => item.prev,
236 return .{ .key = k, .val = item.data };
242 pub fn iterator(self: Self) Iterator {
245 .idx = self.head.first,
249 pub fn reverse_iterator(self: Self) Iterator {
252 .idx = self.head.last,
259 pub fn Set(comptime K: type) type {
262 pub const Val = void;
264 pub const Base = SetListBase(Key, Val);
265 pub const View = struct {
266 const ViewBase = SetListViewBase(Key, Val);
270 pub fn del(self: *@This(), key: Key) !void {
271 try self.base.del(key);
273 pub fn clear(self: *@This()) !void {
274 try self.base.clear();
276 pub fn len(self: @This()) usize {
277 return self.base.len();
279 pub fn append(self: *@This(), key: Key) !void {
280 try self.base.append(key, {});
282 pub fn has(self: @This(), key: Key) !bool {
283 return try self.base.has(key);
285 pub fn iterator(self: @This()) ViewBase.Iterator {
286 return self.base.iterator();
288 pub fn reverse_iterator(self: @This()) ViewBase.Iterator {
289 return self.base.reverse_iterator();
295 pub fn init(txn: lmdb.Txn) !@This() {
296 return .{ .base = try Base.init(txn) };
298 pub fn open(self: @This(), txn: lmdb.Txn) !View {
299 return .{ .base = try self.base.open(txn) };
304 pub fn List(comptime V: type) type {
309 pub const Base = SetListBase(Key, Val);
310 pub const View = struct {
311 const ViewBase = SetListViewBase(Key, Val);
315 fn gen(self: @This()) !Key {
318 const key = try Prng.gen(self.base.dbi, Key);
319 if (!try self.base.dbi.has(self.base.item_idx(key))) {
324 pub fn del(self: *@This(), key: Key) !void {
325 try self.base.del(key);
327 pub fn clear(self: *@This()) !void {
328 try self.base.clear();
330 pub fn len(self: @This()) usize {
331 return self.base.len();
333 pub fn append(self: *@This(), val: Val) !Key {
334 const key = try self.gen();
335 try self.base.append(key, val);
338 pub fn get(self: @This(), key: Key) !Val {
339 return try self.base.get(key);
341 pub fn has(self: @This(), key: Key) !bool {
342 return try self.base.has(key);
344 pub fn iterator(self: @This()) ViewBase.Iterator {
345 return self.base.iterator();
347 pub fn reverse_iterator(self: @This()) ViewBase.Iterator {
348 return self.base.reverse_iterator();
354 pub fn init(txn: lmdb.Txn) !@This() {
355 return .{ .base = try Base.init(txn) };
357 pub fn open(self: @This(), txn: lmdb.Txn) !View {
358 return .{ .base = try self.base.open(txn) };
363 pub fn SetList(comptime K: type, comptime V: type) type {
368 pub const Base = SetListBase(Key, Val);
369 pub const View = struct {
370 const ViewBase = SetListViewBase(Key, Val);
374 pub fn del(self: *@This(), key: Key) !void {
375 try self.base.del(key);
377 pub fn clear(self: *@This()) !void {
378 try self.base.clear();
380 pub fn len(self: @This()) usize {
381 return self.base.len();
383 pub fn append(self: *@This(), key: Key, val: Val) !void {
384 try self.base.append(key, val);
386 pub fn get(self: @This(), key: Key) !Val {
387 return try self.base.get(key);
389 pub fn has(self: @This(), key: Key) !bool {
390 return try self.base.has(key);
392 pub fn iterator(self: @This()) ViewBase.Iterator {
393 return self.base.iterator();
395 pub fn reverse_iterator(self: @This()) ViewBase.Iterator {
396 return self.base.reverse_iterator();
402 pub fn init(txn: lmdb.Txn) !@This() {
403 return .{ .base = try Base.init(txn) };
405 pub fn open(self: @This(), txn: lmdb.Txn) !View {
406 return .{ .base = try self.base.open(txn) };
411 const DB_SIZE = 1024 * 1024 * 1;
414 const env = try lmdb.Env.open("db", DB_SIZE);
417 const txn = try env.txn();
418 defer txn.commit() catch {};
420 var db = try Db(u32, u32).init(txn, "123");
422 if (try db.has(123)) {
427 std.debug.print("n: {}\n", .{n});
431 // const env = try lmdb.Env.open("db", DB_SIZE);
432 // defer env.close();
434 // const txn = try env.txn();
435 // defer txn.commit();
437 // const db = List.init(txn, "b", u32);
441 var env = try lmdb.Env.open("db", 1024 * 1024 * 1);
445 var txn = try env.txn();
446 defer txn.commit() catch {};
448 var dbi = try txn.dbi("abc");
454 var a: A = undefined;
455 const a_idx: u64 = 27;
456 if (try dbi.has(a_idx)) {
457 a = try dbi.get(a_idx, A);
459 a = A{ .ml = try Set(usize).init(txn) };
460 try dbi.put(a_idx, a);
463 var ml = try a.ml.open(txn);
465 const len = ml.len();
466 std.debug.print("{}\n", .{len});
468 std.debug.print("{}\n", .{try ml.has(len)});
469 var it = ml.iterator();
470 while (it.next()) |i| {
471 std.debug.print("{}\n", .{i});
476 var env = try lmdb.Env.open("db", 1024 * 1024 * 1);
480 var txn = try env.txn();
481 defer txn.commit() catch {};
483 var dbi = try txn.dbi("def");
489 var a: A = undefined;
490 const a_idx: u64 = 27;
491 if (try dbi.has(a_idx)) {
492 a = try dbi.get(a_idx, A);
494 a = A{ .ml = try List(usize).init(txn) };
495 try dbi.put(a_idx, a);
498 var ml = try a.ml.open(txn);
500 const len = ml.len();
501 std.debug.print("{}\n", .{len});
502 const newest = try ml.append(len * 10);
503 std.debug.print("{}: {}\n", .{ newest, try ml.get(newest) });
504 var it = ml.iterator();
505 while (it.next()) |i| {
506 std.debug.print("{}: {}\n", .{ i.key, i.val });
511 var env = try lmdb.Env.open("db", 1024 * 1024 * 1);
515 var txn = try env.txn();
516 defer txn.commit() catch {};
518 var dbi = try txn.dbi("ghi");
521 ml: SetList(usize, usize),
524 var a: A = undefined;
525 const a_idx: u64 = 27;
526 if (try dbi.has(a_idx)) {
527 a = try dbi.get(a_idx, A);
529 a = A{ .ml = try SetList(usize, usize).init(txn) };
530 try dbi.put(a_idx, a);
533 var ml = try a.ml.open(txn);
535 const len = ml.len();
536 std.debug.print("{}\n", .{len});
537 try ml.append(len, len * 10);
538 std.debug.print("{}\n", .{try ml.get(len)});
539 var it = ml.iterator();
540 while (it.next()) |i| {
541 std.debug.print("{}: {}\n", .{ i.key, i.val });