diff --git a/.github/workflows/publish-conan-branch-package.yml b/.github/workflows/publish-conan-branch-package.yml index ad5a309..cdb59a2 100644 --- a/.github/workflows/publish-conan-branch-package.yml +++ b/.github/workflows/publish-conan-branch-package.yml @@ -10,10 +10,10 @@ jobs: uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-conan-branch-package.yml@main with: public_artifactory: true - os: ubuntu-22.04 - compiler: clang-15 + os: ubuntu-24.04 + compiler: clang-20 cmake-version: 3.22.6 - conan-version: 2.3.0 + conan-version: 2.17.0 conan-options: -o boost/*:header_only=True secrets: CONAN_USER: ${{ secrets.CONAN_USER }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b7ce28c..bdb5f47 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -16,10 +16,10 @@ jobs: uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-release.yml@main with: public_artifactory: true - os: ubuntu-22.04 - compiler: clang-15 + os: ubuntu-24.04 + compiler: clang-20 cmake-version: 3.22.6 - conan-version: 2.3.0 + conan-version: 2.17.0 conan-options: -o boost/*:header_only=True secrets: CONAN_USER: ${{ secrets.CONAN_USER }} diff --git a/conanfile.py b/conanfile.py index 74b012a..a9096d6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -29,7 +29,7 @@ class Recipe(ConanFile): generators = "CMakeDeps", "CMakeToolchain" def requirements(self): - self.requires("metall/0.28", transitive_headers=True) + self.requires("metall/0.32", transitive_headers=True) if self.options.with_test_deps: self.requires("doctest/2.4.11") diff --git a/src/dice/ffi/metall.cpp b/src/dice/ffi/metall.cpp index 59841f1..9d05743 100644 --- a/src/dice/ffi/metall.cpp +++ b/src/dice/ffi/metall.cpp @@ -7,17 +7,16 @@ using metall_manager_t = dice::metall_ffi::internal::metall_manager; template metall_manager *open_impl(char const *path) { - if (!metall::manager::consistent(path)) { - // prevents opening the same datastore twice - // (because opening removes the properly_closed_mark and this checks for it) - errno = ENOTRECOVERABLE; - return nullptr; - } - auto *manager = new metall_manager_t{open_mode, path}; if (!manager->check_sanity()) { delete manager; - errno = ENOTRECOVERABLE; + + if (!metall::manager::consistent(path)) { + errno = ENOTRECOVERABLE; + } else { + errno = EBUSY; + } + return nullptr; } diff --git a/src/dice/ffi/metall.h b/src/dice/ffi/metall.h index 0981db1..a27764b 100644 --- a/src/dice/ffi/metall.h +++ b/src/dice/ffi/metall.h @@ -37,7 +37,9 @@ typedef struct metall_manager metall_manager; * @brief Attempts to open the metall datastore at path * @param path path to datastore * @return true on success, false on failure. On failure, sets errno to one of the following values: - * - ENOTRECOVERABLE if the given metall datastore is inconsistent + * - ENOTRECOVERABLE if the given metall datastore is inconsistent, or if it is currently open as read-write + * by a previous call to metall_open or metall_create + * - EBUSY if the given metall datastore is already open as read-only */ metall_manager *metall_open(char const *path); diff --git a/tests/tests_Sanity.cpp b/tests/tests_Sanity.cpp index 8eecee5..13436dd 100644 --- a/tests/tests_Sanity.cpp +++ b/tests/tests_Sanity.cpp @@ -128,4 +128,41 @@ TEST_SUITE("metall-ffi") { FAIL("Did not refuse to allocate"); } } + + TEST_CASE("open read-only then read-write") { + std::string const path = "/tmp/" + std::to_string(std::random_device{}()); + + // create datastore + { + metall_manager *mgr = metall_create(path.c_str()); + metall_close(mgr); + } + + metall_manager *mgr_ro = metall_open_read_only(path.c_str()); + CHECK_NE(mgr_ro, nullptr); + + metall_manager *mgr_ro2 = metall_open_read_only(path.c_str()); + CHECK_NE(mgr_ro2, nullptr); + + metall_manager *mgr_rw = metall_open(path.c_str()); + CHECK_EQ(mgr_rw, nullptr); + CHECK_EQ(errno, EBUSY); + + metall_close(mgr_ro); + + metall_manager *mgr_rw2 = metall_open(path.c_str()); + CHECK_EQ(mgr_rw2, nullptr); + CHECK_EQ(errno, EBUSY); + + metall_close(mgr_ro2); + + metall_manager *mgr_rw3 = metall_open(path.c_str()); + CHECK_NE(mgr_rw3, nullptr); + + metall_manager *mgr_rw4 = metall_open(path.c_str()); + CHECK_EQ(mgr_rw4, nullptr); + CHECK_EQ(errno, ENOTRECOVERABLE); + + metall_close(mgr_rw3); + } }