Commit 1e310bdd authored by Ramon Nou's avatar Ramon Nou
Browse files

Fix replication repair bitmap crash during client teardown

parent 2f870f2c
Loading
Loading
Loading
Loading
Loading
+8 −4
Changes for src/common/rpc/rpc_util.cpp: 8 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
*/

#include <common/rpc/rpc_util.hpp>
#include <string_view>

extern "C" {
#include <unistd.h>
@@ -123,7 +124,8 @@ get_host_by_name(const string& hostname) {
 */
bool
get_bitset(const std::vector<uint8_t>& data, const uint16_t position) {
    return (data[(position) / 8] & 1 << ((position) % 8));
    return position / 8 < data.size() &&
           (data[position / 8] & (1 << (position % 8)));
}

/**
@@ -139,7 +141,9 @@ set_bitset(std::vector<uint8_t>& data, const uint16_t position) {

std::string
base64_encode(const std::vector<uint8_t>& data) {
    static const std::string base64_chars =
    // Repair workers can encode during process teardown. Do not use a
    // function-static owning string whose destructor may have already run.
    static constexpr std::string_view base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    std::ostringstream encoded;
@@ -169,7 +173,7 @@ base64_encode(const std::vector<uint8_t>& data) {

std::vector<uint8_t>
base64_decode(const std::string& encoded) {
    static const std::string base64_chars =
    static constexpr std::string_view base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    std::vector<uint8_t> data;
@@ -182,7 +186,7 @@ base64_decode(const std::string& encoded) {
            break;

        std::size_t value = base64_chars.find(c);
        if(value == std::string::npos)
        if(value == std::string_view::npos)
            continue;

        buffer = (buffer << 6) | value;
+1 −0
Changes for tests/integration/data/test_replication.py: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -282,6 +282,7 @@ def test_replication_workload_survives_daemon_kill(
        assert opened.retval != -1
        written = gkfs_client.write_validate(degraded_file, payload_size)
        assert written.retval == 0
        assert d00._proc.poll() is None, "surviving daemon crashed during degraded I/O"
        degraded_stat = gkfs_client.stat(degraded_file)
        assert degraded_stat.retval == 0
        assert degraded_stat.statbuf.st_size == payload_size
+1 −0
Changes for tests/unit/CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ target_sources(unit_tests
    ${CMAKE_CURRENT_LIST_DIR}/test_distributor_factory_and_migrator.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_random_slicing_pipeline.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_env_util.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_rpc_bitset.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_stats.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_unique_fd.cpp
    ${CMAKE_CURRENT_LIST_DIR}/test_repair_journal_lock.cpp
+27 −0
Changes for tests/unit/test_rpc_bitset.cpp: 27 added lines, 0 removed lines.
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-3.0-or-later

#include <common/rpc/rpc_util.hpp>
#include <catch2/catch_test_macros.hpp>

TEST_CASE("RPC chunk bitmaps round trip", "[rpc][bitset]") {
    REQUIRE(gkfs::rpc::compress_bitset(std::vector<uint8_t>{1}) == "AQ==");
    for(std::size_t size = 1; size <= 128; ++size) {
        std::vector<uint8_t> bitmap(size, 0);
        gkfs::rpc::set_bitset(bitmap, 0);
        gkfs::rpc::set_bitset(bitmap, size * 8 - 1);
        auto decoded = gkfs::rpc::decompress_bitset(
                gkfs::rpc::compress_bitset(bitmap));
        REQUIRE(decoded == bitmap);
        REQUIRE(gkfs::rpc::get_bitset(decoded, 0));
        REQUIRE(gkfs::rpc::get_bitset(decoded, size * 8 - 1));
        REQUIRE_FALSE(gkfs::rpc::get_bitset(decoded, size * 8));
    }
}

TEST_CASE("Missing RPC bitmap bits are not selected", "[rpc][bitset]") {
    REQUIRE_FALSE(gkfs::rpc::get_bitset({}, 0));
    REQUIRE_FALSE(gkfs::rpc::get_bitset({}, 65535));
    auto malformed = gkfs::rpc::decompress_bitset("?Q==");
    REQUIRE(malformed.empty());
    REQUIRE_FALSE(gkfs::rpc::get_bitset(malformed, 0));
}
 No newline at end of file