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(null);
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 gen(self: @This()) !Key {
150 const key = try Prng.gen(self.dbi, Key);
151 if (!try self.dbi.has(self.item_idx(key))) {
156 fn item_idx(self: Self, k: K) ItemIndex {
157 return .{ self.idx, k };
159 fn item_get(self: Self, k: K) !Item {
160 return try self.dbi.get(self.item_idx(k), Item);
162 fn item_put(self: Self, k: K, item: Item) !void {
163 try self.dbi.put(self.item_idx(k), item);
165 fn head_update(self: Self) !void {
166 try self.dbi.put(self.idx, self.head);
168 pub fn del(self: *Self, k: K) !void {
169 const item = try self.item_get(k);
171 if (item.prev != null) {
172 var prev = try self.item_get(item.prev.?);
173 prev.next = item.next;
174 try self.item_put(item.prev.?, prev);
177 if (item.next != null) {
178 var next = try self.item_get(item.next.?);
179 next.prev = item.prev;
180 try self.item_put(item.next.?, next);
183 if (std.meta.eql(self.head.first, k)) self.head.first = item.next;
184 if (std.meta.eql(self.head.last, k)) self.head.last = item.prev;
186 try self.head_update();
188 try self.dbi.del(self.item_idx(k));
190 pub fn clear(self: *Self) !void {
191 var it = self.iterator();
192 while (it.next()) |kv| {
193 try self.del(kv.key);
196 pub fn len(self: Self) usize {
197 return self.head.len;
199 pub fn append(self: *Self, key: Key, val: Val) !void {
200 if (self.head.len == 0) {
201 const item = Item{ .data = val };
202 try self.item_put(key, item);
205 self.head.first = key;
206 self.head.last = key;
207 try self.head_update();
209 const prev_idx = self.head.last.?;
210 var prev = try self.item_get(prev_idx);
212 const item = Item{ .prev = prev_idx, .data = val };
213 try self.item_put(key, item);
216 try self.item_put(prev_idx, prev);
218 self.head.last = key;
220 try self.head_update();
223 pub fn get(self: Self, key: Key) !Val {
224 const item = try self.item_get(key);
227 pub fn has(self: Self, key: Key) !bool {
228 return self.dbi.has(self.item_idx(key));
230 pub const Iterator = struct {
231 pub const Result = struct { key: K, val: V };
233 slv: SetListViewBase(K, V),
235 dir: enum { Forward, Backward },
237 pub fn next(self: *Iterator) ?Result {
238 if (self.idx != null) {
239 const k = self.idx.?;
240 const item = self.slv.item_get(k) catch return null;
241 self.idx = switch (self.dir) {
242 .Forward => item.next,
243 .Backward => item.prev,
245 return .{ .key = k, .val = item.data };
251 pub fn iterator(self: Self) Iterator {
254 .idx = self.head.first,
258 pub fn reverse_iterator(self: Self) Iterator {
261 .idx = self.head.last,
268 pub fn Set(comptime K: type) type {
271 pub const Val = void;
273 pub const Base = SetListBase(Key, Val);
274 pub const View = struct {
275 const ViewBase = SetListViewBase(Key, Val);
279 pub fn del(self: *@This(), key: Key) !void {
280 try self.base.del(key);
282 pub fn clear(self: *@This()) !void {
283 try self.base.clear();
285 pub fn len(self: @This()) usize {
286 return self.base.len();
288 pub fn append(self: *@This(), key: Key) !void {
289 try self.base.append(key, {});
291 pub fn has(self: @This(), key: Key) !bool {
292 return try self.base.has(key);
294 pub fn iterator(self: @This()) ViewBase.Iterator {
295 return self.base.iterator();
297 pub fn reverse_iterator(self: @This()) ViewBase.Iterator {
298 return self.base.reverse_iterator();
304 pub fn init(txn: lmdb.Txn) !@This() {
305 return .{ .base = try Base.init(txn) };
307 pub fn open(self: @This(), txn: lmdb.Txn) !View {
308 return .{ .base = try self.base.open(txn) };
313 pub fn List(comptime V: type) type {
318 pub const Base = SetListBase(Key, Val);
319 pub const View = struct {
320 const ViewBase = SetListViewBase(Key, Val);
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.base.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 });