Expirementation with a new way to finish threads. Currently not working.

This commit is contained in:
Caleb J. Gardner
2026-03-04 06:39:44 -06:00
parent 4515610082
commit edfe919c1b
4 changed files with 224 additions and 136 deletions
+84 -85
View File
@@ -14,8 +14,9 @@ const file = @import("inode_data/file.zig");
const misc = @import("inode_data/misc.zig");
const DataReader = @import("util/data.zig");
const ThreadedDataReader = @import("util/data_threaded.zig");
const InodeFinish = @import("util/inode_finish.zig");
const FinishUnion = InodeFinish.FinishUnion;
const MetadataReader = @import("util/metadata.zig");
const XattrTable = @import("xattr.zig");
pub const Ref = packed struct {
block_offset: u16,
@@ -155,7 +156,7 @@ fn entriesFromData(alloc: std.mem.Allocator, archive: Archive, data: anytype) ![
return DirEntry.readDir(alloc, &meta.interface, data.size);
}
/// Returns the xattr index for the given inode. If the inode isn't an extended variant or doesn't have any, the returned value is the max u32 value (0xFFFFFFFF)
/// Returns the xattr index for the given inode. If the inode isn't an extended variant or doesn't have any, the u32 max is returned (0xFFFFFFFF).
pub fn xattrIdx(self: Inode) u32 {
return switch (self.data) {
.ext_dir => |d| d.xattr_id,
@@ -167,7 +168,9 @@ pub fn xattrIdx(self: Inode) u32 {
};
}
inline fn setPermissionAndXattr(self: Inode, alloc: std.mem.Allocator, archive: *Archive, fil: std.fs.File, options: ExtractionOptions) !void {
/// Applies the Inode's metadata to the given File.
/// Mod time is always set, but permissions and xattrs are set based on the given ExtractionOptions.
pub fn setMetadata(self: Inode, alloc: std.mem.Allocator, archive: *Archive, fil: std.fs.File, options: ExtractionOptions) !void {
const time = @as(i128, self.hdr.mod_time) * 1000000000;
try fil.updateTimes(time, time);
if (!options.ignore_permissions) {
@@ -223,7 +226,7 @@ pub fn extractTo(self: Inode, alloc: std.mem.Allocator, archive: *Archive, path:
var fil = try std.fs.cwd().openFile(path, .{});
defer fil.close();
try self.setPermissionAndXattr(alloc, archive, fil, options);
try self.setMetadata(alloc, archive, fil, options);
},
.file, .ext_file => try self.extractRegFile(alloc, archive, path, options),
.symlink, .ext_symlink => try self.extractSymlink(path),
@@ -231,46 +234,6 @@ pub fn extractTo(self: Inode, alloc: std.mem.Allocator, archive: *Archive, path:
}
}
const Parent = struct {
alloc: std.mem.Allocator,
inode: Inode,
path: []const u8,
archive: *Archive,
options: ExtractionOptions,
wg: WaitGroup = .{},
mut: Mutex = .{},
fn create(alloc: std.mem.Allocator, inode: Inode, path: []const u8, archive: *Archive, options: ExtractionOptions, dir_size: usize) !*Parent {
const out = try alloc.create(Parent);
errdefer alloc.destroy(out);
out.* = .{
.alloc = alloc,
.inode = inode,
.path = path,
.archive = archive,
.options = options,
};
out.wg.startMany(dir_size);
return out;
}
fn finish(p: *Parent) !void {
p.mut.lock();
{
defer p.mut.unlock();
p.wg.finish();
if (!p.wg.isDone()) return;
}
defer p.alloc.destroy(p);
var fil = try std.fs.cwd().openFile(p.path, .{});
defer fil.close();
try p.inode.setPermissionAndXattr(p.alloc, p.archive, fil, p.options);
}
};
/// Extract the inode to the given path. Multi-threaded.
/// Functions identically to extractTo on all but regular files and directories.
fn extractToThreaded(self: Inode, allocator: std.mem.Allocator, archive: *Archive, path: []const u8, options: ExtractionOptions) !void {
@@ -294,13 +257,13 @@ fn extractToThreaded(self: Inode, allocator: std.mem.Allocator, archive: *Archiv
var out_err: ?anyerror = null;
wg.start();
self.extractThread(alloc, archive, path, options, &wg, &pool, &out_err, null);
self.extractThread(alloc, archive, path, options, .{ .wg = &wg }, &pool, &out_err);
pool.waitAndWork(&wg);
if (out_err != null) return out_err.?;
var fil = try std.fs.cwd().openFile(path, .{});
defer fil.close();
try self.setPermissionAndXattr(alloc, archive, fil, options);
try self.setMetadata(alloc, archive, fil, options);
},
.file, .ext_file => {
var pool: Pool = undefined;
@@ -314,11 +277,17 @@ fn extractToThreaded(self: Inode, allocator: std.mem.Allocator, archive: *Archiv
var thread_alloc: std.heap.ThreadSafeAllocator = .{ .child_allocator = arena_alloc.allocator() };
const alloc = thread_alloc.allocator();
try self.extractRegFileThreaded(alloc, archive, path, options, &pool);
var wg: WaitGroup = .{};
var out_err: ?anyerror = null;
self.extractThread(alloc, archive, path, options, .{ .wg = &wg }, &pool, &out_err);
pool.waitAndWork(&wg);
if (out_err != null) return out_err.?;
var fil = try std.fs.cwd().openFile(path, .{});
defer fil.close();
try self.setPermissionAndXattr(alloc, archive, fil, options);
try self.setMetadata(alloc, archive, fil, options);
},
.symlink, .ext_symlink => try self.extractSymlink(path),
else => try self.extractDevice(allocator, archive, path, options),
@@ -331,13 +300,12 @@ fn extractThreadEntry(
archive: *Archive,
path: []const u8,
options: ExtractionOptions,
wg: *WaitGroup,
finish: FinishUnion,
pool: *Pool,
out_err: *?anyerror,
parent: ?*Parent,
) void {
var new_path = alloc.alloc(u8, path.len + entry.name.len + 1) catch |err| {
wg.finish();
finish.finish();
out_err.* = err;
return;
};
@@ -346,10 +314,10 @@ fn extractThreadEntry(
new_path[path.len] = '/';
var inode = readFromEntry(alloc, archive, entry) catch |err| {
out_err.* = err;
wg.finish();
finish.finish();
return;
};
inode.extractThread(alloc, archive, new_path, options, wg, pool, out_err, parent);
inode.extractThread(alloc, archive, new_path, options, finish, pool, out_err);
}
/// Extract threadedly the inode to the path.
@@ -359,21 +327,13 @@ fn extractThread(
archive: *Archive,
path: []const u8,
options: ExtractionOptions,
wg: *WaitGroup,
finish: FinishUnion,
pool: *Pool,
out_err: *?anyerror,
parent: ?*Parent,
) void {
if (options.verbose)
options.verbose_writer.?.print("Extracting inode #{} to {s}\n", .{ self.hdr.num, path }) catch {};
defer {
if (parent != null) parent.?.finish() catch |err| {
if (options.verbose)
options.verbose_writer.?.print("Error setting folder permission to {s}: {}\n", .{ path, err }) catch {};
out_err.* = err;
};
wg.finish();
}
defer finish.finish();
if (out_err.* != null) return;
switch (self.hdr.inode_type) {
.dir, .ext_dir => {
@@ -390,15 +350,35 @@ fn extractThread(
out_err.* = err;
return;
};
const p = Parent.create(alloc, self, path, archive, options, entries.len) catch |err| {
const fin = InodeFinish.create(
alloc,
self,
path,
archive,
options,
finish,
out_err,
null,
entries.len,
) catch |err| {
if (options.verbose)
options.verbose_writer.?.print("Error allocating memory\n", .{}) catch {};
out_err.* = err;
return;
};
wg.startMany(entries.len);
// defer files.deinit(alloc); We don't need to do this due to ArenaAllocator
for (entries) |entry| {
if (entry.inode_type == .dir) {
extractThreadEntry(entry, alloc, archive, path, options, wg, pool, out_err, p);
extractThreadEntry(
entry,
alloc,
archive,
path,
options,
.{ .fin = fin },
pool,
out_err,
);
continue;
}
pool.spawn(
@@ -409,13 +389,12 @@ fn extractThread(
archive,
path,
options,
wg,
FinishUnion{ .fin = fin },
pool,
out_err,
p,
},
) catch |err| {
wg.finish();
fin.finish();
if (options.verbose)
options.verbose_writer.?.print("Error starting extraction thread: {}\n", .{err}) catch {};
out_err.* = err;
@@ -424,10 +403,42 @@ fn extractThread(
}
},
.file, .ext_file => {
self.extractRegFileThreaded(alloc, archive, path, options, pool) catch |err| {
const fil = std.fs.cwd().createFile(path, .{}) catch |err| {
if (options.verbose)
options.verbose_writer.?.print("Error extracting file inode #{} to {s}: {}\n", .{ self.hdr.num, path, err }) catch {};
options.verbose_writer.?.print("Error creating {s}: {}\n", .{ path, err }) catch {};
out_err.* = err;
return;
};
var data = self.threadedDataReader(alloc, archive) catch |err| {
if (options.verbose)
options.verbose_writer.?.print(
"Error creating data reader for inode #{} (extracting to {s}): {}\n",
.{ self.hdr.num, path, err },
) catch {};
out_err.* = err;
return;
};
const fin = InodeFinish.create(
alloc,
self,
path,
archive,
options,
finish,
out_err,
fil,
data.num_blocks,
) catch |err| {
if (options.verbose)
options.verbose_writer.?.print("Error allocating memory\n", .{}) catch {};
out_err.* = err;
return;
};
data.extractThreaded(fil, pool, fin) catch |err| {
if (options.verbose)
options.verbose_writer.?.print("Error spawning threads: {}\n", .{err}) catch {};
out_err.* = err;
return;
};
},
.symlink, .ext_symlink => {
@@ -459,19 +470,7 @@ fn extractRegFile(self: Inode, alloc: std.mem.Allocator, archive: *Archive, path
_ = try dat_rdr.interface.streamRemaining(&wrt.interface);
try wrt.interface.flush();
try self.setPermissionAndXattr(alloc, archive, fil, options);
}
/// Extract the inode file contents to the given path threadedly.
/// pool is used to spawn threads.
///
/// Assumes the inode is a file or ext_file type.
fn extractRegFileThreaded(self: Inode, alloc: std.mem.Allocator, archive: *Archive, path: []const u8, options: ExtractionOptions, pool: *Pool) !void {
var fil = try std.fs.cwd().createFile(path, .{});
defer fil.close();
var data = try self.threadedDataReader(alloc, archive);
try data.extractThreaded(fil, pool);
try self.setPermissionAndXattr(alloc, archive, fil, options);
try self.setMetadata(alloc, archive, fil, options);
}
/// Creates the symlink described by the inode.
///
@@ -533,5 +532,5 @@ fn extractDevice(self: Inode, alloc: std.mem.Allocator, archive: *Archive, path:
}
var fil = try std.fs.cwd().openFile(path, .{});
defer fil.close();
try self.setPermissionAndXattr(alloc, archive, fil, options);
try self.setMetadata(alloc, archive, fil, options);
}