| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- const std = @import("std");
- var wal_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
- const wal_allocator = wal_arena.allocator();
- pub fn compactUPKVFile(filename: []const u8) !void {
- const extension = std.fs.path.extension(filename);
- if (!std.mem.eql(u8, extension, "upkv")) {
- std.debug.print("Invalid file extension: {s}\n", .{extension});
- return;
- }
- const records = try getRecordsFromFile(filename);
- const compactedRecords = compact(records);
- for (compactedRecords) |record| {
- std.debug.print("{s}\n", .{record});
- }
- }
- test "compactUPKVFile test" {}
- pub fn getRecordsFromFile(filename: []const u8) ![]const []const u8 {
- const cwd = std.fs.cwd();
- var upkv: ?std.fs.File = null;
- upkv = cwd.openFile(filename, .{ .mode = .read_only }) catch |err| {
- std.debug.print("Failed to open file: {any}\n", .{err});
- return err;
- };
- const upkvData = upkv.?.readToEndAlloc(wal_allocator, 10_000_000 * 100) catch |err| {
- std.debug.print("Failed to read file: {any}\n", .{err});
- return err;
- };
- var records = std.ArrayListUnmanaged([]const u8){};
- var it = std.mem.splitScalar(u8, upkvData, '\r');
- while (it.next()) |record| {
- if (record.len > 0) {
- try records.append(wal_allocator, record);
- }
- }
- return records.items;
- }
- test "getRecordsFromFile test" {
- var tmp_dir = std.testing.tmpDir(.{});
- defer tmp_dir.cleanup();
- const file = try tmp_dir.dir.createFile("test.upkv", .{});
- defer file.close();
- try file.writeAll("W|key1|value1\rD|key2|\rW|key3|value3");
- var path_buf: [std.fs.max_path_bytes]u8 = undefined;
- const tmp_path = try tmp_dir.dir.realpath(".", &path_buf);
- const full_path = try std.fmt.allocPrint(std.testing.allocator, "{s}/test.upkv", .{tmp_path});
- defer std.testing.allocator.free(full_path);
- const records = try getRecordsFromFile(full_path);
- try std.testing.expect(records.len == 3);
- try std.testing.expectEqualStrings("W|key1|value1", records[0]);
- try std.testing.expectEqualStrings("D|key2|", records[1]);
- try std.testing.expectEqualStrings("W|key3|value3", records[2]);
- }
- pub fn compact(records: []const []const u8) []const []const u8 {
- var compactMap = std.StringHashMap([]const u8).init(wal_allocator);
- for (records) |record| {
- var parts = std.mem.splitScalar(u8, record, '|');
- const opcode = parts.next() orelse continue;
- const key = parts.next() orelse continue;
- const value = parts.next() orelse "";
- if (std.mem.eql(u8, opcode, "D")) {
- _ = compactMap.remove(key);
- } else if (std.mem.eql(u8, opcode, "W")) {
- compactMap.put(key, value) catch continue;
- }
- }
- var compactedRecords = std.ArrayListUnmanaged([]const u8){};
- var it = compactMap.iterator();
- while (it.next()) |entry| {
- const record = std.fmt.allocPrint(wal_allocator, "W|{s}|{s}", .{ entry.key_ptr.*, entry.value_ptr.* }) catch continue;
- compactedRecords.append(wal_allocator, record) catch continue;
- }
- return compactedRecords.items;
- }
- test "compaction test" {
- const records = &[_][]const u8{
- "W|key1|value1v1",
- "W|key1|value1v2",
- "W|key2|value2v1",
- "D|key2|",
- "W|key3|value3v1",
- "W|key4|value4v1",
- "D|key4|",
- };
- const compactedExpected = &[_][]const u8{
- "W|key1|value1v2",
- "W|key3|value3v1",
- };
- const compacted = compact(records[0..]);
- for (compacted, 0..) |record, i| {
- try std.testing.expectEqualStrings(compactedExpected[i], record);
- }
- }
|