Skip to content

Commit 9b8e9cd

Browse files
committed
MB-66479: Run cluster_test with magma backend and fix hang
The snapshot test for instance will use a different code path to collect the files in use which revealed a bug in GetFileFragment causing it to hang forever when trying to fetch multiple files as the state machinery didn't clear the EWB state from "too much data" Change-Id: Ib8fe47d9a3f416721f170f6018a125be1d701bb2 Reviewed-on: https://review.couchbase.org/c/kv_engine/+/226984 Reviewed-by: Vesko Karaganev <vesko.karaganev@couchbase.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 8084ce5 commit 9b8e9cd

File tree

8 files changed

+95
-14
lines changed

8 files changed

+95
-14
lines changed

cluster_framework/cluster.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@
2424

2525
namespace cb::test {
2626

27+
std::string format_as(BucketPersistenceBackend backend) {
28+
switch (backend) {
29+
case BucketPersistenceBackend::Couchstore:
30+
return "couchdb";
31+
case BucketPersistenceBackend::Magma:
32+
return "magma";
33+
}
34+
Expects(false && "Unexpected backend");
35+
}
36+
37+
void to_json(nlohmann::json& j, const BucketPersistenceBackend backend) {
38+
j = format_as(backend);
39+
}
40+
2741
Cluster::~Cluster() = default;
2842

2943
class ClusterImpl : public Cluster {
@@ -33,6 +47,13 @@ class ClusterImpl : public Cluster {
3347
ClusterImpl(std::vector<std::unique_ptr<Node>>& nod,
3448
std::filesystem::path dir);
3549
~ClusterImpl() override;
50+
void setBucketPersistenceBackend(
51+
BucketPersistenceBackend backend_) override {
52+
backend = backend_;
53+
}
54+
BucketPersistenceBackend getBucketPersistenceBackend() const override {
55+
return backend;
56+
}
3657
[[nodiscard]] std::shared_ptr<Bucket> createBucket(
3758
const std::string& name,
3859
const nlohmann::json& attributes,
@@ -76,6 +97,7 @@ class ClusterImpl : public Cluster {
7697
const std::string uuid;
7798
std::atomic<int64_t> revno{1};
7899
static constexpr int64_t epoch = 1;
100+
BucketPersistenceBackend backend = BucketPersistenceBackend::Couchstore;
79101
};
80102

81103
ClusterImpl::ClusterImpl(std::vector<std::unique_ptr<Node>>& nod,
@@ -239,7 +261,7 @@ std::shared_ptr<Bucket> ClusterImpl::createBucket(
239261
size_t replicas = std::min<size_t>(size() - 1, 3);
240262

241263
nlohmann::json json = {{"max_size", 67108864},
242-
{"backend", "couchdb"},
264+
{"backend", backend},
243265
{"couch_bucket", name},
244266
{"max_vbuckets", vbuckets},
245267
{"data_traffic_enabled", false},

cluster_framework/cluster.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class MemcachedConnection;
2323

2424
namespace cb::test {
2525

26+
enum class BucketPersistenceBackend { Couchstore, Magma };
27+
std::string format_as(BucketPersistenceBackend backend);
28+
void to_json(nlohmann::json& j, const BucketPersistenceBackend backend);
29+
2630
class Node;
2731
class Bucket;
2832
class AuthProviderService;
@@ -37,6 +41,11 @@ class Cluster {
3741
public:
3842
virtual ~Cluster();
3943

44+
/// Set the backend to use for buckets
45+
virtual void setBucketPersistenceBackend(
46+
BucketPersistenceBackend backend) = 0;
47+
virtual BucketPersistenceBackend getBucketPersistenceBackend() const = 0;
48+
4049
/**
4150
* Create a Couchbase bucket
4251
*

daemon/protocol/mcbp/get_file_fragment_context.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ cb::engine_errc GetFileFragmentContext::step() {
8383
ret = transfer_with_sendfile();
8484
break;
8585
case State::Done:
86+
cookie.clearEwouldblock();
8687
return cb::engine_errc::success;
8788
}
8889
}
@@ -272,6 +273,11 @@ cb::engine_errc GetFileFragmentContext::chain_file_chunk() {
272273
iob->length()};
273274
connection.chainDataToOutputStream(
274275
std::make_unique<IOBufSendBuffer>(std::move(iob), view));
275-
state = State::ReadFileChunk;
276+
if (length) {
277+
// We need to read another chunk
278+
state = State::ReadFileChunk;
279+
} else {
280+
state = State::Done;
281+
}
276282
return cb::engine_errc::too_much_data_in_output_buffer;
277283
}

tests/testapp_cluster/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,15 @@ add_test(NAME cluster_test
2828
# Don't run it concurrently with any other tests.
2929
set_tests_properties(cluster_test
3030
PROPERTIES RUN_SERIAL TRUE)
31+
32+
if (BUILD_ENTERPRISE AND NOT WIN32)
33+
# Magma emits a lot of critical warnings and fails on
34+
# win32 due to failing to open files.
35+
# Only run on other platforms for now
36+
add_test(NAME cluster_test_magma
37+
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
38+
COMMAND cluster_test --backend=magma)
39+
# The cluster_test spins up 4 memcached instances and is relatively heavyweight.
40+
# Don't run it concurrently with any other tests.
41+
set_tests_properties(cluster_test_magma PROPERTIES RUN_SERIAL TRUE)
42+
endif()

tests/testapp_cluster/clustertest.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ std::ostream& cb::test::operator<<(std::ostream& os,
2626
<< " MiB, upper: " << stats.upper / 1024.0 / 1024.0 << " MiB}";
2727
}
2828

29-
void cb::test::ClusterTest::StartCluster() {
29+
void cb::test::ClusterTest::StartCluster(BucketPersistenceBackend backend) {
3030
MemcachedConnection::setLookupUserPasswordFunction(
3131
[](const std::string& user) -> std::string {
3232
if (user == "@admin") {
@@ -45,6 +45,7 @@ void cb::test::ClusterTest::StartCluster() {
4545
});
4646

4747
cluster = Cluster::create(4);
48+
cluster->setBucketPersistenceBackend(backend);
4849
if (!cluster) {
4950
std::cerr << "Failed to create the cluster" << std::endl;
5051
std::exit(EXIT_FAILURE);

tests/testapp_cluster/clustertest.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace cb::test {
2020

2121
class Bucket;
2222
class Cluster;
23+
enum class BucketPersistenceBackend;
2324

2425
struct MemStats {
2526
size_t current{0};
@@ -52,7 +53,7 @@ class ClusterTest : public ::testing::Test {
5253
static void TearDownTestCase();
5354

5455
/// Start the cluster with 4 nodes.
55-
static void StartCluster();
56+
static void StartCluster(BucketPersistenceBackend backend);
5657

5758
/// Shutdown the cluster
5859
static void ShutdownCluster();

tests/testapp_cluster/main.cc

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@
88
* the file licenses/APL2.txt.
99
*/
1010

11+
#include "cluster_framework/cluster.h"
1112
#include "clustertest.h"
12-
1313
#include <event2/thread.h>
1414
#include <platform/cbassert.h>
15+
#include <platform/command_line_options_parser.h>
1516
#include <platform/dirutils.h>
1617
#include <platform/platform_socket.h>
1718
#include <array>
1819
#include <csignal>
1920
#include <cstdlib>
2021
#include <string>
2122

23+
using cb::test::BucketPersistenceBackend;
24+
using namespace std::string_view_literals;
25+
2226
int main(int argc, char** argv) {
2327
setupWindowsDebugCRTAssertHandling();
2428
cb::net::initialize();
@@ -61,8 +65,38 @@ int main(int argc, char** argv) {
6165
}
6266
#endif
6367
::testing::InitGoogleTest(&argc, argv);
68+
auto backend = BucketPersistenceBackend::Couchstore;
69+
70+
cb::getopt::CommandLineOptionsParser parser;
71+
using cb::getopt::Argument;
72+
parser.addOption(
73+
{[&backend](auto value) {
74+
if (value == "magma"sv) {
75+
backend = BucketPersistenceBackend::Magma;
76+
} else if (value == "couchstore"sv) {
77+
backend = BucketPersistenceBackend::Couchstore;
78+
} else {
79+
std::cerr << "backend must be 'couchstore' or 'magma'"
80+
<< std::endl;
81+
exit(EXIT_FAILURE);
82+
}
83+
},
84+
"backend",
85+
Argument::Required,
86+
"magma",
87+
"The name of the backend"});
88+
89+
parser.addOption({[&parser](auto) {
90+
std::cout << std::endl
91+
<< std::endl
92+
<< parser << std::endl;
93+
},
94+
"help",
95+
"This help text"});
96+
97+
parser.parse(argc, argv, [&parser]() { std::exit(EXIT_FAILURE); });
6498

65-
cb::test::ClusterTest::StartCluster();
99+
cb::test::ClusterTest::StartCluster(backend);
66100
const auto ret = RUN_ALL_TESTS();
67101
cb::test::ClusterTest::ShutdownCluster();
68102

tests/testapp_cluster/misc_tests.cc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -458,14 +458,10 @@ TEST_F(BasicClusterTest, AllStatGroups) {
458458
// These require a vbucket argument.
459459
key += " 0";
460460
break;
461-
case StatGroupId::Fusion: {
462-
if (conn->statsMap("")["ep_backend"] != "magma") {
463-
return;
464-
}
465-
// These require a existing subcmd and a vbucket argument.
466-
key += " sync_info 0";
467-
break;
468-
}
461+
case StatGroupId::Fusion:
462+
// Fusion stats isn't implemented currently in the cluster
463+
// testsuite
464+
return;
469465
default:
470466
break;
471467
}

0 commit comments

Comments
 (0)