2
0

persistence.zig 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. const std = @import("std");
  2. const storage = @import("storage.zig");
  3. const MAX_PERSISTENCE_SIZE = 10_000_000 * 100;
  4. var storage_file: ?std.fs.File = null;
  5. var thread_pool: std.Thread.Pool = undefined;
  6. var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
  7. const allocator = arena.allocator();
  8. var mutex: std.Thread.Mutex = .{};
  9. pub fn init() !void {
  10. try std.Thread.Pool.init(&thread_pool, .{ .allocator = allocator, .n_jobs = 1024 });
  11. const cwd = std.fs.cwd();
  12. storage_file = cwd.openFile(".db", .{ .mode = .read_write }) catch |err| {
  13. if (err == std.fs.File.OpenError.FileNotFound) {
  14. std.debug.print("No persisted data found, starting fresh...\n", .{});
  15. storage_file = cwd.createFile(".db", .{}) catch |ierr| {
  16. std.debug.print("Failed to create storage file: {any}\n", .{ierr});
  17. return;
  18. };
  19. std.debug.print("Created new storage file .db\n", .{});
  20. }
  21. return;
  22. };
  23. const storage_data = storage_file.?.readToEndAlloc(allocator, MAX_PERSISTENCE_SIZE) catch |err| {
  24. std.debug.print("Failed to read storage file: {any}\n", .{err});
  25. return;
  26. };
  27. defer allocator.free(storage_data);
  28. var records = std.mem.splitScalar(u8, storage_data, '\r');
  29. var record_count: usize = 0;
  30. while (records.next()) |record| {
  31. if (record.len == 0) {
  32. continue;
  33. }
  34. record_count += 1;
  35. std.debug.print("Restoring record N:{d}\r", .{record_count});
  36. var kv = std.mem.splitScalar(u8, record, '|');
  37. const key = kv.first();
  38. const value = kv.rest();
  39. _ = storage.writeVolatile(key, value);
  40. }
  41. std.debug.print("Restored {d} records from persistence", .{record_count});
  42. return;
  43. }
  44. pub fn persist(key: []const u8, value: []const u8) void {
  45. mutex.lock();
  46. const record = std.fmt.allocPrint(allocator, "{s}|{s}\r", .{ key, value }) catch {
  47. std.debug.print("Failed to format record for persistence\n", .{});
  48. mutex.unlock();
  49. return;
  50. };
  51. mutex.unlock();
  52. thread_pool.spawn(persistRecord, .{record}) catch |err| {
  53. std.debug.print("Failed to spawn persistence job: {any}\n", .{err});
  54. return;
  55. };
  56. }
  57. fn persistRecord(record: []const u8) void {
  58. mutex.lock();
  59. defer mutex.unlock();
  60. _ = storage_file.?.write(record) catch |err| {
  61. std.debug.print("Failed to write record to storage file: {any}\n", .{err});
  62. return;
  63. };
  64. }