feat: extend version

This commit is contained in:
dualfroz committed 2026-09-13 14:32:09 +02:00
1 parent a18ad868b9
commit db958c4d5d
1 file changed
+183
+183
View File
@@ -473,3 +473,186 @@ test "manifest rotates once pending records outgrow live file count" {
try opened.set.logAndApply(&edit, &opened.state);
}
var n: usize = 0;
while (n < 20) : (n += 1) {
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.deleteFile(fileId);
fileId += 1;
try edit.addFile(fileId, 0);
try opened.set.logAndApply(&edit, &opened.state);
}
try std.testing.expect(opened.set.manifestId > 1);
try std.testing.expectEqual(@as(usize, 1), opened.state.count());
try std.testing.expectEqual(@as(usize, 0), opened.state.get(fileId).?);
var nameBuf: [64]u8 = undefined;
const oldName = try manifestFileName(&nameBuf, 1);
try std.testing.expectError(error.FileNotFound, tmp.dir.access(oldName, .{}));
}
test "reopen after rotation still reflects live state" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var lastId: u64 = 0;
var finalFileId: u64 = 1;
{
var opened = try VersionSet.open(allocator, tmp.dir);
defer opened.state.deinit();
defer opened.set.close();
{
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.addFile(finalFileId, 0);
try opened.set.logAndApply(&edit, &opened.state);
}
var n: usize = 0;
while (n < 12) : (n += 1) {
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.deleteFile(finalFileId);
finalFileId += 1;
try edit.addFile(finalFileId, 0);
try opened.set.logAndApply(&edit, &opened.state);
}
lastId = opened.set.manifestId;
}
try std.testing.expect(lastId > 1);
var reopened = try VersionSet.open(allocator, tmp.dir);
defer reopened.state.deinit();
defer reopened.set.close();
try std.testing.expectEqual(@as(usize, 1), reopened.state.count());
try std.testing.expectEqual(@as(usize, 0), reopened.state.get(finalFileId).?);
try std.testing.expectEqual(reopened.set.manifestId, lastId);
}
test "torn trailing record is ignored on recovery" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
{
var opened = try VersionSet.open(allocator, tmp.dir);
defer opened.state.deinit();
defer opened.set.close();
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.addFile(7, 0);
try opened.set.logAndApply(&edit, &opened.state);
try opened.set.file.seekFromEnd(0);
try opened.set.file.writeAll(&[_]u8{ 0xde, 0xad, 0xbe });
try opened.set.file.sync();
}
var reopened = try VersionSet.open(allocator, tmp.dir);
defer reopened.state.deinit();
defer reopened.set.close();
try std.testing.expectEqual(@as(usize, 1), reopened.state.count());
try std.testing.expectEqual(@as(usize, 0), reopened.state.get(7).?);
}
test "logAndApply persists nextFileId and nextSeq counters across reopen" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
{
var opened = try VersionSet.open(allocator, tmp.dir);
defer opened.state.deinit();
defer opened.set.close();
try std.testing.expectEqual(@as(?u64, null), opened.set.counters.nextFileId);
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.addFile(1, 0);
edit.setNextFileId(2);
edit.setNextSeq(500);
try opened.set.logAndApply(&edit, &opened.state);
try std.testing.expectEqual(@as(?u64, 2), opened.set.counters.nextFileId);
try std.testing.expectEqual(@as(?u64, 500), opened.set.counters.nextSeq);
}
var reopened = try VersionSet.open(allocator, tmp.dir);
defer reopened.state.deinit();
defer reopened.set.close();
try std.testing.expectEqual(@as(?u64, 2), reopened.set.counters.nextFileId);
try std.testing.expectEqual(@as(?u64, 500), reopened.set.counters.nextSeq);
}
test "counters survive manifest rotation" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var lastId: u64 = 0;
{
var opened = try VersionSet.open(allocator, tmp.dir);
defer opened.state.deinit();
defer opened.set.close();
var fileId: u64 = 1;
{
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.addFile(fileId, 0);
edit.setNextFileId(fileId + 1);
edit.setNextSeq(10);
try opened.set.logAndApply(&edit, &opened.state);
}
// Force rotation the same way the existing rotation test does, each
// round bumping the seq counter so the final persisted value is
// distinguishable from an earlier one if rotation dropped it.
var n: usize = 0;
while (n < 20) : (n += 1) {
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.deleteFile(fileId);
fileId += 1;
try edit.addFile(fileId, 0);
edit.setNextFileId(fileId + 1);
edit.setNextSeq(10 + n + 1);
try opened.set.logAndApply(&edit, &opened.state);
}
lastId = opened.set.manifestId;
try std.testing.expectEqual(@as(?u64, fileId + 1), opened.set.counters.nextFileId);
try std.testing.expectEqual(@as(?u64, 30), opened.set.counters.nextSeq);
}
try std.testing.expect(lastId > 1);
var reopened = try VersionSet.open(allocator, tmp.dir);
defer reopened.state.deinit();
defer reopened.set.close();
try std.testing.expectEqual(@as(?u64, 30), reopened.set.counters.nextSeq);
}
test "missing CURRENT after previous run bootstraps fresh, empty state" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
{
var opened = try VersionSet.open(allocator, tmp.dir);
defer opened.state.deinit();
defer opened.set.close();
var edit = VersionEdit.init(allocator);
defer edit.deinit();
try edit.addFile(1, 0);
try opened.set.logAndApply(&edit, &opened.state);
}
try tmp.dir.deleteFile(currentName);
var reopened = try VersionSet.open(allocator, tmp.dir);
defer reopened.state.deinit();
defer reopened.set.close();
try std.testing.expectEqual(@as(usize, 0), reopened.state.count());
}