commit 3c362bec22fb22ac81f7929365770cc612e0e29f
parent 8d5cf5206a6a57d9d2e35e1c34e5961917a4b06a
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 16 Aug 2021 10:03:52 +0200
os::dirfdfs: allow tuning getdents buffer size
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/errors/common.ha b/errors/common.ha
@@ -28,6 +28,9 @@ export type cancelled = !void;
// A connection attempt was refused.
export type refused = !void;
+// Unable to allocate sufficient memory for the requested operation.
+export type nomem = !void;
+
// A tagged union of all error types.
export type error = !(
busy |
@@ -40,5 +43,6 @@ export type error = !(
timeout |
cancelled |
refused |
+ nomem |
opaque
);
diff --git a/errors/string.ha b/errors/string.ha
@@ -19,5 +19,6 @@ export fn strerror(err: error) const str = match (err) {
timeout => "The requested operation timed out",
cancelled => "The requested operation was cancelled",
refused => "A connection attempt was refused",
+ nomem => "Unable to allocate sufficient memory for the requested operation",
op: opaque => op.strerror(&op.data),
};
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -41,6 +41,7 @@ type os_filesystem = struct {
fs: fs::fs,
dirfd: int,
resolve: resolve_flags,
+ getdents_bufsz: size,
};
// Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a
@@ -78,6 +79,7 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = {
...
},
dirfd = fd,
+ getdents_bufsz = 32768, // 32 KiB
};
return &filesystem.fs;
};
@@ -95,6 +97,17 @@ export fn dirfs_clone(fs: *fs::fs, resolve: resolve_flags...) *fs::fs = {
return &new.fs;
};
+// Sets the buffer size to use with the getdents(2) system call, for use with
+// [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can
+// scan large directories faster. The default buffer size is 32 KiB.
+//
+// This function is not portable.
+export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = {
+ assert(fs.open == &fs_open);
+ let fs = fs: *os_filesystem;
+ fs.getdents_bufsz = sz;
+};
+
fn errno_to_fs(err: rt::errno) fs::error = switch (err) {
rt::ENOENT => errors::noentry,
rt::EEXIST => errors::exists,
@@ -349,7 +362,7 @@ type os_iterator = struct {
fd: int,
buf_pos: size,
buf_end: size,
- buf: [BUFSIZ]u8,
+ buf: []u8,
};
fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
@@ -364,11 +377,16 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
n: int => n,
};
+ let buf = match (rt::malloc(fs.getdents_bufsz)) {
+ v: *void => v: *[*]u8,
+ null => return errors::nomem,
+ };
let iter = alloc(os_iterator {
iter = fs::iterator {
next = &iter_next,
},
fd = fd,
+ buf = buf[..fs.getdents_bufsz],
...
});
return &iter.iter;
@@ -377,9 +395,11 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
fn iter_next(iter: *fs::iterator) (fs::dirent | void) = {
let iter = iter: *os_iterator;
if (iter.buf_pos >= iter.buf_end) {
- let n = rt::getdents64(iter.fd, &iter.buf, BUFSIZ) as size;
+ let n = rt::getdents64(iter.fd,
+ iter.buf: *[*]u8, len(iter.buf)) as size;
if (n == 0) {
rt::close(iter.fd)!;
+ free(iter.buf);
free(iter);
return;
};