diff --git a/.github/workflows/ci-tests.yaml b/.github/workflows/ci-tests.yaml index 940d9ba10..1a67a994c 100644 --- a/.github/workflows/ci-tests.yaml +++ b/.github/workflows/ci-tests.yaml @@ -9,11 +9,11 @@ on: - capio-v2 concurrency: group: build-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true jobs: codespell-check: name: "Check codespell conformance" runs-on: ubuntu-22.04 + continue-on-error: true steps: - uses: actions/checkout@v4 - name: "Run codespell" @@ -75,13 +75,14 @@ jobs: steps: - uses: actions/checkout@v4 - name: "Run clang-format style check" - uses: jidicula/clang-format-action@v4.13.0 + uses: jidicula/clang-format-action@v4.15.0 with: - clang-format-version: "16" + clang-format-version: "20" check-path: "${{ matrix.path }}" unit-tests: name: "Build ${{ matrix.build_type }} with ${{ matrix.cxx }}" runs-on: ubuntu-22.04 + continue-on-error: true strategy: matrix: build_type: @@ -170,6 +171,12 @@ jobs: capio_posix_unit_tests \ --gtest_break_on_failure \ --gtest_print_time=1 + + echo "Run CAPIO memory file integration tests" + LD_PRELOAD=libcapio_posix.so \ + capio_memory_file_unit_tests \ + --gtest_break_on_failure \ + --gtest_print_time=1 - name: "Show client logs on failure" if: ${{ always() && steps.run-tests.outcome == 'failure' && matrix.build_type == 'Debug' }} diff --git a/src/common/capio/constants.hpp b/src/common/capio/constants.hpp index 9bac78642..aaade0322 100644 --- a/src/common/capio/constants.hpp +++ b/src/common/capio/constants.hpp @@ -29,7 +29,7 @@ constexpr char CAPIO_SHM_CANARY_ERROR[] = // CAPIO communication constants constexpr int CAPIO_REQ_BUFF_CNT = 512; // Max number of elements inside buffers constexpr int CAPIO_CACHE_LINES_DEFAULT = 10; -constexpr int CAPIO_CACHE_LINE_SIZE_DEFAULT = 4096; +constexpr int CAPIO_CACHE_LINE_SIZE_DEFAULT = 32768; // 32K of default size for cache lines // TODO: use that in communication only uses the file descriptor instead of the path to save on the // PATH_MAX constexpr size_t CAPIO_REQ_MAX_SIZE = (PATH_MAX + 256) * sizeof(char); @@ -144,6 +144,9 @@ constexpr char CAPIO_SERVER_ARG_PARSER_BACKEND_PORT_OPT_HELP[] = "A valid PORT for the Communication backend"; constexpr char CAPIO_SERVER_ARG_PARSER_CONFIG_NO_CONF_FILE_HELP[] = "If specified, server application will start without a config file, using default settings."; +constexpr char CAPIO_SERVER_ARG_PARSER_MEM_STORAGE_ONLY_HELP[] = + "If set, all files will be stored inside the home node server memory and never on file system " + "(unless memory limit is reached, or server instance terminates)."; constexpr char CAPIO_SERVER_ARG_PARSER_CONFIG_NCONTINUE_ON_ERROR_HELP[] = "If specified, Capio will try to continue its execution to continue even if it has reached a " "fatal termination point. This flag should be used only to debug capio. If this flag is " diff --git a/src/common/capio/queue.hpp b/src/common/capio/queue.hpp index 1854657d8..fcdb3ed15 100644 --- a/src/common/capio/queue.hpp +++ b/src/common/capio/queue.hpp @@ -18,7 +18,6 @@ * @tparam Mutex Type of semaphore */ template class Queue { - private: void *_shm; const long int _max_num_elems, _elem_size; // elements size in bytes long int _buff_size; // buffer size in bytes @@ -83,6 +82,7 @@ template class Queue { Queue(const Queue &) = delete; Queue &operator=(const Queue &) = delete; + ~Queue() { START_LOG(capio_syscall(SYS_gettid), "call(_shm_name=%s, _first_elem_name=%s, _last_elem_name=%s)", _shm_name.c_str(), @@ -93,8 +93,11 @@ template class Queue { syscall_no_intercept_flag = true; #endif SHM_DESTROY_CHECK(_shm_name.c_str()); + LOG("Removed %s", _shm_name.c_str()); SHM_DESTROY_CHECK(_first_elem_name.c_str()); + LOG("Removed %s", _first_elem_name.c_str()); SHM_DESTROY_CHECK(_last_elem_name.c_str()); + LOG("Removed %s", _last_elem_name.c_str()); #ifdef __CAPIO_POSIX syscall_no_intercept_flag = false; #endif @@ -176,4 +179,4 @@ template using CircularBuffer = Queue; // Single Producer Single Consumer queue using SPSCQueue = Queue; -#endif // CAPIO_QUEUE_HPP +#endif // CAPIO_QUEUE_HPP \ No newline at end of file diff --git a/src/common/capio/semaphore.hpp b/src/common/capio/semaphore.hpp index fb5bb85ba..f1f0f560e 100644 --- a/src/common/capio/semaphore.hpp +++ b/src/common/capio/semaphore.hpp @@ -20,7 +20,8 @@ class NoLock { NoLock(const NoLock &) = delete; NoLock &operator=(const NoLock &) = delete; - ~NoLock() = default; + + ~NoLock() { START_LOG(capio_syscall(SYS_gettid), "call()"); }; static inline void lock() { START_LOG(capio_syscall(SYS_gettid), "call()"); }; @@ -58,6 +59,7 @@ class NamedSemaphore { NamedSemaphore(const NamedSemaphore &) = delete; NamedSemaphore &operator=(const NamedSemaphore &) = delete; + ~NamedSemaphore() { START_LOG(capio_syscall(SYS_gettid), "call()"); if (_require_cleanup) { @@ -125,6 +127,7 @@ class Semaphore { Semaphore(const Semaphore &) = delete; Semaphore &operator=(const Semaphore &) = delete; + ~Semaphore() { START_LOG(capio_syscall(SYS_gettid), "call()"); if (_require_cleanup) { diff --git a/src/posix/handlers/close.hpp b/src/posix/handlers/close.hpp index f909b407f..1107e47fc 100644 --- a/src/posix/handlers/close.hpp +++ b/src/posix/handlers/close.hpp @@ -12,6 +12,7 @@ int close_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long ar if (exists_capio_fd(fd)) { close_request(get_capio_fd_path(fd), tid); + write_request_cache_mem->flush(); delete_capio_fd(fd); } diff --git a/src/posix/handlers/exit.hpp b/src/posix/handlers/exit.hpp index 75732bccf..c966035fc 100644 --- a/src/posix/handlers/exit.hpp +++ b/src/posix/handlers/exit.hpp @@ -18,27 +18,28 @@ int exit_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg auto tid = static_cast(syscall_no_intercept(SYS_gettid)); START_LOG(tid, "call()"); + syscall_no_intercept_flag = true; + LOG("syscall_no_intercept_flag = true"); + if (is_capio_tid(tid)) { LOG("Thread %d is a CAPIO thread: clean up", tid); exit_group_request(tid); remove_capio_tid(tid); } + delete_caches(); + LOG("Removed caches"); + if (const auto itm = bufs_response->find(tid); itm != bufs_response->end()) { delete itm->second; bufs_response->erase(tid); LOG("Removed response buffer"); } - - delete_caches(); - LOG("Removed caches"); - - delete stc_queue; - delete cts_queue; - LOG("Removed data queues"); + syscall_no_intercept_flag = false; + LOG("syscall_no_intercept_flag = false"); return CAPIO_POSIX_SYSCALL_SKIP; } #endif // SYS_exit || SYS_exit_group -#endif // CAPIO_POSIX_HANDLERS_EXIT_GROUP_HPP +#endif // CAPIO_POSIX_HANDLERS_EXIT_GROUP_HPP \ No newline at end of file diff --git a/src/posix/handlers/open.hpp b/src/posix/handlers/open.hpp index 148a341b5..65340469f 100644 --- a/src/posix/handlers/open.hpp +++ b/src/posix/handlers/open.hpp @@ -79,6 +79,9 @@ int open_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg LOG("not O_CREAT"); open_request(-1, path.data(), tid); } + } else { + LOG("Not a CAPIO path. skipping..."); + return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; } int fd = static_cast(syscall_no_intercept(SYS_open, arg0, arg1, arg2, arg3, arg4, arg5)); @@ -112,6 +115,9 @@ int openat_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long a LOG("not O_CREAT"); open_request(-1, path.data(), tid); } + } else { + LOG("Not a CAPIO path. skipping..."); + return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; } int fd = static_cast(syscall_no_intercept(SYS_openat, arg0, arg1, arg2, arg3, arg4, arg5)); @@ -127,4 +133,4 @@ int openat_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long a } #endif // SYS_openat -#endif // CAPIO_POSIX_HANDLERS_OPENAT_HPP +#endif // CAPIO_POSIX_HANDLERS_OPENAT_HPP \ No newline at end of file diff --git a/src/posix/handlers/read.hpp b/src/posix/handlers/read.hpp index e53ed49b0..65cdb2391 100644 --- a/src/posix/handlers/read.hpp +++ b/src/posix/handlers/read.hpp @@ -1,14 +1,8 @@ #ifndef CAPIO_POSIX_HANDLERS_READ_HPP #define CAPIO_POSIX_HANDLERS_READ_HPP -#if defined(SYS_read) -int read_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long *result) { - int fd = static_cast(arg0); - auto count = static_cast(arg2); - auto tid = static_cast(syscall_no_intercept(SYS_gettid)); - - START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, tid=%d, count=%ld)", fd, tid, count); - +inline off64_t capio_read_fs(int fd, size_t count, pid_t tid) { + START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, count=%ld, tid=%ld)", fd, count, tid); if (exists_capio_fd(fd)) { auto computed_offset = get_capio_fd_offset(fd) + count; @@ -21,6 +15,41 @@ int read_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg } return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; } + +inline off64_t capio_read_mem(int fd, size_t count, void *buffer, long *result) { + START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, count=%ld)", fd, count); + if (exists_capio_fd(fd)) { + auto computed_offset = get_capio_fd_offset(fd) + count; + + LOG("Handling read on file %s up to byte %ld", get_capio_fd_path(fd).c_str(), + computed_offset); + + *result = read_request_cache_mem->read(fd, buffer, count); + LOG("Result of read is %lu", *result); + return CAPIO_POSIX_SYSCALL_SUCCESS; + } + return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; +} + +#if defined(SYS_read) +int read_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long *result) { + int fd = static_cast(arg0); + auto count = static_cast(arg2); + auto buffer = reinterpret_cast(arg1); + auto tid = static_cast(syscall_no_intercept(SYS_gettid)); + + START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, tid=%d, count=%ld)", fd, tid, count); + if (exists_capio_fd(fd)) { + auto read_result = store_file_in_memory(get_capio_fd_path(fd), tid) + ? capio_read_mem(fd, count, buffer, result) + : capio_read_fs(fd, count, tid); + + LOG("read result: %ld", read_result); + return read_result; + } + LOG("Not a CAPIO fd... skipping..."); + return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; +} #endif // SYS_read #if defined(SYS_readv) @@ -40,4 +69,4 @@ int readv_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long ar } #endif // SYS_readv -#endif // CAPIO_POSIX_HANDLERS_READ_HPP +#endif // CAPIO_POSIX_HANDLERS_READ_HPP \ No newline at end of file diff --git a/src/posix/handlers/write.hpp b/src/posix/handlers/write.hpp index 18769c179..6d2aa6702 100644 --- a/src/posix/handlers/write.hpp +++ b/src/posix/handlers/write.hpp @@ -12,10 +12,18 @@ inline off64_t capio_write_fs(int fd, capio_off64_t count, pid_t tid) { return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; } -inline off64_t capio_write_mem(int fd, char *buffer, capio_off64_t count, pid_t tid) { +inline off64_t capio_writev_fs(int fd, char *buffer, off64_t count, pid_t tid) { + START_LOG(tid, "Handling FS write within writev"); + capio_write_fs(fd, count, tid); + const off64_t write_count = syscall_no_intercept(SYS_write, fd, buffer, count); + LOG("Wrote %ld bytes", write_count); + return write_count; +} +inline off64_t capio_write_mem(int fd, char *buffer, capio_off64_t count, pid_t tid) { START_LOG(tid, "call(fd=%d, count=%ld)", fd, count); - return 0; + write_request_cache_mem->write(fd, buffer, count); + return count; } #if defined(SYS_write) @@ -34,6 +42,8 @@ int write_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long ar ? capio_write_mem(fd, buffer, count, tid) : capio_write_fs(fd, count, tid); + LOG("Write result: %ld", write_result); + return posix_return_value(write_result, result); } #endif // SYS_write @@ -41,21 +51,32 @@ int write_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long ar #if defined(SYS_writev) int writev_handler(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long *result) { auto fd = static_cast(arg0); - auto buffer = reinterpret_cast(arg1); + auto io_vec = reinterpret_cast(arg1); auto iovcnt = static_cast(arg2); long tid = syscall_no_intercept(SYS_gettid); - START_LOG(tid, "call(fd=%d, buffer=%p, count=%ld, id=%ld)", fd, buffer, iovcnt, tid); + START_LOG(tid, "call(fd=%d, buffer=%p, count=%ld, pid=%ld)", fd, io_vec->iov_base, + io_vec->iov_len, tid); if (!exists_capio_fd(fd)) { - LOG("FD %d is not handled by capio... skipping syscall", fd); + LOG("FD %d is not handled by CAPIO... skipping syscall", fd); return CAPIO_POSIX_SYSCALL_REQUEST_SKIP; } - auto write_result = store_file_in_memory(get_capio_fd_path(fd), tid) - ? capio_write_mem(fd, buffer, iovcnt, tid) - : capio_write_fs(fd, iovcnt, tid); + LOG("Need to handle %ld IOVEC objects", iovcnt); + int write_result = 0; + for (auto i = 0; i < iovcnt; ++i) { + const auto [iov_base, iov_len] = io_vec[i]; + if (iov_len == 0) { + LOG("Size of IOVEC is 0. Skipping write request"); + continue; + } + LOG("Handling IOVEC elements %d of size %ld", i, iov_len); + write_result += store_file_in_memory(get_capio_fd_path(fd), tid) + ? capio_write_mem(fd, static_cast(iov_base), iov_len, tid) + : capio_writev_fs(fd, static_cast(iov_base), iov_len, tid); + } return posix_return_value(write_result, result); } #endif // SYS_writev -#endif // CAPIO_POSIX_HANDLERS_WRITE_HPP +#endif // CAPIO_POSIX_HANDLERS_WRITE_HPP \ No newline at end of file diff --git a/src/posix/utils/cache.hpp b/src/posix/utils/cache.hpp index 7c2d6c083..67e07977f 100644 --- a/src/posix/utils/cache.hpp +++ b/src/posix/utils/cache.hpp @@ -31,6 +31,11 @@ inline void delete_caches() { delete consent_request_cache_fs; delete write_request_cache_mem; delete read_request_cache_mem; + + delete cts_queue; + LOG("Removed cts_queue"); + delete stc_queue; + LOG("Removed stc_queue"); } -#endif // CAPIO_CACHE_HPP +#endif // CAPIO_CACHE_HPP \ No newline at end of file diff --git a/src/posix/utils/cache/consent_request_cache.hpp b/src/posix/utils/cache/consent_request_cache.hpp index 022eab605..bf5cced10 100644 --- a/src/posix/utils/cache/consent_request_cache.hpp +++ b/src/posix/utils/cache/consent_request_cache.hpp @@ -24,7 +24,10 @@ class ConsentRequestCache { available_consent = new std::unordered_map; }; - ~ConsentRequestCache() { delete available_consent; }; + ~ConsentRequestCache() { + START_LOG(capio_syscall(SYS_gettid), "call()"); + delete available_consent; + }; void consent_request(const std::filesystem::path &path, long tid, const std::string &source_func) const { diff --git a/src/posix/utils/cache/read_request_cache_fs.hpp b/src/posix/utils/cache/read_request_cache_fs.hpp index 4e1d184ff..d8a6f07c2 100644 --- a/src/posix/utils/cache/read_request_cache_fs.hpp +++ b/src/posix/utils/cache/read_request_cache_fs.hpp @@ -26,7 +26,10 @@ class ReadRequestCacheFS { available_read_cache = new std::unordered_map; }; - ~ReadRequestCacheFS() { delete available_read_cache; }; + ~ReadRequestCacheFS() { + START_LOG(capio_syscall(SYS_gettid), "call()"); + delete available_read_cache; + }; void read_request(std::filesystem::path path, const long end_of_read, int tid, const int fd) { START_LOG(capio_syscall(SYS_gettid), "[cache] call(path=%s, end_of_read=%ld, tid=%ld)", diff --git a/src/posix/utils/cache/read_request_cache_mem.hpp b/src/posix/utils/cache/read_request_cache_mem.hpp index 29930efb2..16661c02a 100644 --- a/src/posix/utils/cache/read_request_cache_mem.hpp +++ b/src/posix/utils/cache/read_request_cache_mem.hpp @@ -1,15 +1,16 @@ #ifndef READ_REQUEST_CACHE_MEM_HPP #define READ_REQUEST_CACHE_MEM_HPP + class ReadRequestCacheMEM { - private: char *_cache; long _tid; int _fd; capio_off64_t _max_line_size, _actual_size, _cache_offset; - capio_off64_t _last_read_end; + capio_off64_t _last_read_end, _real_file_size_commmitted; + bool committed = false; /** - * Copy data from the cache internal buffer to target buffer + * Copy data from the cache internal buffer to the target buffer * @param buffer * @param count */ @@ -25,34 +26,40 @@ class ReadRequestCacheMEM { protected: [[nodiscard]] capio_off64_t read_request(const int fd, const capio_off64_t count, - const long tid) { - START_LOG(capio_syscall(SYS_gettid), "call(fd=%ld, count=%llu, tid=%ld)", fd, count, tid); + const long tid, bool use_cache = true) { + START_LOG(capio_syscall(SYS_gettid), "call(fd=%ld, count=%llu, tid=%ld, load_data=%s)", fd, + count, tid, use_cache ? "true" : "false"); char req[CAPIO_REQ_MAX_SIZE]; - // send as last parameter to the server the maximum amount of data that can be read into a - // single line of cache + // send as the last parameter to the server the maximum amount of data that can be read into + // a single line of cache auto read_begin_offset = get_capio_fd_offset(fd); - sprintf(req, "%04d %ld %llu %llu %llu %s", CAPIO_REQUEST_READ_MEM, tid, read_begin_offset, - count, _max_line_size, get_capio_fd_path(fd).c_str()); + sprintf(req, "%04d %ld %llu %llu %llu %d %s", CAPIO_REQUEST_READ_MEM, tid, + read_begin_offset, count, _max_line_size, use_cache, get_capio_fd_path(fd).c_str()); LOG("Sending read request %s", req); buf_requests->write(req, CAPIO_REQ_MAX_SIZE); capio_off64_t stc_queue_read = bufs_response->at(tid)->read(); - LOG("Response to request is %ld", stc_queue_read); - - // FIXME: if count > _max_line_size, a deadlock or SEGFAULT is foreseen Fix it asap. - // FIXME: still this might not occur as the read() method should protect from this event - auto read_size = count; - while (read_size > 0) { - const capio_off64_t tmp_read_size = - read_size > _max_line_size ? _max_line_size : read_size; - stc_queue->read(_cache, tmp_read_size); - _cache_offset = 0; - read_size -= tmp_read_size; + LOG("Response to request is %llu", stc_queue_read); + + if (stc_queue_read >= 0x8000000000000000) { + committed = true; + stc_queue_read -= 0x8000000000000000; + _real_file_size_commmitted = stc_queue_read; + LOG("File is committed. Actual offset is: %ld", stc_queue_read); } - LOG("Completed fetch of data from server"); + if (use_cache) { + stc_queue->read(_cache, stc_queue_read); + _cache_offset = 0; + LOG("Completed fetch of data from server"); + } else { + _actual_size = 0; + _cache_offset = 0; + LOG("Data has not been loaded from server, as load_data==false." + " Load will occur independently"); + } return stc_queue_read; } @@ -64,71 +71,128 @@ class ReadRequestCacheMEM { _cache = new char[_max_line_size]; } - ~ReadRequestCacheMEM() { delete[] _cache; } + ~ReadRequestCacheMEM() { + START_LOG(capio_syscall(SYS_gettid), "call()"); + delete[] _cache; + } - inline void flush() { + void flush() { START_LOG(capio_syscall(SYS_gettid), "call()"); if (_cache_offset != _actual_size) { _actual_size = _cache_offset = 0; } + committed = false; + _real_file_size_commmitted = -1; } - void read(const int fd, void *buffer, off64_t count) { + long read(const int fd, void *buffer, off64_t count) { START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, count=%ld)", fd, count); + + long actual_read_size = 0; + if (_fd != fd) { LOG("changed fd from %d to %d: flushing", _fd, fd); flush(); _fd = fd; - _last_read_end = get_capio_fd_offset(_fd); + _last_read_end = get_capio_fd_offset(fd); } // Check if a seek has occurred before and in case in which case flush the cache // and update the offset to the new value if (_last_read_end != get_capio_fd_offset(_fd)) { + LOG("A seek() has occurred (_last_read_end=%llu, get_capio_fd_offset=%llu). Performing " + "flush().", + _last_read_end, get_capio_fd_offset(_fd)); flush(); _last_read_end = get_capio_fd_offset(_fd); } - if (_actual_size == 0) { + if (committed && _real_file_size_commmitted == _last_read_end) { + LOG("All file content has been read. Returning 0"); + return 0; + } + + /* + * Check: if read size is greater than the capability of the cache line, bypass + * the cache and perform a read directly to the provided buffer + */ + if (count > _max_line_size) { + LOG("count > _max_line_size. Bypassing cache. Performing read() directly to buffer."); + const auto _read_size = read_request(_fd, count, _tid, false); + stc_queue->read(static_cast(buffer), _read_size); + return _read_size; + } + + // Check if cache is empty or if all the content of the cache has been already consumed + if (_actual_size == 0 || _actual_size == _cache_offset) { + LOG("No data is present locally. performing request."); const auto size = count < _max_line_size ? count : _max_line_size; - read_request(_fd, size, _tid); + _actual_size = read_request(_fd, size, _tid); + + // Update count for current request. If count exceeds _actual_size, resize it to not + // exceeds the available size on posix application + count = std::min(static_cast(count), _actual_size); } if (count <= _max_line_size - _cache_offset) { // There is enough data to perform a read LOG("The requested amount of data can be served without performing a request"); _read(buffer, count); + actual_read_size = count; + _last_read_end = get_capio_fd_offset(_fd) + count; + set_capio_fd_offset(fd, _last_read_end); } else { // There could be some data available already on the cache. Copy that first and then // proceed to request the other missing data - const auto first_copy_size = _max_line_size - _cache_offset; + const auto first_copy_size = + std::min(_actual_size - _cache_offset, static_cast(count)); + + LOG("Data (or part of it) might be already present. performing first copy of" + " std::min(_actual_size(%llu) - _cache_offset(%llu), count(%llu) = %ld", + _actual_size, _cache_offset, count, first_copy_size); _read(buffer, first_copy_size); + _last_read_end = get_capio_fd_offset(_fd) + first_copy_size; set_capio_fd_offset(fd, get_capio_fd_offset(fd) + first_copy_size); + actual_read_size = first_copy_size; + LOG("actual_read_size incremented to: %ld", actual_read_size); // Compute the remaining amount of data to send to client auto remaining_size = count - first_copy_size; capio_off64_t copy_offset = first_copy_size; - while (copy_offset < count) { - + while (copy_offset < count && !committed) { + LOG("Need to request still %ld of data from server component", count - copy_offset); // request a line from the server component through a request - auto available_size = read_request(_fd, remaining_size, _tid); + _actual_size = read_request(_fd, remaining_size, _tid); + + if (committed) { + LOG("File has resulted in a commit message. Exiting loop"); + break; + } + + LOG("Available size after request: %ld", _actual_size); // compute the amount of data that is going to be sent to the client application auto size_to_send_to_client = - remaining_size < available_size ? remaining_size : available_size; + remaining_size < _actual_size ? remaining_size : _actual_size; + LOG("Sending %ld of data to posix application", size_to_send_to_client); _read(static_cast(buffer) + copy_offset, size_to_send_to_client); + actual_read_size += size_to_send_to_client; + LOG("actual_read_size incremented to: %ld", actual_read_size); copy_offset += size_to_send_to_client; remaining_size -= size_to_send_to_client; + + _last_read_end = get_capio_fd_offset(_fd) + size_to_send_to_client; + set_capio_fd_offset(fd, _last_read_end); } } - _last_read_end = get_capio_fd_offset(_fd) + count; - set_capio_fd_offset(fd, _last_read_end); + LOG("Read return value: %ld (_last_Read_end = %llu)", actual_read_size, _last_read_end); + return actual_read_size; } }; -#endif // READ_REQUEST_CACHE_MEM_HPP +#endif // READ_REQUEST_CACHE_MEM_HPP \ No newline at end of file diff --git a/src/posix/utils/cache/write_request_cache_fs.hpp b/src/posix/utils/cache/write_request_cache_fs.hpp index 129cc6197..096c5a941 100644 --- a/src/posix/utils/cache/write_request_cache_fs.hpp +++ b/src/posix/utils/cache/write_request_cache_fs.hpp @@ -22,7 +22,10 @@ class WriteRequestCacheFS { public: explicit WriteRequestCacheFS() : _max_size(get_capio_write_cache_size()) {} - ~WriteRequestCacheFS() { this->flush(capio_syscall(SYS_gettid)); } + ~WriteRequestCacheFS() { + START_LOG(capio_syscall(SYS_gettid), "call()"); + this->flush(capio_syscall(SYS_gettid)); + } void write_request(std::filesystem::path path, int tid, int fd, long count) { START_LOG(capio_syscall(SYS_gettid), "call(path=%s, tid=%ld, fd=%ld, count=%ld)", diff --git a/src/posix/utils/cache/write_request_cache_mem.hpp b/src/posix/utils/cache/write_request_cache_mem.hpp index 741de6bc7..34c570460 100644 --- a/src/posix/utils/cache/write_request_cache_mem.hpp +++ b/src/posix/utils/cache/write_request_cache_mem.hpp @@ -1,5 +1,6 @@ #ifndef WRITE_REQUEST_CACHE_MEM_HPP #define WRITE_REQUEST_CACHE_MEM_HPP + class WriteRequestCacheMEM { char *_cache; long _tid; @@ -38,13 +39,20 @@ class WriteRequestCacheMEM { : _cache(nullptr), _tid(capio_syscall(SYS_gettid)), _fd(-1), _max_line_size(line_size), _actual_size(0), _last_write_end(-1), _last_write_begin(0) {} + ~WriteRequestCacheMEM() { + START_LOG(capio_syscall(SYS_gettid), "call()"); + this->flush(); + } + void flush() { START_LOG(capio_syscall(SYS_gettid), "call()"); if (_actual_size != 0) { - write_request(_fd, _actual_size, get_capio_fd_path(_fd).c_str(), _last_write_begin); + LOG("Actual size: %ld", _actual_size); + write_request(_actual_size, _tid, get_capio_fd_path(_fd).c_str(), _last_write_begin); _cache = nullptr; _actual_size = 0; } + LOG("Flush completed"); } void write(int fd, const void *buffer, off64_t count) { diff --git a/src/posix/utils/filesystem.hpp b/src/posix/utils/filesystem.hpp index c2f09b31a..c64d8c4e6 100644 --- a/src/posix/utils/filesystem.hpp +++ b/src/posix/utils/filesystem.hpp @@ -83,16 +83,16 @@ inline std::filesystem::path capio_posix_realpath(const std::filesystem::path &p if (pathname.is_absolute()) { LOG("Path=%s is already absolute", pathname.c_str()); return {pathname}; - } else { - std::filesystem::path new_path = (*current_dir / pathname).lexically_normal(); - if (is_capio_path(new_path)) { - LOG("Computed absolute path = %s", new_path.c_str()); - return new_path; - } else { - LOG("file %s is not a posix file, nor a capio file!", pathname.c_str()); - return {}; - } } + + std::filesystem::path new_path = (*current_dir / pathname).lexically_normal(); + if (is_capio_path(new_path)) { + LOG("Computed absolute path = %s", new_path.c_str()); + return new_path; + } + + LOG("file %s is not a posix file, nor a capio file!", pathname.c_str()); + return {}; } // if not, then check for realpath through libc implementation @@ -286,7 +286,10 @@ inline void rename_capio_path(const std::string &oldpath, const std::string &new * @return */ inline void set_capio_fd_offset(int fd, capio_off64_t offset) { + START_LOG(capio_syscall(SYS_gettid), "call(fd=%d, offset=%lld)", fd, offset); + LOG("Previous offset = %lld", *std::get<0>(files->at(fd))); *std::get<0>(files->at(fd)) = offset; + LOG("New offset = %lld", *std::get<0>(files->at(fd))); } /** @@ -297,4 +300,4 @@ inline void set_current_dir(const std::filesystem::path &cwd) { current_dir = std::make_unique(cwd); } -#endif // CAPIO_POSIX_UTILS_FILESYSTEM_HPP +#endif // CAPIO_POSIX_UTILS_FILESYSTEM_HPP \ No newline at end of file diff --git a/src/posix/utils/requests.hpp b/src/posix/utils/requests.hpp index 97b236236..e32858515 100644 --- a/src/posix/utils/requests.hpp +++ b/src/posix/utils/requests.hpp @@ -48,9 +48,9 @@ inline void handshake_request(const long tid, const long pid, const std::string LOG("Sent handshake request"); cts_queue = new SPSCQueue("queue-" + std::to_string(tid) + ".cts", get_cache_lines(), - get_cache_line_size()); + get_cache_line_size(), get_capio_workflow_name(), true); stc_queue = new SPSCQueue("queue-" + std::to_string(tid) + ".stc", get_cache_lines(), - get_cache_line_size()); + get_cache_line_size(), get_capio_workflow_name(), true); LOG("Initialized data transfer queues"); } @@ -65,9 +65,9 @@ inline std::vector *file_in_memory_request(const long pid) { LOG("Need to read %llu files from data queues", files_to_read_from_queue); const auto regex_vector = new std::vector; for (int i = 0; i < files_to_read_from_queue; i++) { - LOG("Reading %d file", i); - auto file = new char[CAPIO_MAX_SPSCQUEUE_ELEM_SIZE]{}; - stc_queue->read(file, CAPIO_MAX_SPSCQUEUE_ELEM_SIZE); + LOG("Reading file number %d", i); + auto file = new char[PATH_MAX]{}; + stc_queue->read(file, PATH_MAX); LOG("Obtained path %s", file); regex_vector->emplace_back(generateCapioRegex(file)); delete[] file; @@ -125,4 +125,4 @@ inline void rename_request(const std::filesystem::path &old_path, #include "utils/storage.hpp" -#endif // CAPIO_POSIX_UTILS_REQUESTS_HPP +#endif // CAPIO_POSIX_UTILS_REQUESTS_HPP \ No newline at end of file diff --git a/src/posix/utils/storage.hpp b/src/posix/utils/storage.hpp index 8f5843848..6370af8f8 100644 --- a/src/posix/utils/storage.hpp +++ b/src/posix/utils/storage.hpp @@ -8,6 +8,9 @@ inline bool store_file_in_memory(const std::filesystem::path &file_name, const long pid) { START_LOG(capio_syscall(SYS_gettid), "call(path=%s, pid=%ld)", file_name.c_str(), pid); if (paths_to_store_in_memory == nullptr) { + /* + * Request which files need to be handled in memory instead of file system + */ LOG("Vector is empty and not allocated. performing request"); paths_to_store_in_memory = file_in_memory_request(pid); } @@ -17,4 +20,4 @@ inline bool store_file_in_memory(const std::filesystem::path &file_name, const l [file_name](const std::regex &rx) { return std::regex_match(file_name.string(), rx); }); } -#endif // STORAGE_HPP +#endif // STORAGE_HPP \ No newline at end of file diff --git a/src/server/capio-cl-engine/capio_cl_engine.hpp b/src/server/capio-cl-engine/capio_cl_engine.hpp index 0cda7f548..bbd8ac3cc 100644 --- a/src/server/capio-cl-engine/capio_cl_engine.hpp +++ b/src/server/capio-cl-engine/capio_cl_engine.hpp @@ -12,18 +12,18 @@ class CapioCLEngine { private: std::unordered_map, // Vector for producers [0] - std::vector, // Vector for consumers [1] - std::string, // commit rule [2] - std::string, // fire_rule [3] - bool, // permanent [4] - bool, // exclude [5] - bool, // is_file (if true yes otherwise it is a directory) [6] - int, // commit on close number [7] - long, // directory file count [8] - std::vector, // File dependencies [9] - std::regex, // Regex from name to match globs [10] - bool>> // Store File in memory or on FS. true = memory [11] + std::tuple, // Vector for producers [0] + std::vector, // Vector for consumers [1] + std::string, // commit rule [2] + std::string, // fire_rule [3] + bool, // permanent [4] + bool, // exclude [5] + bool, // is_file (false = directory) [6] + int, // commit on close number [7] + long, // directory file count [8] + std::vector, // File dependencies [9] + std::regex, // Regex to match globs [10] + bool>> // Store File on FS. true = memory [11] _locations; static std::string truncateLastN(const std::string &str, const int n) { @@ -403,15 +403,13 @@ class CapioCLEngine { } void setStoreFileInMemory(const std::filesystem::path &path) { - if (const auto itm = _locations.find(path); itm != _locations.end()) { - std::get<11>(itm->second) = true; - } + this->newFile(path); + std::get<11>(_locations.at(path)) = true; } void setStoreFileInFileSystem(const std::filesystem::path &path) { - if (const auto itm = _locations.find(path); itm != _locations.end()) { - std::get<11>(itm->second) = false; - } + this->newFile(path); + std::get<11>(_locations.at(path)) = false; } bool storeFileInMemory(const std::filesystem::path &path) { diff --git a/src/server/capio-cl-engine/json_parser.hpp b/src/server/capio-cl-engine/json_parser.hpp index e52bff5e9..a6d5a4891 100644 --- a/src/server/capio-cl-engine/json_parser.hpp +++ b/src/server/capio-cl-engine/json_parser.hpp @@ -56,6 +56,11 @@ class JsonParser { capio_dir.c_str()); locations->newFile(get_capio_dir()); + locations->setDirectory(get_capio_dir()); + if (StoreOnlyInMemory) { + locations->setStoreFileInMemory(get_capio_dir()); + } + if (source.empty()) { return locations; } @@ -321,7 +326,8 @@ class JsonParser { << "Completed parsing of io_graph" << std::endl; LOG("Completed parsing of io_graph"); - if (entries["permanent"].get_array().get(permanent_files)) { // PARSING PERMANENT FILES + if (entries["permanent"].get_array().get(permanent_files)) { + // PARSING PERMANENT FILES std::cout << CAPIO_LOG_SERVER_CLI_LEVEL_WARNING << " [ " << node_name << " ] " << "No permanent section found for workflow: " << workflow_name << std::endl; LOG("No permanent section found for workflow: %s", std::string(workflow_name).c_str()); @@ -351,7 +357,8 @@ class JsonParser { std::cout << CAPIO_LOG_SERVER_CLI_LEVEL_JSON << " [ " << node_name << " ] " << std::endl; - if (entries["exclude"].get_array().get(exclude_files)) { // PARSING PERMANENT FILES + if (entries["exclude"].get_array().get(exclude_files)) { + // PARSING PERMANENT FILES std::cout << CAPIO_LOG_SERVER_CLI_LEVEL_WARNING << " [ " << node_name << " ] " << "No exclude section found for workflow: " << workflow_name << std::endl; LOG("No exclude section found for workflow: %s", std::string(workflow_name).c_str()); diff --git a/src/server/capio_server.cpp b/src/server/capio_server.cpp index bfe86594d..367b35991 100644 --- a/src/server/capio_server.cpp +++ b/src/server/capio_server.cpp @@ -20,7 +20,12 @@ #include #include +/* + * Variables required to be globally available + * to all classes and subclasses. + */ std::string workflow_name; +inline bool StoreOnlyInMemory = false; char node_name[HOST_NAME_MAX]; #include "utils/types.hpp" @@ -66,9 +71,12 @@ std::string parseCLI(int argc, char **argv) { CAPIO_SERVER_ARG_PARSER_BACKEND_PORT_OPT_HELP, {'p', "port"}); args::Flag continueOnErrorFlag(arguments, "continue-on-error", - CAPIO_SERVER_ARG_PARSER_CONFIG_NCONTINUE_ON_ERROR_HELP, + CAPIO_SERVER_ARG_PARSER_MEM_STORAGE_ONLY_HELP, {"continue-on-error"}); + args::Flag memStorageOnly(arguments, "mem-storage-only", + CAPIO_SERVER_ARG_PARSER_CONFIG_NCONTINUE_ON_ERROR_HELP, {"mem-only"}); + try { parser.ParseCLI(argc, argv); } catch (args::Help &) { @@ -96,6 +104,12 @@ std::string parseCLI(int argc, char **argv) { #endif } + if (memStorageOnly) { + StoreOnlyInMemory = true; + std::cout << CAPIO_LOG_SERVER_CLI_LEVEL_INFO << " [ " << node_name << " ] " + << "All files will be stored in memory whenever possible." << std::endl; + } + if (logfile_folder) { #ifdef CAPIO_LOG log_master_dir_name = args::get(logfile_folder); @@ -124,8 +138,8 @@ std::string parseCLI(int argc, char **argv) { #ifdef CAPIO_LOG auto logname = open_server_logfile(); log = new Logger(__func__, __FILE__, __LINE__, gettid(), "Created new log file"); - std::cout << CAPIO_SERVER_CLI_LOG_SERVER << "started logging to logfile " << logname - << std::endl; + std::cout << CAPIO_SERVER_CLI_LOG_SERVER << " [ " << node_name << " ] " + << "started logging to logfile " << logname << std::endl; #endif if (config) { diff --git a/src/server/client-manager/handlers/read.hpp b/src/server/client-manager/handlers/read.hpp index 32cdaa1b3..befba4f5a 100644 --- a/src/server/client-manager/handlers/read.hpp +++ b/src/server/client-manager/handlers/read.hpp @@ -57,25 +57,47 @@ inline void read_handler(const char *const str) { inline void read_mem_handler(const char *const str) { pid_t tid; capio_off64_t read_size, client_cache_line_size, read_begin_offset; + int use_cache; char path[PATH_MAX]; - sscanf(str, "%ld %llu %llu %llu %s", &tid, &read_begin_offset, &read_size, - &client_cache_line_size, path); + sscanf(str, "%ld %llu %llu %llu %d %s", &tid, &read_begin_offset, &read_size, + &client_cache_line_size, &use_cache, path); START_LOG(gettid(), "call(tid=%d, read_begin_offset=%llu, read_size=%llu, client_cache_line_size=%llu, " - "path=%s)", - tid, read_begin_offset, read_size, client_cache_line_size, path); + "use_cache=%s, path=%s)", + tid, read_begin_offset, read_size, client_cache_line_size, + use_cache ? "true" : "false", path); - if (storage_service->sizeOf(path) < read_begin_offset + read_size) { - LOG("File is not yet ready to be consumed as there is not enough data"); + if (storage_service->sizeOf(path) < read_begin_offset + read_size && + !file_manager->isCommitted(path)) { + LOG("File is not yet ready to be consumed as there is not enough data, and is not " + "committed"); storage_service->addThreadWaitingForData(tid, path, read_begin_offset, read_size); return; } - auto size_to_send = read_size < client_cache_line_size ? read_size : client_cache_line_size; + capio_off64_t size_to_send = storage_service->sizeOf(path); + if (use_cache) { + LOG("Computing size of data to send: minimum between:"); + LOG("client_cache_line_size: %llu", client_cache_line_size); + LOG("file_size:%llu - read_begin_offset=%llu = %llu", size_to_send, read_begin_offset, + size_to_send - read_begin_offset); + size_to_send = std::min({client_cache_line_size, (size_to_send - read_begin_offset)}); + } + + LOG("Sending to posix app the offset up to which read."); + if (file_manager->isCommitted(path) && + read_begin_offset + size_to_send >= storage_service->sizeOf(path)) { + LOG("File is committed, and end of read >= than file size." + " signaling it to posix application by setting offset MSB to 1"); + LOG("Sending offset: %llu", 0x8000000000000000 | size_to_send); + client_manager->reply_to_client(tid, 0x8000000000000000 | size_to_send); + } else { + LOG("File is not committed. Sending offset: %llu", size_to_send); + client_manager->reply_to_client(tid, size_to_send); + } - LOG("Need to sent to client %llu bytes", size_to_send); - client_manager->reply_to_client(tid, size_to_send); + LOG("Need to sent to client %llu bytes, asking storage service to send data", size_to_send); storage_service->reply_to_client(tid, path, read_begin_offset, size_to_send); } -#endif // READ_HPP +#endif // READ_HPP \ No newline at end of file diff --git a/src/server/file-manager/file_manager_impl.hpp b/src/server/file-manager/file_manager_impl.hpp index 362ef5360..775b36ca3 100644 --- a/src/server/file-manager/file_manager_impl.hpp +++ b/src/server/file-manager/file_manager_impl.hpp @@ -233,6 +233,7 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { static std::unordered_map committed_files; if (committed_files.find(path) != committed_files.end()) { + LOG("Committed: TRUE"); return true; } @@ -253,8 +254,10 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { if (count >= file_count) { committed_files[path] = true; + LOG("Committed: TRUE"); return true; } + LOG("Committed: FALSE"); return false; } @@ -277,6 +280,7 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { if (commit_computed) { committed_files[path] = true; } + LOG("Committed: %s", commit_computed ? "TRUE" : "FALSE"); return commit_computed; } @@ -284,7 +288,8 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { LOG("Commit rule is ON_CLOSE"); if (!std::filesystem::exists(metadata_computed_path)) { - LOG("Commit file does not yet exists. returning false"); + LOG("Commit file does not yet exists."); + LOG("Committed: FALSE"); return false; } @@ -292,6 +297,7 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { LOG("Expected close count is: %d", commit_count); if (commit_count == -1) { LOG("File needs to be closed exactly once and token exists. returning"); + LOG("Committed: TRUE"); return true; } @@ -308,7 +314,9 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { if (actual_commit_count >= commit_count) { committed_files[path] = true; return true; + LOG("Committed: TRUE"); } + LOG("Committed: FALSE"); return false; } @@ -317,8 +325,10 @@ inline bool CapioFileManager::isCommitted(const std::filesystem::path &path) { if (std::filesystem::exists(metadata_computed_path)) { committed_files[path] = true; + LOG("Committed: TRUE"); return true; } + LOG("Committed: FALSE"); return false; } @@ -372,4 +382,4 @@ inline void CapioFileManager::checkFileAwaitingData() { } } -#endif // FILE_MANAGER_HPP +#endif // FILE_MANAGER_HPP \ No newline at end of file diff --git a/src/server/storage-service/CapioFile/CapioFile.hpp b/src/server/storage-service/CapioFile/CapioFile.hpp index 3eac56b38..af6ac1a51 100644 --- a/src/server/storage-service/CapioFile/CapioFile.hpp +++ b/src/server/storage-service/CapioFile/CapioFile.hpp @@ -7,10 +7,14 @@ class CapioFile { std::size_t totalSize; public: - explicit CapioFile(const std::string &filePath) : fileName(filePath), totalSize(0){}; + explicit CapioFile(const std::string &filePath) : fileName(filePath), totalSize(0) {}; virtual ~CapioFile() = default; - [[nodiscard]] std::size_t getSize() const { return totalSize; } + [[nodiscard]] std::size_t getSize() const { + START_LOG(gettid(), "call()"); + return totalSize; + } + [[nodiscard]] const std::string &getFileName() const { return fileName; } /** @@ -51,4 +55,4 @@ class CapioFile { std::size_t length) const = 0; }; -#endif // CAPIOFILE_HPP +#endif // CAPIOFILE_HPP \ No newline at end of file diff --git a/src/server/storage-service/CapioFile/CapioMemoryFile.hpp b/src/server/storage-service/CapioFile/CapioMemoryFile.hpp index 832a7133d..5fd98bd8d 100644 --- a/src/server/storage-service/CapioFile/CapioMemoryFile.hpp +++ b/src/server/storage-service/CapioFile/CapioMemoryFile.hpp @@ -15,11 +15,12 @@ class CapioMemoryFile : public CapioFile { std::map> memoryBlocks; - // maps for bits + // Static file sizes of file pages static constexpr u_int32_t _pageSizeMB = 4; - static constexpr u_int64_t _pageMask = 0xFFFFF; static constexpr u_int64_t _pageSizeBytes = _pageSizeMB * 1024 * 1024; + char *cross_page_buffer_view; + /** * Compute the offsets required to handle write operations onto CapioMemoryFile * @param offset Offset from the start of the file, on which the write operation will begin @@ -27,21 +28,23 @@ class CapioMemoryFile : public CapioFile { * @return tuple */ static auto compute_offsets(const std::size_t offset, std::size_t length) { + + START_LOG(gettid(), "call(offset=%llu, length=%llu)", offset, length); // Compute the offset of the memoryBlocks component. - // This is done by first obtaining the MB component of the address - // and then dividing it by the size in megabyte of the address - const auto map_offset = (offset >> 20) / _pageSizeMB; + const auto map_offset = offset / _pageSizeBytes; // Compute the first write offset relative to the first block of memory - const auto mem_block_offset = offset & _pageMask; + const auto mem_block_offset = offset % _pageSizeBytes; // compute the first write size. if the write operation is bigger than the size of the page // in bytes, then we need to perform the first write operation with size equals to the // distance between the write offset and the end of the page. otherwise it is possible to // use the given length. The returned offset starts from mem_block_offset const auto first_write_size = - length > _pageSizeBytes ? _pageSizeBytes - mem_block_offset : length; + length > _pageSizeBytes - mem_block_offset ? _pageSizeBytes - mem_block_offset : length; + LOG("Computed offsets. map_offset=%llu, mem_block_offset=%llu, first_write_size=%llu", + map_offset, mem_block_offset, first_write_size); return std::tuple(map_offset, mem_block_offset, first_write_size); } @@ -57,7 +60,11 @@ class CapioMemoryFile : public CapioFile { } public: - explicit CapioMemoryFile(const std::string &filePath) : CapioFile(filePath) {} + explicit CapioMemoryFile(const std::string &filePath) : CapioFile(filePath) { + cross_page_buffer_view = new char[_pageSizeBytes]; + } + + ~CapioMemoryFile() override { delete[] cross_page_buffer_view; } /** * Write data to a file stored inside the memory @@ -101,6 +108,7 @@ class CapioMemoryFile : public CapioFile { totalSize = std::max(totalSize, buffer_offset); return totalSize; } + /** * Read from Capio File * @param buffer Buffer to read to @@ -146,18 +154,20 @@ class CapioMemoryFile : public CapioFile { const auto &[map_offset, write_offset, first_write_size] = compute_offsets(offset, length); + auto remaining_bytes = length; + auto &block = memoryBlocks[map_offset]; block.resize(_pageSizeBytes); // reserve 4MB of space queue.read(block.data() + write_offset, first_write_size); // update remaining bytes to write - length -= first_write_size; + remaining_bytes -= first_write_size; size_t map_count = 1; // start from map following the one obtained from the first write // Variable to store the read offset of the input buffer auto buffer_offset = first_write_size; - while (length > 0) { + while (remaining_bytes > 0) { auto &next_block = memoryBlocks[map_offset + map_count]; next_block.resize(_pageSizeBytes); // reserve 4MB of space // Compute the actual size of the current write @@ -166,7 +176,7 @@ class CapioMemoryFile : public CapioFile { queue.read(next_block.data(), write_size); buffer_offset += write_size; map_count++; - length -= _pageSizeBytes; + remaining_bytes -= _pageSizeBytes; } totalSize = std::max(totalSize, offset + length); @@ -181,29 +191,29 @@ class CapioMemoryFile : public CapioFile { */ std::size_t writeToQueue(SPSCQueue &queue, std::size_t offset, std::size_t length) const override { + START_LOG(gettid(), "call(offset=%llu, length=%llu)", offset, length); std::size_t bytesRead = 0; - const auto &[map_offset, mem_block_offset_begin, buffer_view_size] = - compute_offsets(offset, length); + while (bytesRead < length) { + const auto [map_offset, mem_block_offset_begin, buffer_view_size] = + compute_offsets(offset, length - bytesRead); - // Traverse the memory blocks to read the requested data starting from the first block of - // date - for (auto it = memoryBlocks.lower_bound(map_offset); - it != memoryBlocks.end() && bytesRead < length; ++it) { - auto &[blockOffset, block] = *it; + if (const auto it = memoryBlocks.lower_bound(map_offset); it != memoryBlocks.end()) { + auto &[blockOffset, block] = *it; - if (blockOffset >= offset + length) { - break; // Past the requested range - } + if (blockOffset >= offset + length) { + return bytesRead; // Past the requested range + } - // Copy the data to the buffer - queue.write(block.data() + mem_block_offset_begin, buffer_view_size); + // Copy the data to the buffer + queue.write(block.data() + mem_block_offset_begin, buffer_view_size); - bytesRead += buffer_view_size; + bytesRead += buffer_view_size; + offset += buffer_view_size; + } } - return bytesRead; } }; -#endif // CAPIOMEMORYFILE_HPP +#endif // CAPIOMEMORYFILE_HPP \ No newline at end of file diff --git a/src/server/storage-service/capio_storage_service.hpp b/src/server/storage-service/capio_storage_service.hpp index d9d34a9e8..5de1c3d6d 100644 --- a/src/server/storage-service/capio_storage_service.hpp +++ b/src/server/storage-service/capio_storage_service.hpp @@ -10,7 +10,7 @@ class CapioStorageService { // TODO: put all of this conde on a different thread std::unordered_map *_client_to_server_queue; - std::unordered_map *_server_to_clien_queue; + std::unordered_map *_server_to_client_queue; std::unordered_map *_stored_files; std::unordered_map>> @@ -33,7 +33,7 @@ class CapioStorageService { START_LOG(gettid(), "call()"); _stored_files = new std::unordered_map; _client_to_server_queue = new std::unordered_map; - _server_to_clien_queue = new std::unordered_map; + _server_to_client_queue = new std::unordered_map; _threads_waiting_for_memory_data = new std::unordered_map>>; @@ -45,7 +45,7 @@ class CapioStorageService { // TODO: dump files to FS delete _stored_files; delete _client_to_server_queue; - delete _server_to_clien_queue; + delete _server_to_client_queue; delete _threads_waiting_for_memory_data; } @@ -114,11 +114,11 @@ class CapioStorageService { void register_client(const std::string &app_name, const pid_t pid) const { START_LOG(gettid(), "call(app_name=%s)", app_name.c_str()); _client_to_server_queue->emplace( - pid, new SPSCQueue("queue-" + std::to_string(pid) + +".cts", CAPIO_MAX_SPSQUEUE_ELEMS, - CAPIO_MAX_SPSCQUEUE_ELEM_SIZE, get_capio_workflow_name(), false)); - _server_to_clien_queue->emplace( - pid, new SPSCQueue("queue-" + std::to_string(pid) + +".stc", CAPIO_MAX_SPSQUEUE_ELEMS, - CAPIO_MAX_SPSCQUEUE_ELEM_SIZE, get_capio_workflow_name(), false)); + pid, new SPSCQueue("queue-" + std::to_string(pid) + +".cts", get_cache_lines(), + get_cache_line_size(), workflow_name, false)); + _server_to_client_queue->emplace( + pid, new SPSCQueue("queue-" + std::to_string(pid) + +".stc", get_cache_lines(), + get_cache_line_size(), workflow_name, false)); LOG("Created communication queues"); } @@ -134,7 +134,7 @@ class CapioStorageService { START_LOG(gettid(), "call(pid=%llu, file=%s, offset=%llu, size=%llu)", pid, file.c_str(), offset, size); - getFile(file)->writeToQueue(*_server_to_clien_queue->at(pid), offset, size); + getFile(file)->writeToQueue(*_server_to_client_queue->at(pid), offset, size); } /** @@ -148,13 +148,14 @@ class CapioStorageService { off64_t size) const { START_LOG(gettid(), "call(tid=%d, file=%s, offset=%lld, size=%lld)", tid, file.c_str(), offset, size); - - getFile(file)->readFromQueue(*_client_to_server_queue->at(tid), offset, size); + const auto f = getFile(file); + const auto queue = _client_to_server_queue->at(tid); + f->readFromQueue(*queue, offset, size); } void remove_client(const pid_t pid) const { _client_to_server_queue->erase(pid); - _server_to_clien_queue->erase(pid); + _server_to_client_queue->erase(pid); } /** @@ -165,10 +166,24 @@ class CapioStorageService { */ [[nodiscard]] size_t sendFilesToStoreInMemory(const long pid) const { START_LOG(gettid(), "call(pid=%d)", pid); + + if (StoreOnlyInMemory) { + LOG("All files should be handled in memory. sending * wildcard"); + char f[PATH_MAX + 1]{0}; + auto c_dir = get_capio_dir().string(); + memcpy(f, c_dir.c_str(), c_dir.length()); + memcpy(f + c_dir.size(), "/*", 2); + _server_to_client_queue->at(pid)->write(f, PATH_MAX); + LOG("Return value=%llu", 1); + return 1; + } + auto files_to_store_in_mem = capio_cl_engine->getFileToStoreInMemory(); for (const auto &file : files_to_store_in_mem) { LOG("Sending file %s", file.c_str()); - _server_to_clien_queue->at(pid)->write(file.c_str()); + char f[PATH_MAX + 1]{0}; + memcpy(f, file.c_str(), file.size()); + _server_to_client_queue->at(pid)->write(f, PATH_MAX); } LOG("Return value=%llu", files_to_store_in_mem.size()); @@ -178,4 +193,4 @@ class CapioStorageService { inline CapioStorageService *storage_service; -#endif // CAPIO_STORAGE_SERVICE_H +#endif // CAPIO_STORAGE_SERVICE_H \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 69f8a41bd..f3fd7597e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,5 +25,6 @@ include(GoogleTest) add_subdirectory(unit/posix) add_subdirectory(unit/server) add_subdirectory(unit/syscall) +add_subdirectory(unit/MemoryFiles) add_subdirectory(multinode/integration) add_subdirectory(multinode/backend) diff --git a/tests/unit/MemoryFiles/CMakeLists.txt b/tests/unit/MemoryFiles/CMakeLists.txt new file mode 100644 index 000000000..349f168c4 --- /dev/null +++ b/tests/unit/MemoryFiles/CMakeLists.txt @@ -0,0 +1,63 @@ +##################################### +# Target information +##################################### +set(TARGET_NAME capio_memory_file_unit_tests) +set(TARGET_INCLUDE_FOLDER "${PROJECT_SOURCE_DIR}/src/posix") +set(TARGET_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp +) + +##################################### +# Target definition +##################################### +add_executable(${TARGET_NAME} ${TARGET_SOURCES}) + +##################################### +# External projects +##################################### +set(SYSCALL_INTERCEPT_BINARY_DIR "${PROJECT_BINARY_DIR}/src/posix/syscall_intercept") +set(SYSCALL_INTERCEPT_INCLUDE_FOLDER + "${SYSCALL_INTERCEPT_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}") +set(SYSCALL_INTERCEPT_LIB_FOLDER + "${SYSCALL_INTERCEPT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +##################################### +# Definitions +##################################### +target_compile_definitions(${TARGET_NAME} PRIVATE __CAPIO_POSIX) + +##################################### +# Include files and directories +##################################### +file(GLOB_RECURSE CAPIO_POSIX_HEADERS "${TARGET_INCLUDE_FOLDER}/*.hpp") +file(GLOB_RECURSE SYSCALL_INTERCEPT_HEADERS "${SYSCALL_INTERCEPT_INCLUDE_FOLDER}/*.h") +target_sources(${TARGET_NAME} PRIVATE + "${CAPIO_COMMON_HEADERS}" + "${CAPIO_POSIX_HEADERS}" + "${GTEST_CONFIG_HEADERS}" + "${SYSCALL_INTERCEPT_HEADERS}" +) +target_include_directories(${TARGET_NAME} PRIVATE + "${TARGET_INCLUDE_FOLDER}" + "${SYSCALL_INTERCEPT_INCLUDE_FOLDER}" +) + +##################################### +# Link libraries +##################################### +target_link_directories(${TARGET_NAME} PRIVATE ${SYSCALL_INTERCEPT_LIB_FOLDER}) +target_link_libraries(${TARGET_NAME} PRIVATE rt syscall_intercept GTest::gtest_main) + +##################################### +# Configure tests +##################################### +gtest_discover_tests(${TARGET_NAME} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) + +##################################### +# Install rules +##################################### +install(TARGETS ${TARGET_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} +) \ No newline at end of file diff --git a/tests/unit/MemoryFiles/src/main.cpp b/tests/unit/MemoryFiles/src/main.cpp new file mode 100644 index 000000000..4c51b8cff --- /dev/null +++ b/tests/unit/MemoryFiles/src/main.cpp @@ -0,0 +1,137 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +char **build_args() { + char **args = (char **) malloc(4 * sizeof(uintptr_t)); + + char const *command = std::getenv("CAPIO_SERVER_PATH"); + if (command == nullptr) { + command = "capio_server"; + } + + args[0] = strdup(command); + args[1] = strdup("--no-config"); + args[2] = strdup("--mem-only"); + args[3] = (char *) nullptr; + + return args; +} + +char **build_env(char **envp) { + std::vector vars; + for (int i = 0; envp[i] != nullptr; i++) { + const std::string_view var(envp[i]); + const std::string_view key = var.substr(0, var.find('=')); + if (key != "LD_PRELOAD") { + vars.emplace_back(i); + } + } + + char **cleaned_env = (char **) malloc((vars.size() + 2) * sizeof(uintptr_t)); + for (int i = 0; i < vars.size(); i++) { + cleaned_env[i] = strdup(envp[i]); + } + + cleaned_env[vars.size()] = strdup("LD_PRELOAD="); + cleaned_env[vars.size() + 1] = (char *) nullptr; + + return cleaned_env; +} + +class CapioServerEnvironment : public testing::Environment { + private: + char **args; + char **envp; + int server_pid; + + public: + explicit CapioServerEnvironment(char **envp) + : args(build_args()), envp(build_env(envp)), server_pid(-1) {}; + + ~CapioServerEnvironment() override { + for (int i = 0; args[i] != nullptr; i++) { + free(args[i]); + } + free(args); + for (int i = 0; envp[i] != nullptr; i++) { + free(envp[i]); + } + free(envp); + }; + + void SetUp() override { + if (server_pid < 0) { + ASSERT_NE(std::getenv("CAPIO_DIR"), nullptr); + ASSERT_GE(server_pid = fork(), 0); + if (server_pid == 0) { + execvpe(args[0], args, envp); + std::cout << "Error: unable to start server" << std::endl; + _exit(127); + } else { + sleep(5); + } + } + } + + void TearDown() override { + if (server_pid > 0) { + kill(server_pid, SIGTERM); + waitpid(server_pid, nullptr, 0); + server_pid = -1; + } + } +}; + +const std::string filename = "hello.txt"; +constexpr size_t textSize = 32 * 1024 * 1024; // 32 MBB + +inline std::string generateLongText() { + std::string pattern = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"; + std::string longText; + while (longText.size() + pattern.size() <= textSize) { + longText += pattern; + } + // Pad the remaining bytes + if (longText.size() < textSize) { + longText.append(textSize - longText.size(), 'X'); + } + return longText; +} + +TEST(CapioMemoryFileTest, TestReadAndWrite32MBFile) { + std::string longText = generateLongText(); + + std::ofstream outFile(filename, std::ios::out | std::ios::binary); + EXPECT_TRUE(outFile.is_open()); + outFile.write(longText.c_str(), longText.size()); + outFile.close(); + + std::string fileContent(textSize, ' '); + std::ifstream inFile(filename, std::ios::in | std::ios::binary); + + EXPECT_TRUE(inFile.is_open()); + EXPECT_TRUE(inFile.read(fileContent.data(), fileContent.size())); + + inFile.close(); + + EXPECT_EQ(fileContent.size(), longText.size()); + + for (size_t i = 0; i < longText.size(); ++i) { + EXPECT_EQ(fileContent[i], longText[i]); + } +} + +int main(int argc, char **argv, char **envp) { + testing::InitGoogleTest(&argc, argv); + testing::AddGlobalTestEnvironment(new CapioServerEnvironment(envp)); + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/tests/unit/server/src/CapioCacheSPSCQueueTests.hpp b/tests/unit/server/src/CapioCacheSPSCQueueTests.hpp index 6912875c9..331aecdd2 100644 --- a/tests/unit/server/src/CapioCacheSPSCQueueTests.hpp +++ b/tests/unit/server/src/CapioCacheSPSCQueueTests.hpp @@ -15,10 +15,23 @@ inline CircularBuffer *buf_requests; #include "../posix/utils/cache.hpp" #include "SourceText.hpp" +auto checkStringEquality = [](const std::string &a, const std::string &b) { + size_t minLen = std::min(a.size(), b.size()); + for (size_t i = 0; i < minLen; ++i) { + if (a[i] != b[i]) { + std::cout << "Difference at offset " << i << ": '" << a[i] << "' vs '" << b[i] << "'\n"; + } + } + if (a.size() != b.size()) { + std::cout << "Strings have different lengths. input: " << a.size() + << ". check: " << b.size() << std::endl; + } +}; + WriteRequestCacheMEM *writeCache; ReadRequestCacheMEM *readCache; -int test_fd = 0; +int test_fd = -1; std::string test_file_name = "test.dat"; void init_server_data_structures() { @@ -69,16 +82,27 @@ TEST(CapioCacheSPSCQueue, TestWriteCacheWithSpscQueueWrite) { capio_files_descriptors->emplace(test_fd, test_file_name); files->insert({test_fd, {std::make_shared(0), 0, 0, false}}); + writeCache->write(test_fd, SOURCE_TEST_TEXT, long_test_length); + writeCache->flush(); + std::thread t1([long_test_length, tmp_buf] { cts_queue->read(tmp_buf->get(), long_test_length); - EXPECT_TRUE(strncmp(tmp_buf->get(), SOURCE_TEST_TEXT, long_test_length) == 0); - }); - writeCache->write(test_fd, SOURCE_TEST_TEXT, long_test_length); - writeCache->flush(); + // In the event a flush is triggered with a write of size 0, read again + if (strlen(tmp_buf->get()) == 0) { + cts_queue->read(tmp_buf->get(), long_test_length); + } + + if (strncmp(tmp_buf->get(), SOURCE_TEST_TEXT, long_test_length) != 0) { + checkStringEquality(std::string(tmp_buf->get()), std::string(SOURCE_TEST_TEXT)); + } + + EXPECT_EQ(strncmp(tmp_buf->get(), SOURCE_TEST_TEXT, long_test_length), 0); + }); t1.join(); + delete tmp_buf; delete_server_data_structures(); } @@ -91,6 +115,9 @@ TEST(CapioCacheSPSCQueue, TestWriteCacheSPSCQueueAndCapioFile) { capio_files_descriptors->emplace(test_fd, test_file_name); files->insert({test_fd, {std::make_shared(0), 0, 0, false}}); + writeCache->write(test_fd, SOURCE_TEST_TEXT, long_test_length); + writeCache->flush(); + std::thread t2([long_test_length, readBufSize] { CapioMemoryFile *testFile = new CapioMemoryFile(test_file_name); testFile->readFromQueue(*cts_queue, 0, long_test_length); @@ -104,9 +131,6 @@ TEST(CapioCacheSPSCQueue, TestWriteCacheSPSCQueueAndCapioFile) { delete testFile; }); - writeCache->write(test_fd, SOURCE_TEST_TEXT, long_test_length); - writeCache->flush(); - t2.join(); delete_server_data_structures(); @@ -222,6 +246,9 @@ TEST(CapioCacheSPSCQueue, TestWriteCacheSPSCQueueAndCapioFileWithRequestAndSeek) // perform to write ad a different offset writeCache->write(test_fd, SOURCE_TEST_TEXT, long_test_length); + // simulate Close on file + writeCache->flush(); + t3.join(); delete_server_data_structures(); @@ -338,31 +365,37 @@ TEST(CapioCacheSPSCQueue, TestReadCacheWithSpscQueueReadWithCapioFileAndSeek) { files->insert({test_fd, {std::make_shared(0), 0, 0, false}}); std::thread server_thread([long_test_length, response_tid] { + START_LOG(gettid(), "call(server_instance)"); int iteration = 0; CapioMemoryFile testFile(test_file_name); testFile.writeData(SOURCE_TEST_TEXT, 0, long_test_length); + LOG("Wrote data to server test file"); capio_off64_t total_data_sent = 0; while (total_data_sent < 2000) { - char req[CAPIO_REQ_MAX_SIZE]; + char req[CAPIO_REQ_MAX_SIZE]{0}; char file[1024]; - int code; + int code, use_cache; pid_t tid; capio_off64_t read_size, client_cache_line_size, read_begin_offset; - buf_requests->read(req, CAPIO_REQ_MAX_SIZE); - auto [ptr, ec] = std::from_chars(req, req + 4, code); - EXPECT_EQ(ec, std::errc()); - strcpy(req, ptr + 1); + buf_requests->read(req, CAPIO_REQ_MAX_SIZE); + LOG("Received request: %s", req); + sscanf(req, "%d %ld %llu %llu %llu %d %s", &code, &tid, &read_begin_offset, &read_size, + &client_cache_line_size, &use_cache, file); EXPECT_EQ(code, CAPIO_REQUEST_READ_MEM); - sscanf(req, "%ld %llu %llu %llu %s", &tid, &read_begin_offset, &read_size, - &client_cache_line_size, file); - + LOG("code: %d", code); + LOG("tid: %ld", tid); + LOG("read_begin_offset: %lld", read_begin_offset); + LOG("read_size: %lld", read_size); + LOG("client_cache_line_size: %lld", client_cache_line_size); + LOG("use_cache: %lld", use_cache); + LOG("file: %s", file); auto size_to_send = read_size < client_cache_line_size ? read_size : client_cache_line_size; - + LOG("Sending %ld data", size_to_send); bufs_response->at(response_tid)->write(size_to_send); testFile.writeToQueue(*stc_queue, read_begin_offset, size_to_send); total_data_sent += size_to_send; @@ -381,10 +414,11 @@ TEST(CapioCacheSPSCQueue, TestReadCacheWithSpscQueueReadWithCapioFileAndSeek) { tmp_buf_ptr += new_offset; readCache->read(test_fd, tmp_buf_ptr, 1000); + // checkStringEquality(SOURCE_TEST_TEXT + new_offset, tmp_buf->get() + new_offset); EXPECT_EQ(strncmp(SOURCE_TEST_TEXT + new_offset, tmp_buf->get() + new_offset, 1000), 0); server_thread.join(); delete_server_data_structures(); } -#endif // CAPIOCACHESPSCQUEUETESTS_HPP +#endif // CAPIOCACHESPSCQUEUETESTS_HPP \ No newline at end of file diff --git a/tests/unit/server/src/CapioFileTests.hpp b/tests/unit/server/src/CapioFileTests.hpp index 9b37c367d..d5a7ae40e 100644 --- a/tests/unit/server/src/CapioFileTests.hpp +++ b/tests/unit/server/src/CapioFileTests.hpp @@ -53,37 +53,6 @@ TEST(CapioMemoryFileTest, TestHugeFileOnMultiplePages) { delete[] input_buffer4; } -/* - * WARNING: This test uses files that are too big to be handled by the CI/CD on github, - * and as such it has been disabled. Nevertheless this test can be executed locally - * -TEST(CapioMemoryFileTest, TestHugeFileOnMultiplePagesThatStartOnDifferentOffset) { - CapioMemoryFile file1("test.txt"); - capio_off64_t LONG_TEXT_SIZE = 1024 * 1024 * 16; - auto LONG_TEXT = new char[LONG_TEXT_SIZE]{}; // 16 MB string - for (capio_off64_t i = 0; i < LONG_TEXT_SIZE; i++) { - LONG_TEXT[i] = 'A' + (random() % 26); - } - - auto input_buffer4 = new char[LONG_TEXT_SIZE + 1]{}; - bool write_count_match = file1.writeData(LONG_TEXT, 2048, LONG_TEXT_SIZE) == LONG_TEXT_SIZE; - EXPECT_TRUE(write_count_match); - - file1.readData(input_buffer4, 2048, LONG_TEXT_SIZE); - - bool ok = true; - for (capio_off64_t i = 0; i < LONG_TEXT_SIZE && ok; i++) { - ok &= (LONG_TEXT[i] == input_buffer4[i]); - if (!ok) { - std::cout << "Check failed at byte " << i << " out of " << LONG_TEXT_SIZE << std::endl; - } - } - EXPECT_TRUE(ok); - - delete LONG_TEXT; -} -*/ - TEST(CapioMemoryFileTest, TestWriteAndRead) { CapioMemoryFile file("test.txt"); diff --git a/tests/unit/syscall/src/main.cpp b/tests/unit/syscall/src/main.cpp index 954fb51aa..bc5961c3a 100644 --- a/tests/unit/syscall/src/main.cpp +++ b/tests/unit/syscall/src/main.cpp @@ -43,7 +43,7 @@ class CapioServerEnvironment : public testing::Environment { public: explicit CapioServerEnvironment(char **envp) - : args(build_args()), envp(build_env(envp)), server_pid(-1){}; + : args(build_args()), envp(build_env(envp)), server_pid(-1) {}; ~CapioServerEnvironment() override { for (int i = 0; args[i] != nullptr; i++) { diff --git a/tests/unit/syscall/src/stat.cpp b/tests/unit/syscall/src/stat.cpp index de2198f2d..e643ee53d 100644 --- a/tests/unit/syscall/src/stat.cpp +++ b/tests/unit/syscall/src/stat.cpp @@ -23,7 +23,7 @@ TEST(SystemCallTest, TestStatOnFile) { EXPECT_EQ(access(PATHNAME, F_OK), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(stat(PATHNAME, &statbuf), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlink(PATHNAME), -1); @@ -34,7 +34,7 @@ TEST(SystemCallTest, TestStatOnDirectory) { constexpr const char *PATHNAME = "test"; EXPECT_NE(mkdir(PATHNAME, S_IRWXU), -1); EXPECT_EQ(access(PATHNAME, F_OK), 0); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(stat(PATHNAME, &statbuf), 0); check_statbuf(statbuf, 4096); EXPECT_NE(rmdir(PATHNAME), -1); @@ -42,7 +42,7 @@ TEST(SystemCallTest, TestStatOnDirectory) { } TEST(SystemCallTest, TestStatOnNonexistentFile) { - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(stat("test", &statbuf), -1); EXPECT_EQ(errno, ENOENT); } @@ -55,7 +55,7 @@ TEST(SystemCallTest, TestFstatOnFile) { EXPECT_NE(fd, -1); EXPECT_EQ(access(PATHNAME, F_OK), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstat(fd, &statbuf), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(close(fd), -1); @@ -70,7 +70,7 @@ TEST(SystemCallTest, TestFstatOnDirectory) { int flags = O_RDONLY | O_DIRECTORY; int fd = open(PATHNAME, flags, S_IRUSR | S_IWUSR); EXPECT_NE(fd, -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstat(fd, &statbuf), 0); check_statbuf(statbuf, 4096); EXPECT_NE(close(fd), -1); @@ -79,7 +79,7 @@ TEST(SystemCallTest, TestFstatOnDirectory) { } TEST(SystemCallTest, TestFstatOnInvalidFd) { - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstat(-1, &statbuf), -1); EXPECT_EQ(errno, EBADF); } @@ -93,7 +93,7 @@ TEST(SystemCallTest, TestFstatatOnFileWithAtFdcwd) { EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(AT_FDCWD, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(AT_FDCWD, PATHNAME, 0), -1); @@ -104,7 +104,7 @@ TEST(SystemCallTest, TestFstatatOnDirectoryWithAtFdcwd) { constexpr const char *PATHNAME = "test"; EXPECT_NE(mkdirat(AT_FDCWD, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(AT_FDCWD, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, 4096); EXPECT_NE(unlinkat(AT_FDCWD, PATHNAME, AT_REMOVEDIR), -1); @@ -122,7 +122,7 @@ TEST(SystemCallTest, TestFstatatOnFileInDifferentDirectoryWithAbsolutePath) { EXPECT_EQ(faccessat(0, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(0, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(0, PATHNAME, 0), -1); @@ -134,7 +134,7 @@ TEST(SystemCallTest, TestFstatatOnDirectoryInDifferentDirectoryWithAbsolutePath) const char *PATHNAME = path_fs.c_str(); EXPECT_NE(mkdirat(0, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(0, PATHNAME, F_OK, 0), 0); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(0, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, 4096); EXPECT_NE(unlinkat(0, PATHNAME, AT_REMOVEDIR), -1); @@ -152,7 +152,7 @@ TEST(SystemCallTest, TestFstatatOnFileInDifferentDirectoryWithDirfd) { EXPECT_EQ(faccessat(dirfd, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(dirfd, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(dirfd, PATHNAME, 0), -1); @@ -167,7 +167,7 @@ TEST(SystemCallTest, TestFstatatOnDirectoryInDifferentDirectoryWithDirfd) { EXPECT_NE(dirfd, -1); EXPECT_NE(mkdirat(dirfd, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(dirfd, PATHNAME, F_OK, 0), 0); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(dirfd, PATHNAME, &statbuf, 0), 0); check_statbuf(statbuf, 4096); EXPECT_NE(unlinkat(dirfd, PATHNAME, AT_REMOVEDIR), -1); @@ -176,7 +176,7 @@ TEST(SystemCallTest, TestFstatatOnDirectoryInDifferentDirectoryWithDirfd) { } TEST(SystemCallTest, TwstFstatatWithAtEmptyPathAndAtFdcwd) { - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(AT_FDCWD, "", &statbuf, AT_EMPTY_PATH), 0); check_statbuf(statbuf, 4096); } @@ -188,7 +188,7 @@ TEST(SystemCallTest, TestFstatatOnFileWithAtEmptyPathAndDirfd) { int dirfd = openat(AT_FDCWD, PATHNAME, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(dirfd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(dirfd, "", &statbuf, AT_EMPTY_PATH), 0); check_statbuf(statbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(close(dirfd), -1); @@ -202,7 +202,7 @@ TEST(SystemCallTest, TestFstatatOnDirectoryWIthAtEmptyPathAndDirfd) { EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); int dirfd = openat(AT_FDCWD, PATHNAME, O_RDONLY | O_DIRECTORY); EXPECT_NE(dirfd, -1); - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(dirfd, "", &statbuf, AT_EMPTY_PATH), 0); check_statbuf(statbuf, 4096); EXPECT_NE(close(dirfd), -1); @@ -211,20 +211,20 @@ TEST(SystemCallTest, TestFstatatOnDirectoryWIthAtEmptyPathAndDirfd) { } TEST(SystemCallTest, TestFstatatOnNonexistentFile) { - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(AT_FDCWD, "test", &statbuf, 0), -1); EXPECT_EQ(errno, ENOENT); } TEST(SystemCallTest, TestFstatatOnRelativePathWithInvalidDirfd) { constexpr const char *PATHNAME = "test"; - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(-1, PATHNAME, &statbuf, 0), -1); EXPECT_EQ(errno, EBADF); } TEST(SystemCallTest, TestFstatatWithEmptyPathAndNoAtEmptyPath) { - struct stat statbuf {}; + struct stat statbuf{}; EXPECT_EQ(fstatat(AT_FDCWD, "", &statbuf, 0), -1); EXPECT_EQ(errno, ENOENT); } diff --git a/tests/unit/syscall/src/statx.cpp b/tests/unit/syscall/src/statx.cpp index 9191c73d5..adff1ef38 100644 --- a/tests/unit/syscall/src/statx.cpp +++ b/tests/unit/syscall/src/statx.cpp @@ -22,7 +22,7 @@ TEST(SystemCallTest, TestStatxOnFileWithAtFdcwd) { EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(AT_FDCWD, PATHNAME, 0), -1); @@ -33,7 +33,7 @@ TEST(SystemCallTest, TestStatxOnDirectoryWithAtFdcwd) { constexpr const char *PATHNAME = "test"; EXPECT_NE(mkdirat(AT_FDCWD, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, 4096); EXPECT_NE(unlinkat(AT_FDCWD, PATHNAME, AT_REMOVEDIR), -1); @@ -51,7 +51,7 @@ TEST(SystemCallTest, TestStatxOnFileInDifferentDirectoryWithAbsolutePath) { EXPECT_EQ(faccessat(0, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(0, PATHNAME, 0), -1); @@ -63,7 +63,7 @@ TEST(SystemCallTest, TestStatxOnDirectoryInDifferentDirectoryWithAbsoluePath) { const char *PATHNAME = path_fs.c_str(); EXPECT_NE(mkdirat(0, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(0, PATHNAME, F_OK, 0), 0); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, 4096); EXPECT_NE(unlinkat(0, PATHNAME, AT_REMOVEDIR), -1); @@ -81,7 +81,7 @@ TEST(SystemCallTest, TestStatxOnFileInDifferentDirectoryWithDirfd) { EXPECT_EQ(faccessat(dirfd, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(fd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); EXPECT_NE(close(fd), -1); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(dirfd, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(unlinkat(dirfd, PATHNAME, 0), -1); @@ -96,7 +96,7 @@ TEST(SystemCallTest, TestStatxOnDirectoryInDifferentDirectoryWithDirfd) { EXPECT_NE(dirfd, -1); EXPECT_NE(mkdirat(dirfd, PATHNAME, S_IRWXU), -1); EXPECT_EQ(faccessat(dirfd, PATHNAME, F_OK, 0), 0); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(dirfd, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, 4096); EXPECT_NE(unlinkat(dirfd, PATHNAME, AT_REMOVEDIR), -1); @@ -105,7 +105,7 @@ TEST(SystemCallTest, TestStatxOnDirectoryInDifferentDirectoryWithDirfd) { } TEST(SystemCallTest, TestStatxWithAtEmptyPathAndAtFdcwd) { - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, "", AT_EMPTY_PATH, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, 4096); } @@ -117,7 +117,7 @@ TEST(SystemCallTest, TestStatxOnFileWithAtEmptyPathAndDirfd) { int dirfd = openat(AT_FDCWD, PATHNAME, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); EXPECT_EQ(write(dirfd, BUFFER, strlen(BUFFER)), strlen(BUFFER)); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(dirfd, "", AT_EMPTY_PATH, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, strlen(BUFFER) * sizeof(char)); EXPECT_NE(close(dirfd), -1); @@ -131,7 +131,7 @@ TEST(SystemCallTest, TestStatxOnDirectoryWithAtEmptyPathAndDirfd) { EXPECT_EQ(faccessat(AT_FDCWD, PATHNAME, F_OK, 0), 0); int dirfd = openat(AT_FDCWD, PATHNAME, O_RDONLY | O_DIRECTORY); EXPECT_NE(dirfd, -1); - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(dirfd, "", AT_EMPTY_PATH, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), 0); check_statxbuf(statxbuf, 4096); EXPECT_NE(close(dirfd), -1); @@ -140,27 +140,27 @@ TEST(SystemCallTest, TestStatxOnDirectoryWithAtEmptyPathAndDirfd) { } TEST(SystemCallTest, TestStatxOnNonexistentFile) { - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, "test", 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), -1); EXPECT_EQ(errno, ENOENT); } TEST(SystemCallTest, TestStatxOnRelativePathWithInvalidDirfd) { constexpr const char *PATHNAME = "test"; - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(-1, PATHNAME, 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), -1); EXPECT_EQ(errno, EBADF); } TEST(SystemCallTest, TestStatxWithStatxReservedSet) { constexpr const char *PATHNAME = "test"; - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(-1, PATHNAME, 0, STATX__RESERVED, &statxbuf), -1); EXPECT_EQ(errno, EINVAL); } TEST(SystemCallTest, TestStatxWithEmptyPathAndNoEmptyPath) { - struct statx statxbuf {}; + struct statx statxbuf{}; EXPECT_EQ(statx(AT_FDCWD, "", 0, STATX_BASIC_STATS | STATX_BTIME, &statxbuf), -1); EXPECT_EQ(errno, ENOENT); } \ No newline at end of file