@@ -5,6 +5,7 @@ const log = std.log.scoped(.index);
5
5
const zul = @import ("zul" );
6
6
7
7
const Deadline = @import ("utils/Deadline.zig" );
8
+ const Scheduler = @import ("utils/Scheduler.zig" );
8
9
const Change = @import ("change.zig" ).Change ;
9
10
const SearchResult = @import ("common.zig" ).SearchResult ;
10
11
const SearchResults = @import ("common.zig" ).SearchResults ;
@@ -43,6 +44,7 @@ const Options = struct {
43
44
44
45
options : Options ,
45
46
allocator : std.mem.Allocator ,
47
+ scheduler : * Scheduler ,
46
48
47
49
dir : std.fs.Dir ,
48
50
@@ -66,16 +68,9 @@ memory_segments_lock: std.Thread.Mutex = .{},
66
68
// Mutex used to control linearity of updates.
67
69
update_lock : std.Thread.Mutex = .{},
68
70
69
- stopping : std .atomic .Value (bool ),
70
-
71
- checkpoint_event : std.Thread.ResetEvent = .{},
72
- checkpoint_thread : ? std.Thread = null ,
73
-
74
- file_segment_merge_event : std.Thread.ResetEvent = .{},
75
- file_segment_merge_thread : ? std.Thread = null ,
76
-
77
- memory_segment_merge_event : std.Thread.ResetEvent = .{},
78
- memory_segment_merge_thread : ? std.Thread = null ,
71
+ checkpoint_task : ? Scheduler.Task = null ,
72
+ file_segment_merge_task : ? Scheduler.Task = null ,
73
+ memory_segment_merge_task : ? Scheduler.Task = null ,
79
74
80
75
fn getFileSegmentSize (segment : SharedPtr (FileSegment )) usize {
81
76
return segment .value .getSize ();
@@ -85,7 +80,7 @@ fn getMemorySegmentSize(segment: SharedPtr(MemorySegment)) usize {
85
80
return segment .value .getSize ();
86
81
}
87
82
88
- pub fn init (allocator : std.mem.Allocator , parent_dir : std.fs.Dir , path : []const u8 , options : Options ) ! Self {
83
+ pub fn init (allocator : std.mem.Allocator , scheduler : * Scheduler , parent_dir : std.fs.Dir , path : []const u8 , options : Options ) ! Self {
89
84
var dir = try parent_dir .makeOpenPath (path , .{ .iterate = true });
90
85
errdefer dir .close ();
91
86
@@ -120,22 +115,29 @@ pub fn init(allocator: std.mem.Allocator, parent_dir: std.fs.Dir, path: []const
120
115
return .{
121
116
.options = options ,
122
117
.allocator = allocator ,
118
+ .scheduler = scheduler ,
123
119
.dir = dir ,
124
120
.oplog = oplog ,
125
121
.segments_lock = .{},
126
122
.memory_segments = memory_segments ,
127
123
.file_segments = file_segments ,
128
- .stopping = std .atomic .Value (bool ).init (false ),
129
124
};
130
125
}
131
126
132
127
pub fn deinit (self : * Self ) void {
133
128
log .info ("closing index {}" , .{@intFromPtr (self )});
134
- self .stopping .store (true , .release );
135
129
136
- self .stopCheckpointThread ();
137
- self .stopMemorySegmentMergeThread ();
138
- self .stopFileSegmentMergeThread ();
130
+ if (self .checkpoint_task ) | task | {
131
+ self .scheduler .destroyTask (task );
132
+ }
133
+
134
+ if (self .memory_segment_merge_task ) | task | {
135
+ self .scheduler .destroyTask (task );
136
+ }
137
+
138
+ if (self .file_segment_merge_task ) | task | {
139
+ self .scheduler .destroyTask (task );
140
+ }
139
141
140
142
self .memory_segments .deinit (self .allocator , .keep );
141
143
self .file_segments .deinit (self .allocator , .keep );
@@ -221,45 +223,30 @@ fn doCheckpoint(self: *Self) !bool {
221
223
self .file_segments .commitUpdate (& file_segments_update );
222
224
223
225
if (self .file_segments .needsMerge ()) {
224
- self .file_segment_merge_event .set ();
226
+ if (self .file_segment_merge_task ) | task | {
227
+ self .scheduler .scheduleTask (task );
228
+ }
225
229
}
226
230
227
231
return true ;
228
232
}
229
233
230
- fn checkpointThreadFn (self : * Self ) void {
231
- log .debug ("checkpoint thread started" , .{});
232
- while (! self .stopping .load (.acquire )) {
233
- if (self .doCheckpoint ()) | successful | {
234
- if (successful ) {
235
- continue ;
236
- }
237
- self .checkpoint_event .reset ();
238
- } else | err | {
239
- log .err ("checkpoint failed: {}" , .{err });
240
- }
241
- log .debug ("waiting for checkpoint event" , .{});
242
- self .checkpoint_event .timedWait (std .time .ns_per_min ) catch continue ;
243
- }
244
- log .debug ("checkpoint thread stopped" , .{});
234
+ fn checkpointTask (self : * Self ) void {
235
+ _ = self .doCheckpoint () catch | err | {
236
+ log .err ("checkpoint failed: {}" , .{err });
237
+ };
245
238
}
246
239
247
- fn startCheckpointThread (self : * Self ) ! void {
248
- if (self .checkpoint_thread != null ) return ;
249
-
250
- log .info ("starting checkpoint thread" , .{});
251
- self .checkpoint_thread = try std .Thread .spawn (.{}, checkpointThreadFn , .{self });
240
+ fn memorySegmentMergeTask (self : * Self ) void {
241
+ _ = self .maybeMergeMemorySegments () catch | err | {
242
+ log .err ("memory segment merge failed: {}" , .{err });
243
+ };
252
244
}
253
245
254
- fn stopCheckpointThread (self : * Self ) void {
255
- log .info ("stopping checkpoint thread" , .{});
256
- if (self .checkpoint_thread ) | thread | {
257
- self .checkpoint_event .set ();
258
- log .debug ("waiting for checkpoint thread to exit" , .{});
259
- thread .join ();
260
- }
261
- log .debug ("checkpoint thread stopped" , .{});
262
- self .checkpoint_thread = null ;
246
+ fn fileSegmentMergeTask (self : * Self ) void {
247
+ _ = self .maybeMergeFileSegments () catch | err | {
248
+ log .err ("file segment merge failed: {}" , .{err });
249
+ };
263
250
}
264
251
265
252
fn updateManifestFile (self : * Self , segments : * FileSegmentList ) ! void {
@@ -303,22 +290,6 @@ fn fileSegmentMergeThreadFn(self: *Self) void {
303
290
}
304
291
}
305
292
306
- fn startFileSegmentMergeThread (self : * Self ) ! void {
307
- if (self .file_segment_merge_thread != null ) return ;
308
-
309
- log .info ("starting file segment merge thread" , .{});
310
- self .file_segment_merge_thread = try std .Thread .spawn (.{}, fileSegmentMergeThreadFn , .{self });
311
- }
312
-
313
- fn stopFileSegmentMergeThread (self : * Self ) void {
314
- log .info ("stopping file segment merge thread" , .{});
315
- if (self .file_segment_merge_thread ) | thread | {
316
- self .file_segment_merge_event .set ();
317
- thread .join ();
318
- }
319
- self .file_segment_merge_thread = null ;
320
- }
321
-
322
293
fn maybeMergeMemorySegments (self : * Self ) ! bool {
323
294
var upd = try self .memory_segments .prepareMerge (self .allocator ) orelse return false ;
324
295
defer self .memory_segments .cleanupAfterUpdate (self .allocator , & upd );
@@ -335,43 +306,12 @@ fn maybeMergeMemorySegments(self: *Self) !bool {
335
306
return true ;
336
307
}
337
308
338
- fn memorySegmentMergeThreadFn (self : * Self ) void {
339
- while (! self .stopping .load (.acquire )) {
340
- if (self .maybeMergeMemorySegments ()) | successful | {
341
- if (successful ) {
342
- continue ;
343
- }
344
- self .memory_segment_merge_event .reset ();
345
- } else | err | {
346
- log .err ("memory segment merge failed: {}" , .{err });
347
- }
348
- self .memory_segment_merge_event .timedWait (std .time .ns_per_min ) catch continue ;
349
- }
350
- }
351
-
352
- fn startMemorySegmentMergeThread (self : * Self ) ! void {
353
- if (self .memory_segment_merge_thread != null ) return ;
354
-
355
- log .info ("starting memory segment merge thread" , .{});
356
- self .memory_segment_merge_thread = try std .Thread .spawn (.{}, memorySegmentMergeThreadFn , .{self });
357
- }
358
-
359
- fn stopMemorySegmentMergeThread (self : * Self ) void {
360
- log .info ("stopping memory segment merge thread" , .{});
361
- if (self .memory_segment_merge_thread ) | thread | {
362
- self .memory_segment_merge_event .set ();
363
- thread .join ();
364
- }
365
- self .memory_segment_merge_thread = null ;
366
- }
367
-
368
309
pub fn open (self : * Self , create : bool ) ! void {
369
310
const last_commit_id = try self .loadSegments (create );
370
311
371
- // start these threads after loading file segments, but before replaying oplog to memory segments
372
- try self .startFileSegmentMergeThread ();
373
- try self .startMemorySegmentMergeThread ();
374
- try self .startCheckpointThread ();
312
+ self .checkpoint_task = try self .scheduler .createTask (.medium , checkpointTask , self );
313
+ self .memory_segment_merge_task = try self .scheduler .createTask (.high , memorySegmentMergeTask , self );
314
+ self .file_segment_merge_task = try self .scheduler .createTask (.low , fileSegmentMergeTask , self );
375
315
376
316
try self .oplog .open (last_commit_id + 1 , updateInternal , self );
377
317
@@ -381,7 +321,9 @@ pub fn open(self: *Self, create: bool) !void {
381
321
fn maybeScheduleCheckpoint (self : * Self ) void {
382
322
if (self .memory_segments .segments .value .getFirst ()) | first_node | {
383
323
if (first_node .value .getSize () >= self .options .min_segment_size ) {
384
- self .checkpoint_event .set ();
324
+ if (self .checkpoint_task ) | task | {
325
+ self .scheduler .scheduleTask (task );
326
+ }
385
327
}
386
328
}
387
329
}
@@ -421,7 +363,9 @@ pub fn updateInternal(self: *Self, changes: []const Change, commit_id: ?u64) !vo
421
363
self .memory_segments .commitUpdate (& upd );
422
364
423
365
if (self .memory_segments .needsMerge ()) {
424
- self .memory_segment_merge_event .set ();
366
+ if (self .memory_segment_merge_task ) | task | {
367
+ self .scheduler .scheduleTask (task );
368
+ }
425
369
}
426
370
}
427
371
0 commit comments