Skip to content

Commit 18a1092

Browse files
committed
First version of fully atomic segment list
1 parent 4f65db1 commit 18a1092

File tree

3 files changed

+153
-3
lines changed

3 files changed

+153
-3
lines changed

src/FileSegment.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ pub fn deinit(self: *Self) void {
4949
}
5050
}
5151

52-
pub fn getBlockData(self: *const Self, block: usize) []const u8 {
52+
pub fn getBlockData(self: Self, block: usize) []const u8 {
5353
return self.blocks[block * self.block_size .. (block + 1) * self.block_size];
5454
}
5555

56-
pub fn search(self: *Self, sorted_hashes: []const u32, results: *SearchResults) !void {
56+
pub fn search(self: Self, sorted_hashes: []const u32, results: *SearchResults) !void {
5757
var prev_block_no: usize = std.math.maxInt(usize);
5858
var prev_block_range_start: usize = 0;
5959

src/MemorySegment.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn deinit(self: *Self) void {
3737
self.items.deinit();
3838
}
3939

40-
pub fn search(self: *Self, sorted_hashes: []const u32, results: *SearchResults) !void {
40+
pub fn search(self: Self, sorted_hashes: []const u32, results: *SearchResults) !void {
4141
var items = self.items.items;
4242
for (sorted_hashes) |hash| {
4343
const matches = std.sort.equalRange(Item, Item{ .hash = hash, .id = 0 }, items, {}, Item.cmpByHash);

src/segment_list.zig

+150
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,153 @@ pub const SegmentMergeOptions = struct {
228228
}
229229
}
230230
};
231+
232+
const MemorySegment = @import("MemorySegment.zig");
233+
const FileSegment = @import("FileSegment.zig");
234+
235+
pub const AnySegment = union(enum) {
236+
file: FileSegment,
237+
memory: MemorySegment,
238+
239+
pub fn search(self: AnySegment, sorted_hashes: []const u32, results: *SearchResults) !void {
240+
switch (self) {
241+
.file => |segment| try segment.search(sorted_hashes, results),
242+
.memory => |segment| try segment.search(sorted_hashes, results),
243+
}
244+
}
245+
246+
pub fn getMaxCommitId(self: AnySegment) u64 {
247+
switch (self) {
248+
.file => |segment| return segment.max_commit_id,
249+
.memory => |segment| return segment.max_commit_id,
250+
}
251+
}
252+
};
253+
254+
pub const AnySegmentNode = struct {
255+
segment: AnySegment,
256+
refs: std.atomic.Value(u32),
257+
next: std.atomic.Value(?*AnySegmentNode),
258+
259+
pub fn create(comptime Segment: type, allocator: std.mem.Allocator) !*AnySegmentNode {
260+
const result = try allocator.create(AnySegmentNode);
261+
errdefer allocator.destroy(result);
262+
263+
result.* = .{
264+
.segment = undefined,
265+
.refs = std.atomic.Value(u32).init(0),
266+
.next = std.atomic.Value(?*AnySegmentNode).init(null),
267+
};
268+
269+
inline for (@typeInfo(AnySegment).Union.fields) |f| {
270+
if (f.type == Segment) {
271+
result.segment = @unionInit(AnySegment, f.name, Segment.init(allocator));
272+
break;
273+
}
274+
} else {
275+
@compileError("Unknown segment type '" ++ @typeName(Segment) ++ "'");
276+
}
277+
278+
return result;
279+
}
280+
281+
pub fn destroy(self: *AnySegmentNode, allocator: std.mem.Allocator) void {
282+
const refs = self.refs.load(.acquire);
283+
if (refs != 0) {
284+
std.debug.panic("trying to destroy segment with {} reference(s)", .{refs});
285+
}
286+
allocator.destroy(self);
287+
}
288+
289+
pub fn ref(self: *AnySegmentNode) void {
290+
_ = self.refs.fetchAdd(1, .release);
291+
}
292+
293+
pub fn unref(self: *AnySegmentNode) void {
294+
_ = self.refs.fetchSub(1, .release);
295+
}
296+
297+
pub fn search(self: *AnySegmentNode, sorted_hashes: []const u32, results: *SearchResults) !void {
298+
self.ref();
299+
defer self.unref();
300+
return self.segment.search(sorted_hashes, results);
301+
}
302+
303+
pub fn getMaxCommitId(self: *AnySegmentNode) u64 {
304+
self.ref();
305+
defer self.unref();
306+
return self.segment.getMaxCommitId();
307+
}
308+
};
309+
310+
pub const AnySegmentList = struct {
311+
allocator: std.mem.Allocator,
312+
head: std.atomic.Value(?*AnySegmentNode),
313+
314+
pub fn init(allocator: std.mem.Allocator) AnySegmentList {
315+
return .{
316+
.allocator = allocator,
317+
.head = std.atomic.Value(?*AnySegmentNode).init(null),
318+
};
319+
}
320+
321+
pub fn count(self: *AnySegmentList) usize {
322+
var result: usize = 0;
323+
var iter = self.head.load(.acquire);
324+
while (iter) |node| : (iter = node.next.load(.acquire)) {
325+
result += 1;
326+
}
327+
return result;
328+
}
329+
330+
pub fn search(self: *AnySegmentList, sorted_hashes: []const u32, results: *SearchResults, deadline: Deadline) !void {
331+
var iter = self.head.load(.acquire);
332+
while (iter) |node| : (iter = node.next.load(.acquire)) {
333+
if (deadline.isExpired()) {
334+
return error.Timeout;
335+
}
336+
try node.search(sorted_hashes, results);
337+
}
338+
}
339+
340+
pub fn getMaxCommitId(self: *AnySegmentList) u64 {
341+
var result: u64 = 0;
342+
var iter = self.head.load(.acquire);
343+
while (iter) |node| : (iter = node.next.load(.acquire)) {
344+
result = @max(result, node.getMaxCommitId());
345+
}
346+
return result;
347+
}
348+
349+
pub fn prepend(self: *AnySegmentList, node: *AnySegmentNode) void {
350+
var head = self.head.load(.acquire);
351+
while (true) {
352+
node.next.store(head, .release);
353+
head = self.head.cmpxchgWeak(head, node, .seq_cst, .seq_cst) orelse break;
354+
}
355+
}
356+
357+
pub fn swap(self: *AnySegmentList, new_node: *AnySegmentNode, old_node: *AnySegmentNode, old_count: usize) void {
358+
_ = self;
359+
_ = new_node;
360+
_ = old_node;
361+
_ = old_count;
362+
}
363+
};
364+
365+
test "AnySegment" {
366+
var node1 = try AnySegmentNode.create(MemorySegment, std.testing.allocator);
367+
defer node1.destroy(std.testing.allocator);
368+
369+
var node2 = try AnySegmentNode.create(MemorySegment, std.testing.allocator);
370+
defer node2.destroy(std.testing.allocator);
371+
372+
var list = AnySegmentList.init(std.testing.allocator);
373+
list.prepend(node1);
374+
list.swap(node2, node1, 1);
375+
376+
var results = SearchResults.init(std.testing.allocator);
377+
defer results.deinit();
378+
379+
try list.search(&[_]u32{}, &results, .{});
380+
}

0 commit comments

Comments
 (0)