From: patrick-scho Date: Sat, 2 Nov 2024 11:02:36 +0000 (+0100) Subject: update db X-Git-Url: https://gitweb.ps.run/chirp/commitdiff_plain/70691a7e0bcb55fe1b9a57fd2b0a57358c999262?ds=inline update db --- diff --git a/src/main.zig b/src/main.zig index 1871dcc..eeada2b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,89 +3,20 @@ const lmdb = @import("lmdb"); // db {{{ -const Db = struct { - const Self = @This(); - - env: ?*lmdb.MDB_env = undefined, - txn: ?*lmdb.MDB_txn = undefined, - dbi: lmdb.MDB_dbi = undefined, +const Prng = struct { prng: std.Random.DefaultPrng = std.Random.DefaultPrng.init(0), - pub fn gen_id(self: *Self) Id { + pub fn gen_id(self: *Prng, dbi: anytype) Id { var id = self.prng.next(); - while (self.has(id)) { + while (dbi.has(id)) { id = self.prng.next(); } return id; } - - pub fn open(self: *Self, name: [*c]const u8) void { - _ = lmdb.mdb_env_create(&self.env); - _ = lmdb.mdb_env_set_maxdbs(self.env, 10); - _ = lmdb.mdb_env_set_mapsize(self.env, 1024 * 1024 * 1); - _ = lmdb.mdb_env_open(self.env, name, lmdb.MDB_WRITEMAP, 0o664); - // _ = lmdb.mdb_env_open(self.env, name, lmdb.MDB_NOSYNC | lmdb.MDB_WRITEMAP, 0o664); - } - - pub fn close(self: *Self) void { - lmdb.mdb_env_close(self.env); - } - - pub fn begin(self: *Self, name: [*c]const u8) void { - switch (lmdb.mdb_txn_begin(self.env, null, 0, &self.txn)) { - 0 => {}, - else => |err| { - std.debug.print("txn err: {}\n", .{err}); - }, - } - - // TODO: lmdb.MDB_INTEGERKEY? - _ = lmdb.mdb_dbi_open(self.txn, name, lmdb.MDB_CREATE, &self.dbi); - } - - pub fn commit(self: *Self) void { - switch (lmdb.mdb_txn_commit(self.txn)) { - 0 => {}, - lmdb.MDB_MAP_FULL => { - std.debug.print("resize\n", .{}); - _ = lmdb.mdb_env_set_mapsize(self.env, 0); - }, - else => |err| { - std.debug.print("commit err: {}\n", .{err}); - }, - } - - // TODO: necessary? - lmdb.mdb_dbi_close(self.env, self.dbi); - } - - pub fn sync(self: *Self) void { - switch (lmdb.mdb_env_sync(self.env, 1)) { - 0 => {}, - else => |err| { - std.debug.print("sync err: {}\n", .{err}); - }, - } - } - - pub fn put(self: *Self, key: anytype, value: anytype) void { - lmdb.put(self.txn, self.dbi, key, value); - } - - pub fn get(self: *Self, key: anytype, comptime T: type) ?T { - return lmdb.get(self.txn, self.dbi, key, T); - } - - pub fn del(self: *Self, key: anytype) void { - lmdb.del(self.txn, self.dbi, key); - } - - pub fn has(self: *Self, key: anytype) bool { - return lmdb.has(self.txn, self.dbi, key); - } }; +var prng = Prng{}; // }}} @@ -180,99 +111,120 @@ pub fn verify_password(password: []const u8, hash: PasswordHash) bool { } } -pub fn register_user(db: *Db, username: []const u8, password: []const u8) !void { +pub fn register_user(env: *lmdb.Env, username: []const u8, password: []const u8) !void { const username_array = try Username.fromSlice(username); - db.begin("users"); - const user_id = db.gen_id(); - db.put(user_id, User{ - .username = username_array, - .password_hash = try hash_password(password), - }); - db.commit(); + var user_id: Id = undefined; - db.begin("ids"); - db.put(username_array.buffer, user_id); - db.commit(); + if (env.txn()) |*txn| { + defer txn.commit(); + if (txn.dbi("users", Id, User)) |users| { + user_id = prng.gen_id(users); + users.put(user_id, User{ + .username = username_array, + .password_hash = try hash_password(password), + }); + } + } - std.debug.print("id: {}\n", .{user_id}); + if (env.txn()) |txn| { + defer txn.commit(); + if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { + user_ids.put(username_array.buffer, user_id); + } + } - db.sync(); + env.sync(); } -pub fn login_user(db: *Db, username: []const u8, password: []const u8) ?SessionToken { +pub fn login_user(env: *lmdb.Env, username: []const u8, password: []const u8) ?SessionToken { const username_array = Username.fromSlice(username) catch return null; - db.begin("ids"); - const user_id = db.get(username_array.buffer, Id) orelse return null; - std.debug.print("id: {}\n", .{user_id}); - // TODO: maybe no commit? - db.commit(); + var user_id_maybe: ?Id = null; + var user_maybe: ?User = null; - db.begin("users"); - const user = db.get(user_id, User) orelse return null; - db.commit(); - - if (verify_password(password, user.password_hash)) { - db.begin("sessions"); - const session_token = db.gen_id(); - db.put(session_token, user_id); - db.commit(); + if (env.txn()) |txn| { + defer txn.abort(); + if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { + user_id_maybe = user_ids.get(username_array.buffer); + std.debug.print("id: {?}\n", .{user_id_maybe}); + } + } - db.sync(); + if (user_id_maybe) |user_id| { + if (env.txn()) |txn| { + defer txn.abort(); + if (txn.dbi("users", Id, User)) |users| { + user_maybe = users.get(user_id_maybe.?); + } + } - return session_token; - } else { - return null; + if (user_maybe) |user| { + if (verify_password(password, user.password_hash)) { + if (env.txn()) |txn| { + defer txn.commit(); + if (txn.dbi("sessions", Id, Id)) |sessions| { + const session_token = prng.gen_id(sessions); + sessions.put(session_token, user_id); + return session_token; + } + } + } + } } + + return null; } -fn logout_user(db: *Db, session_token: SessionToken) void { - db.begin("sessions"); - db.del(session_token); - db.commit(); +fn logout_user(env: *lmdb.Env, session_token: SessionToken) void { + if (env.txn()) |txn| { + defer txn.commit(); + if (txn.dbi("sessions", Id, Id)) |sessions| { + sessions.del(session_token); + } + } } -fn get_session_user(db: *Db, session_token: SessionToken) ?User { - db.begin("sessions"); - const user_id = db.get(session_token, Id) orelse return null; - db.commit(); +fn get_session_user(env: *lmdb.Env, session_token: SessionToken) ?User { + var user_id_maybe: ?Id = null; + + if (env.txn()) |txn| { + defer txn.abort(); + if (txn.dbi("sessions", Id, Id)) |sessions| { + user_id_maybe = sessions.get(session_token); + } + } - db.begin("users"); - const user = db.get(user_id, User) orelse return null; - db.commit(); + if (user_id_maybe) |user_id| { + if (env.txn()) |txn| { + defer txn.abort(); + if (txn.dbi("users", Id, User)) |users| { + return users.get(user_id); + } + } + } - return user; + return null; } // }}} -fn list_users(db: *Db) void { - _ = lmdb.mdb_txn_begin(db.env, null, 0, &db.txn); - - _ = lmdb.mdb_dbi_open(db.txn, "users", lmdb.MDB_CREATE, &db.dbi); +fn list_users(env: *lmdb.Env) void { + if (env.txn()) |txn| { + defer txn.abort(); + if (txn.dbi("users", Id, User)) |users| { + var cursor = users.cursor(); - var cursor: ?*lmdb.MDB_cursor = undefined; - _ = lmdb.mdb_cursor_open(db.txn, db.dbi, &cursor); + var key: Id = undefined; + var user_maybe = cursor.get(&key, .First); - var key: lmdb.MDB_val = undefined; - var val: lmdb.MDB_val = undefined; - var result = lmdb.mdb_cursor_get(cursor, &key, &val, lmdb.MDB_FIRST); + while (user_maybe) |user| { + std.debug.print("[{}] {s}\n", .{ key, user.username.constSlice() }); - while (result != lmdb.MDB_NOTFOUND) { - const user_id = @as(*align(1) Id, @ptrCast(key.mv_data.?)).*; - const user = @as(*align(1) User, @ptrCast(val.mv_data.?)).*; - - std.debug.print("[{}] {s}\n", .{ user_id, user.username.constSlice() }); - - result = lmdb.mdb_cursor_get(cursor, &key, &val, lmdb.MDB_NEXT); + user_maybe = cursor.get(&key, .Next); + } + } } - - _ = lmdb.mdb_cursor_close(cursor); - - _ = lmdb.mdb_dbi_close(db.env, db.dbi); - - _ = lmdb.mdb_txn_commit(db.txn); } pub fn main() !void { @@ -285,11 +237,10 @@ pub fn main() !void { defer server.deinit(); // lmdb - var db = Db{}; - db.open("./db"); - defer db.close(); + var env = lmdb.Env.open("db", 1024 * 1024 * 10); + defer env.close(); - list_users(&db); + list_users(&env); accept: while (true) { const conn = try server.accept(); @@ -311,7 +262,7 @@ pub fn main() !void { if (get_cookie(&req, "session_token")) |session_token_str| { const session_token = try std.fmt.parseUnsigned(SessionToken, session_token_str.constSlice(), 10); - if (get_session_user(&db, session_token)) |user| { + if (get_session_user(&env, session_token)) |user| { logged_in = .{ .user = user, .session_token = session_token, @@ -365,7 +316,7 @@ pub fn main() !void { const password = get_value(&req, "password").?; std.debug.print("New user: {s} {s}\n", .{ username, password }); - try register_user(&db, username, password); + try register_user(&env, username, password); try redirect(&req, "/login"); } else if (std.mem.eql(u8, req.head.target, "/login")) { @@ -374,7 +325,7 @@ pub fn main() !void { const password = get_value(&req, "password").?; std.debug.print("New login: {s} {s}\n", .{ username, password }); - if (login_user(&db, username, password)) |session_token| { + if (login_user(&env, username, password)) |session_token| { var redirect_buffer = try std.BoundedArray(u8, 128).init(0); try std.fmt.format(redirect_buffer.writer(), "/user/{s}", .{username}); @@ -393,7 +344,7 @@ pub fn main() !void { } } else if (std.mem.eql(u8, req.head.target, "/logout")) { if (logged_in) |login| { - logout_user(&db, login.session_token); + logout_user(&env, login.session_token); try req.respond("", .{ .status = .see_other, .extra_headers = &.{