diff --git a/include/ircd/fs/read.h b/include/ircd/fs/read.h index 287c461cf..357f30b62 100644 --- a/include/ircd/fs/read.h +++ b/include/ircd/fs/read.h @@ -27,6 +27,9 @@ namespace ircd::fs std::string read(const fd &, const read_opts & = read_opts_default); std::string read(const string_view &path, const read_opts & = read_opts_default); + // Test whether bytes in the specified range are cached and should not block + bool fetched(const fd &, const size_t &, const read_opts & = read_opts_default); + // Prefetch bytes for subsequent read(); offset is given in opts. size_t prefetch(const fd &, const size_t &, const read_opts & = read_opts_default); } diff --git a/ircd/fs.cc b/ircd/fs.cc index 2ca92cb6d..0ad9b78ef 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -484,7 +484,6 @@ ircd::fs::prefetch(const fd &fd, const size_t &count, const read_opts &opts) { - assert(opts.op == op::READ); static const size_t max_count { 128_KiB @@ -504,6 +503,44 @@ ircd::fs::prefetch(const fd &fd, return count; } +bool +ircd::fs::fetched(const fd &fd, + const size_t &count, + const read_opts &opts) +{ + assert(opts.offset % info::page_size == 0); + const size_t &map_size + { + count?: size(fd) + }; + + void *const &map + { + ::mmap(nullptr, map_size, PROT_NONE, MAP_NONBLOCK | MAP_SHARED, int(fd), opts.offset) + }; + + if(unlikely(map == MAP_FAILED)) + throw_system_error(errno); + + const custom_ptr map_ptr + { + map, [&map_size](void *const &map) + { + syscall(::munmap, map, map_size); + } + }; + + const size_t vec_size + { + std::max(((map_size + info::page_size - 1) / info::page_size) / 8, 1UL) + }; + assert(vec_size > 0 && vec_size < map_size); + + std::vector vec(vec_size); + syscall(::mincore, map, map_size, reinterpret_cast(vec.data())); + return std::find(begin(vec), end(vec), 0UL) == end(vec); +} + std::string ircd::fs::read(const string_view &path, const read_opts &opts)