aboutsummaryrefslogtreecommitdiff
path: root/src/fs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig114
1 files changed, 78 insertions, 36 deletions
diff --git a/src/fs.zig b/src/fs.zig
index 32961d171..d35eacff3 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -28,6 +28,17 @@ pub const FileSystem = struct {
dirname_store: *DirnameStore,
filename_store: *FilenameStore,
+
+ pub var max_fd: FileDescriptorType = 0;
+
+ pub inline fn setMaxFd(fd: anytype) void {
+ if (!FeatureFlags.store_file_descriptors) {
+ return;
+ }
+
+ max_fd = std.math.max(fd, max_fd);
+ }
+
pub var instance: FileSystem = undefined;
pub const DirnameStore = allocators.BSSStringList(Preallocate.Counts.dir_entry, 256);
@@ -73,6 +84,7 @@ pub const FileSystem = struct {
pub const EntryMap = std.StringHashMap(EntryStore.ListIndex);
pub const EntryStore = allocators.BSSList(Entry, Preallocate.Counts.files);
dir: string,
+ fd: StoredFileDescriptorType = 0,
data: EntryMap,
pub fn addEntry(dir: *DirEntry, entry: std.fs.Dir.Entry) !void {
@@ -153,7 +165,7 @@ pub const FileSystem = struct {
d.data.deinit();
}
- pub fn get(entry: *DirEntry, _query: string) ?Entry.Lookup {
+ pub fn get(entry: *const DirEntry, _query: string) ?Entry.Lookup {
if (_query.len == 0) return null;
var end: usize = 0;
@@ -354,6 +366,17 @@ pub const FileSystem = struct {
file_limit: usize = 32,
file_quota: usize = 32,
+ pub fn needToCloseFiles(rfs: *const RealFS) bool {
+ // On Windows, we must always close open file handles
+ // Windows locks files
+ if (!FeatureFlags.store_file_descriptors) {
+ return true;
+ }
+
+ // If we're not near the max amount of open files, don't worry about it.
+ return !(rfs.file_limit > 254 and rfs.file_limit > (FileSystem.max_fd + 1) * 2);
+ }
+
// Always try to max out how many files we can keep open
pub fn adjustUlimit() usize {
var limit = std.os.getrlimit(.NOFILE) catch return 32;
@@ -375,7 +398,7 @@ pub const FileSystem = struct {
.cwd = cwd,
.file_limit = file_limit,
.file_quota = file_limit,
- .limiter = Limiter.init(allocator),
+ .limiter = Limiter.init(allocator, file_limit),
.watcher = if (enable_watcher) std.StringHashMap(WatchData).init(allocator) else null,
};
}
@@ -389,9 +412,7 @@ pub const FileSystem = struct {
mtime: i128 = 0,
mode: std.fs.File.Mode = 0,
- pub fn generate(fs: *RealFS, path: string) anyerror!ModKey {
- var file = try std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true });
- defer file.close();
+ pub fn generate(fs: *RealFS, path: string, file: std.fs.File) anyerror!ModKey {
const stat = try file.stat();
const seconds = @divTrunc(stat.mtime, @as(@TypeOf(stat.mtime), std.time.ns_per_s));
@@ -437,11 +458,8 @@ pub const FileSystem = struct {
}
}
- pub fn modKey(fs: *RealFS, path: string) anyerror!ModKey {
- fs.limiter.before();
- defer fs.limiter.after();
-
- const key = ModKey.generate(fs, path) catch |err| {
+ pub fn modKeyWithFile(fs: *RealFS, path: string, file: anytype) anyerror!ModKey {
+ const key = ModKey.generate(fs, path, file) catch |err| {
fs.modKeyError(path, err);
return err;
};
@@ -457,6 +475,18 @@ pub const FileSystem = struct {
return key;
}
+ pub fn modKey(fs: *RealFS, path: string) anyerror!ModKey {
+ fs.limiter.before();
+ defer fs.limiter.after();
+ var file = try std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true });
+ defer {
+ if (fs.needToCloseFiles()) {
+ file.close();
+ }
+ }
+ return try fs.modKeyWithFile(path, file);
+ }
+
pub const WatchData = struct {
dir_entries: []string = &([_]string{}),
file_contents: string = "",
@@ -493,9 +523,9 @@ pub const FileSystem = struct {
// Limit the number of files open simultaneously to avoid ulimit issues
pub const Limiter = struct {
semaphore: Semaphore,
- pub fn init(allocator: *std.mem.Allocator) Limiter {
+ pub fn init(allocator: *std.mem.Allocator, limit: usize) Limiter {
return Limiter{
- .semaphore = Semaphore.init(32),
+ .semaphore = Semaphore.init(limit),
// .counter = std.atomic.Int(u8).init(0),
// .lock = std.Thread.Mutex.init(),
};
@@ -532,6 +562,12 @@ pub const FileSystem = struct {
var iter: std.fs.Dir.Iterator = handle.iterate();
var dir = DirEntry.init(_dir, fs.allocator);
errdefer dir.deinit();
+
+ if (FeatureFlags.store_file_descriptors) {
+ FileSystem.setMaxFd(handle.fd);
+ dir.fd = handle.fd;
+ }
+
while (try iter.next()) |_entry| {
try dir.addEntry(_entry);
}
@@ -585,7 +621,7 @@ pub const FileSystem = struct {
var handle = _handle orelse try fs.openDir(dir);
defer {
- if (_handle == null) {
+ if (_handle == null and fs.needToCloseFiles()) {
handle.close();
}
}
@@ -596,7 +632,7 @@ pub const FileSystem = struct {
}
// Cache miss: read the directory entries
- const entries = fs.readdir(
+ var entries = fs.readdir(
dir,
handle,
) catch |err| {
@@ -643,15 +679,8 @@ pub const FileSystem = struct {
}
}
- pub fn readFile(fs: *RealFS, path: string, _size: ?usize) !File {
- fs.limiter.before();
- defer fs.limiter.after();
-
- const file: std.fs.File = std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true, .write = false }) catch |err| {
- fs.readFileError(path, err);
- return err;
- };
- defer file.close();
+ pub fn readFileWithHandle(fs: *RealFS, path: string, _size: ?usize, file: std.fs.File) !File {
+ FileSystem.setMaxFd(file.handle);
// Skip the extra file.stat() call when possible
var size = _size orelse (file.getEndPos() catch |err| {
@@ -675,6 +704,26 @@ pub const FileSystem = struct {
return File{ .path = Path.init(path), .contents = file_contents };
}
+ pub fn readFile(
+ fs: *RealFS,
+ path: string,
+ _size: ?usize,
+ ) !File {
+ fs.limiter.before();
+ defer fs.limiter.after();
+ const file: std.fs.File = std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true, .write = false }) catch |err| {
+ fs.readFileError(path, err);
+ return err;
+ };
+ defer {
+ if (fs.needToCloseFiles()) {
+ file.close();
+ }
+ }
+
+ return try fs.readFileWithHandle(path, _size, file);
+ }
+
pub fn kind(fs: *RealFS, _dir: string, base: string) !Entry.Cache {
var dir = _dir;
var combo = [2]string{ dir, base };
@@ -684,7 +733,11 @@ pub const FileSystem = struct {
defer fs.limiter.after();
const file = try std.fs.openFileAbsolute(entry_path, .{ .read = true, .write = false });
- defer file.close();
+ defer {
+ if (fs.needToCloseFiles()) {
+ file.close();
+ }
+ }
var stat = try file.stat();
var _kind = stat.kind;
@@ -711,6 +764,7 @@ pub const FileSystem = struct {
symlink = link;
const file2 = std.fs.openFileAbsolute(symlink, std.fs.File.OpenFlags{ .read = true, .write = false }) catch return cache;
+ // These ones we always close
defer file2.close();
const stat2 = file2.stat() catch return cache;
@@ -756,18 +810,6 @@ pub const FileSystem = struct {
};
};
-pub const FileSystemEntry = union(FileSystemEntry.Kind) {
- file: File,
- directory: Directory,
- not_found: FileNotFound,
-
- pub const Kind = enum(u8) {
- file,
- directory,
- not_found,
- };
-};
-
pub const Directory = struct { path: Path, contents: []string };
pub const File = struct { path: Path, contents: string };