summaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/CMakeLists.txt1
-rw-r--r--src/test/ObjectMap/KeyValueDBMemory.cc21
-rw-r--r--src/test/admin_socket.cc2
-rw-r--r--src/test/admin_socket_output.h1
-rw-r--r--src/test/bench_log.cc3
-rw-r--r--src/test/bufferlist.cc2
-rw-r--r--src/test/ceph_argparse.cc1
-rw-r--r--src/test/cli/radosgw-admin/help.t3
-rw-r--r--src/test/cli/rbd/help.t7
-rw-r--r--src/test/client/TestClient.h1
-rw-r--r--src/test/cls_log/test_cls_log.cc1
-rw-r--r--src/test/cls_rbd/test_cls_rbd.cc6
-rw-r--r--src/test/cls_rgw/test_cls_rgw_stats.cc1
-rw-r--r--src/test/common/CMakeLists.txt6
-rw-r--r--src/test/common/Throttle.cc1
-rw-r--r--src/test/common/test_async_shared_mutex.cc1
-rw-r--r--src/test/common/test_cdc.cc1
-rw-r--r--src/test/common/test_config.cc3
-rw-r--r--src/test/common/test_context.cc3
-rw-r--r--src/test/common/test_htmlformatter.cc26
-rw-r--r--src/test/common/test_intrusive_lru.cc22
-rw-r--r--src/test/common/test_json_formatter.cc24
-rw-r--r--src/test/common/test_shared_cache.cc3
-rw-r--r--src/test/common/test_tableformatter.cc17
-rw-r--r--src/test/common/test_time.cc2
-rw-r--r--src/test/common/test_url_escape.cc2
-rw-r--r--src/test/common/test_xmlformatter.cc22
-rw-r--r--src/test/compressor/test_compression.cc3
-rw-r--r--src/test/crimson/seastore/test_block.h14
-rw-r--r--src/test/crimson/seastore/test_btree_lba_manager.cc45
-rw-r--r--src/test/crimson/seastore/test_cbjournal.cc21
-rw-r--r--src/test/crimson/seastore/test_object_data_handler.cc54
-rw-r--r--src/test/crimson/seastore/test_seastore_cache.cc5
-rw-r--r--src/test/crimson/seastore/test_seastore_journal.cc13
-rw-r--r--src/test/crimson/seastore/test_transaction_manager.cc135
-rw-r--r--src/test/crimson/test_backfill.cc142
-rw-r--r--src/test/crimson/test_fixed_kv_node_layout.cc6
-rw-r--r--src/test/crimson/test_messenger_thrash.cc2
-rw-r--r--src/test/crimson/test_monc.cc1
-rw-r--r--src/test/crypto.cc2
-rw-r--r--src/test/daemon_config.cc2
-rw-r--r--src/test/encoding.cc2
-rw-r--r--src/test/fio/fio_ceph_objectstore.cc7
-rw-r--r--src/test/fio/fio_librgw.cc6
-rw-r--r--src/test/immutable_object_cache/test_DomainSocket.cc2
-rw-r--r--src/test/libcephfs/test.cc28
-rw-r--r--src/test/librados/aio.cc56
-rw-r--r--src/test/librados/aio_cxx.cc90
-rw-r--r--src/test/librados/asio.cc137
-rw-r--r--src/test/librados/misc.cc2
-rw-r--r--src/test/librados/misc_cxx.cc1
-rw-r--r--src/test/librados/test_common.cc1
-rw-r--r--src/test/librados_test_stub/TestMemIoCtxImpl.cc1
-rw-r--r--src/test/librados_test_stub/TestMemRadosClient.cc1
-rw-r--r--src/test/librbd/fsx.cc1
-rw-r--r--src/test/librbd/io/test_mock_ImageRequest.cc2
-rw-r--r--src/test/librbd/journal/test_Replay.cc2
-rw-r--r--src/test/librbd/migration/test_mock_HttpClient.cc4
-rw-r--r--src/test/librbd/mock/MockObjectMap.h2
-rw-r--r--src/test/librbd/object_map/test_mock_InvalidateRequest.cc2
-rw-r--r--src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc2
-rw-r--r--src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc2
-rw-r--r--src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc2
-rw-r--r--src/test/librbd/object_map/test_mock_UpdateRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_Request.cc2
-rw-r--r--src/test/librbd/operation/test_mock_ResizeRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc2
-rw-r--r--src/test/librbd/operation/test_mock_TrimRequest.cc2
-rw-r--r--src/test/librbd/test_DeepCopy.cc2
-rw-r--r--src/test/librbd/test_ImageWatcher.cc1
-rw-r--r--src/test/librbd/test_Migration.cc2
-rw-r--r--src/test/librbd/test_ObjectMap.cc2
-rw-r--r--src/test/librbd/test_fixture.cc1
-rw-r--r--src/test/librbd/test_internal.cc78
-rw-r--r--src/test/librbd/test_mock_ExclusiveLock.cc1
-rw-r--r--src/test/librbd/test_mock_Journal.cc2
-rw-r--r--src/test/librbd/test_mock_ObjectMap.cc2
-rw-r--r--src/test/mon/PGMap.cc1
-rw-r--r--src/test/neorados/read_operations.cc2
-rw-r--r--src/test/objectstore/Allocator_bench.cc1
-rw-r--r--src/test/objectstore/Allocator_test.cc1
-rw-r--r--src/test/objectstore/CMakeLists.txt12
-rw-r--r--src/test/objectstore/Fragmentation_simulator.cc2
-rw-r--r--src/test/objectstore/ObjectStoreImitator.cc2
-rw-r--r--src/test/objectstore/ObjectStoreImitator.h10
-rw-r--r--src/test/objectstore/allocsim/ops_replayer.cc35
-rw-r--r--src/test/objectstore/store_test.cc1
-rw-r--r--src/test/objectstore/test_bluefs.cc173
-rw-r--r--src/test/objectstore/test_deferred.cc6
-rw-r--r--src/test/objectstore/test_memstore_clone.cc1
-rw-r--r--src/test/objectstore_bench.cc1
-rw-r--r--src/test/osd/CMakeLists.txt2
-rw-r--r--src/test/osd/ceph_test_rados_io_sequence.cc1042
-rw-r--r--src/test/osd/ceph_test_rados_io_sequence.h581
-rw-r--r--src/test/osd/test_ec_transaction.cc1
-rw-r--r--src/test/osd/types.cc2
-rw-r--r--src/test/osdc/MemWriteback.cc5
-rw-r--r--src/test/osdc/object_cacher_stress.cc1
-rw-r--r--src/test/perf_counters.cc2
-rw-r--r--src/test/pybind/pytest.ini1
-rwxr-xr-xsrc/test/pybind/test_ceph_argparse.py10
-rw-r--r--src/test/pybind/test_rados.py2
-rw-r--r--src/test/rbd_mirror/test_ImageReplayer.cc2
-rw-r--r--src/test/rbd_mirror/test_ImageSync.cc2
-rw-r--r--src/test/rgw/bucket_notification/api.py4
-rw-r--r--src/test/rgw/bucket_notification/requirements.txt2
-rw-r--r--src/test/rgw/bucket_notification/test_bn.py308
-rw-r--r--src/test/rgw/rgw_multi/tests.py26
-rw-r--r--src/test/rgw/test-rgw-common.sh4
-rwxr-xr-xsrc/test/rgw/test-rgw-multisite.sh58
-rw-r--r--src/test/rgw/test_log_backing.cc1
-rw-r--r--src/test/rgw/test_rgw_iam_policy.cc8
-rw-r--r--src/test/signals.cc1
-rw-r--r--src/test/test_addrs.cc1
-rw-r--r--src/test/test_denc.cc6
-rw-r--r--src/test/test_features.cc2
-rw-r--r--src/test/test_ipaddr.cc155
-rw-r--r--src/test/test_mempool.cc2
-rw-r--r--src/test/test_perf_counters_cache.cc1
-rw-r--r--src/test/test_rewrite_latency.cc1
-rw-r--r--src/test/test_snap_mapper.cc1
-rw-r--r--src/test/test_striper.cc2
-rw-r--r--src/test/test_utime.cc3
-rw-r--r--src/test/test_workqueue.cc3
-rw-r--r--src/test/testcrypto.cc4
-rw-r--r--src/test/testkeys.cc3
132 files changed, 2677 insertions, 914 deletions
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 0ea0bb29347..82816fb07c8 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -591,6 +591,7 @@ if(NOT WIN32)
ceph_snappy
cls_lock
ceph_test_objectstore
+ ceph_test_bluefs
ceph_erasure_code_non_regression
cython_modules
crushtool
diff --git a/src/test/ObjectMap/KeyValueDBMemory.cc b/src/test/ObjectMap/KeyValueDBMemory.cc
index 234e963397e..cfe25930d6a 100644
--- a/src/test/ObjectMap/KeyValueDBMemory.cc
+++ b/src/test/ObjectMap/KeyValueDBMemory.cc
@@ -132,12 +132,26 @@ public:
return "";
}
+ string_view key_as_sv() override {
+ if (valid())
+ return (*it).first.second;
+ else
+ return "";
+ }
+
pair<string,string> raw_key() override {
if (valid())
return (*it).first;
else
return make_pair("", "");
}
+
+ pair<string_view,string_view> raw_key_as_sv() override {
+ if (valid())
+ return (*it).first;
+ else
+ return make_pair("", "");
+ }
bool raw_key_is_prefixed(const string &prefix) override {
return prefix == (*it).first.first;
@@ -150,6 +164,13 @@ public:
return bufferlist();
}
+ std::string_view value_as_sv() override {
+ if (valid())
+ return std::string_view{it->second.c_str(), it->second.length()};
+ else
+ return std::string_view();
+ }
+
int status() override {
return 0;
}
diff --git a/src/test/admin_socket.cc b/src/test/admin_socket.cc
index 69a3cbefd0e..dea29f96f11 100644
--- a/src/test/admin_socket.cc
+++ b/src/test/admin_socket.cc
@@ -27,6 +27,8 @@
#include <sys/un.h>
#include <signal.h>
+#include <iostream> // for std::cout
+
using namespace std;
class AdminSocketTest
diff --git a/src/test/admin_socket_output.h b/src/test/admin_socket_output.h
index 1df12e4a9a5..5d22e8757ee 100644
--- a/src/test/admin_socket_output.h
+++ b/src/test/admin_socket_output.h
@@ -16,6 +16,7 @@
#define CEPH_ADMIN_SOCKET_OUTPUT_H
#include <filesystem>
+#include <iostream> // for std::cout
#include <string>
#include <map>
#include <set>
diff --git a/src/test/bench_log.cc b/src/test/bench_log.cc
index 60fda462e87..2408c5dffb6 100644
--- a/src/test/bench_log.cc
+++ b/src/test/bench_log.cc
@@ -1,6 +1,8 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include <iostream> // for std::cout
+
#include "include/types.h"
#include "common/Thread.h"
#include "common/debug.h"
@@ -8,6 +10,7 @@
#include "common/config.h"
#include "common/ceph_argparse.h"
#include "global/global_init.h"
+#include "log/Log.h"
#define dout_context g_ceph_context
diff --git a/src/test/bufferlist.cc b/src/test/bufferlist.cc
index 013335d8177..4b3ca95ca6c 100644
--- a/src/test/bufferlist.cc
+++ b/src/test/bufferlist.cc
@@ -23,6 +23,8 @@
#include <errno.h>
#include <sys/uio.h>
+#include <iostream> // for std::cout
+
#include "include/buffer.h"
#include "include/buffer_raw.h"
#include "include/compat.h"
diff --git a/src/test/ceph_argparse.cc b/src/test/ceph_argparse.cc
index 738879c5ba8..436ddc86363 100644
--- a/src/test/ceph_argparse.cc
+++ b/src/test/ceph_argparse.cc
@@ -15,6 +15,7 @@
#include "common/ceph_argparse.h"
#include "gtest/gtest.h"
+#include <iostream> // for std::cout
#include <vector>
#include "include/stringify.h"
diff --git a/src/test/cli/radosgw-admin/help.t b/src/test/cli/radosgw-admin/help.t
index 0b937a3f988..c1675d11a80 100644
--- a/src/test/cli/radosgw-admin/help.t
+++ b/src/test/cli/radosgw-admin/help.t
@@ -43,6 +43,8 @@
bucket sync disable disable bucket sync
bucket sync enable enable bucket sync
bucket radoslist list rados objects backing bucket's objects
+ bucket logging flush flush pending log records object of source bucket to the log bucket
+ bucket logging info get info on bucket logging configuration on source bucket or list of sources in log bucket
bi get retrieve bucket index object entries
bi put store bucket index object entries
bi list list raw bucket index entries
@@ -225,6 +227,7 @@
--secret/--secret-key=<key> specify secret key
--gen-access-key generate random access key (for S3)
--gen-secret generate random secret key
+ --generate-key create user with or without credentials
--key-type=<type> key type, options are: swift, s3
--key-active=<bool> activate or deactivate a key
--temp-url-key[-2]=<key> temp url key
diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t
index 984175a97b9..5f304258358 100644
--- a/src/test/cli/rbd/help.t
+++ b/src/test/cli/rbd/help.t
@@ -916,7 +916,7 @@
[--group-namespace <group-namespace>]
[--group <group>] [--image-pool <image-pool>]
[--image-namespace <image-namespace>]
- [--image <image>] [--pool <pool>]
+ [--image <image>]
<group-spec> <image-spec>
Add an image to a group.
@@ -934,7 +934,6 @@
--image-pool arg image pool name
--image-namespace arg image namespace name
--image arg image name
- -p [ --pool ] arg pool name unless overridden
rbd help group image list
usage: rbd group image list [--format <format>] [--pretty-format]
@@ -960,8 +959,7 @@
[--group-namespace <group-namespace>]
[--group <group>] [--image-pool <image-pool>]
[--image-namespace <image-namespace>]
- [--image <image>] [--pool <pool>]
- [--image-id <image-id>]
+ [--image <image>] [--image-id <image-id>]
<group-spec> <image-spec>
Remove an image from a group.
@@ -979,7 +977,6 @@
--image-pool arg image pool name
--image-namespace arg image namespace name
--image arg image name
- -p [ --pool ] arg pool name unless overridden
--image-id arg image id
rbd help group info
diff --git a/src/test/client/TestClient.h b/src/test/client/TestClient.h
index bf3b274af60..d4f3364ad5e 100644
--- a/src/test/client/TestClient.h
+++ b/src/test/client/TestClient.h
@@ -20,6 +20,7 @@
#include "msg/Messenger.h"
#include "mon/MonClient.h"
#include "osdc/ObjectCacher.h"
+#include "osdc/Objecter.h"
#include "client/MetaRequest.h"
#include "client/Client.h"
#include "messages/MClientReclaim.h"
diff --git a/src/test/cls_log/test_cls_log.cc b/src/test/cls_log/test_cls_log.cc
index f8c1a32494a..91e38844dec 100644
--- a/src/test/cls_log/test_cls_log.cc
+++ b/src/test/cls_log/test_cls_log.cc
@@ -332,7 +332,6 @@ TEST_F(cls_log, trim_by_marker)
utime_t start_time = ceph_clock_now();
generate_log(ioctx, oid, 10, start_time, true);
- utime_t zero_time;
std::vector<cls_log_entry> log1;
{
list<cls_log_entry> entries;
diff --git a/src/test/cls_rbd/test_cls_rbd.cc b/src/test/cls_rbd/test_cls_rbd.cc
index 7eb03cc42f5..4f39a8e1eab 100644
--- a/src/test/cls_rbd/test_cls_rbd.cc
+++ b/src/test/cls_rbd/test_cls_rbd.cc
@@ -2156,7 +2156,7 @@ TEST_F(TestClsRbd, mirror_image_map)
{
librados::IoCtx ioctx;
ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
- ioctx.remove(RBD_MIRRORING);
+ ioctx.remove(RBD_MIRROR_LEADER);
std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
ASSERT_EQ(-ENOENT, mirror_image_map_list(&ioctx, "", 0, &image_mapping));
@@ -2177,7 +2177,7 @@ TEST_F(TestClsRbd, mirror_image_map)
mirror_image_map_update(&op, global_image_id, mirror_image_map);
}
- ASSERT_EQ(0, ioctx.operate(RBD_MIRRORING, &op));
+ ASSERT_EQ(0, ioctx.operate(RBD_MIRROR_LEADER, &op));
}
ASSERT_EQ(0, mirror_image_map_list(&ioctx, "", 1000, &image_mapping));
@@ -2203,7 +2203,7 @@ TEST_F(TestClsRbd, mirror_image_map)
librados::ObjectWriteOperation op;
mirror_image_map_remove(&op, "1");
mirror_image_map_update(&op, "10", expected_mirror_image_map);
- ASSERT_EQ(0, ioctx.operate(RBD_MIRRORING, &op));
+ ASSERT_EQ(0, ioctx.operate(RBD_MIRROR_LEADER, &op));
ASSERT_EQ(0, mirror_image_map_list(&ioctx, "0", 1, &image_mapping));
ASSERT_EQ(1U, image_mapping.size());
diff --git a/src/test/cls_rgw/test_cls_rgw_stats.cc b/src/test/cls_rgw/test_cls_rgw_stats.cc
index 80fa88fabf5..90bf4bd25b6 100644
--- a/src/test/cls_rgw/test_cls_rgw_stats.cc
+++ b/src/test/cls_rgw/test_cls_rgw_stats.cc
@@ -10,6 +10,7 @@
#include "common/dout.h"
#include "common/errno.h"
#include "common/random_string.h"
+#include "include/random.h" // for ceph::util::generate_random_number()
#include "global/global_context.h"
#include "test/librados/test_cxx.h"
diff --git a/src/test/common/CMakeLists.txt b/src/test/common/CMakeLists.txt
index 33ff38b932d..3c9cf0003aa 100644
--- a/src/test/common/CMakeLists.txt
+++ b/src/test/common/CMakeLists.txt
@@ -229,6 +229,12 @@ add_executable(unittest_xmlformatter
add_ceph_unittest(unittest_xmlformatter)
target_link_libraries(unittest_xmlformatter ceph-common)
+add_executable(unittest_htmlformatter
+ test_htmlformatter.cc
+ )
+add_ceph_unittest(unittest_htmlformatter)
+target_link_libraries(unittest_htmlformatter ceph-common)
+
# unittest_bit_vector
add_executable(unittest_bit_vector
test_bit_vector.cc
diff --git a/src/test/common/Throttle.cc b/src/test/common/Throttle.cc
index b36d0a901de..6ca05f6dae3 100644
--- a/src/test/common/Throttle.cc
+++ b/src/test/common/Throttle.cc
@@ -23,6 +23,7 @@
#include <signal.h>
#include <chrono>
+#include <iostream> // for std::cout
#include <list>
#include <mutex>
#include <random>
diff --git a/src/test/common/test_async_shared_mutex.cc b/src/test/common/test_async_shared_mutex.cc
index ed3a55a70ed..ebd9b937ac8 100644
--- a/src/test/common/test_async_shared_mutex.cc
+++ b/src/test/common/test_async_shared_mutex.cc
@@ -15,6 +15,7 @@
#include "common/async/shared_mutex.h"
#include <future>
#include <optional>
+#include <shared_mutex> // for std::shared_lock
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/io_context.hpp>
#include <gtest/gtest.h>
diff --git a/src/test/common/test_cdc.cc b/src/test/common/test_cdc.cc
index 620ecf4679f..61a5aa3708c 100644
--- a/src/test/common/test_cdc.cc
+++ b/src/test/common/test_cdc.cc
@@ -3,6 +3,7 @@
#include <vector>
#include <cstring>
+#include <iostream> // for std::cout
#include <random>
#include "include/types.h"
diff --git a/src/test/common/test_config.cc b/src/test/common/test_config.cc
index a70d567a434..4805c14a32e 100644
--- a/src/test/common/test_config.cc
+++ b/src/test/common/test_config.cc
@@ -19,6 +19,9 @@
*
*
*/
+
+#include <iostream> // for std::cout
+
#include "common/config_proxy.h"
#include "common/errno.h"
#include "gtest/gtest.h"
diff --git a/src/test/common/test_context.cc b/src/test/common/test_context.cc
index 889d000da85..8afded98951 100644
--- a/src/test/common/test_context.cc
+++ b/src/test/common/test_context.cc
@@ -19,6 +19,9 @@
*
*
*/
+
+#include <iostream> // for std::cout
+
#include "gtest/gtest.h"
#include "include/types.h"
#include "include/msgr.h"
diff --git a/src/test/common/test_htmlformatter.cc b/src/test/common/test_htmlformatter.cc
new file mode 100644
index 00000000000..0a8d827b53a
--- /dev/null
+++ b/src/test/common/test_htmlformatter.cc
@@ -0,0 +1,26 @@
+#include "gtest/gtest.h"
+
+#include "common/HTMLFormatter.h"
+#include <sstream>
+#include <string>
+
+using namespace ceph;
+
+TEST(htmlformatter, dump_format_large_item)
+{
+ std::stringstream sout;
+ HTMLFormatter formatter(false);
+
+ std::string base_url("http://example.com");
+ std::string bucket_name("bucket");
+ std::string object_key(1024, 'a');
+
+ formatter.dump_format("Location", "%s/%s/%s", base_url.c_str(), bucket_name.c_str(), object_key.c_str());
+
+ formatter.flush(sout);
+
+ std::string uri = base_url + "/" + bucket_name + "/" + object_key;
+ std::string expected_output = "<li>Location: " + uri + "</li>";
+
+ EXPECT_EQ(expected_output, sout.str());
+} \ No newline at end of file
diff --git a/src/test/common/test_intrusive_lru.cc b/src/test/common/test_intrusive_lru.cc
index af8edb8e2bf..1410b73fcaa 100644
--- a/src/test/common/test_intrusive_lru.cc
+++ b/src/test/common/test_intrusive_lru.cc
@@ -177,9 +177,9 @@ TEST(LRU, clear_range) {
auto [live_ref2, existed2] = cache.add(5, 4);
ASSERT_FALSE(existed2);
- cache.clear_range(0,4);
+ cache.clear_range(0, 4, [](auto&){});
- // Should not exists (Unreferenced):
+ // Should not exist
{
auto [ref, existed] = cache.add(1, 4);
ASSERT_FALSE(existed);
@@ -192,21 +192,27 @@ TEST(LRU, clear_range) {
auto [ref, existed] = cache.add(3, 4);
ASSERT_FALSE(existed);
}
- // Should exist (Still being referenced):
{
auto [ref, existed] = cache.add(4, 4);
- ASSERT_TRUE(existed);
+ ASSERT_FALSE(existed);
}
- // Should exists (Still being referenced and wasn't removed)
+ ASSERT_TRUE(live_ref1->is_invalidated());
+ // Should exist, wasn't removed)
{
auto [ref, existed] = cache.add(5, 4);
ASSERT_TRUE(existed);
}
- // Test out of bound deletion:
+ ASSERT_FALSE(live_ref2->is_invalidated());
+ // Test clear_range with right bound past last entry
+ cache.clear_range(3, 8, [](auto&){});
+ ASSERT_TRUE(live_ref2->is_invalidated());
{
- cache.clear_range(3,8);
auto [ref, existed] = cache.add(4, 4);
- ASSERT_TRUE(existed);
+ ASSERT_FALSE(existed);
+ }
+ {
+ auto [ref, existed] = cache.add(5, 4);
+ ASSERT_FALSE(existed);
}
{
auto [ref, existed] = cache.add(3, 4);
diff --git a/src/test/common/test_json_formatter.cc b/src/test/common/test_json_formatter.cc
index 9cc19b24ad1..d0ddd262c0a 100644
--- a/src/test/common/test_json_formatter.cc
+++ b/src/test/common/test_json_formatter.cc
@@ -102,3 +102,27 @@ TEST(formatter, dump_inf_or_nan)
EXPECT_EQ(parser.find_obj("nan_val")->get_data(), "null");
EXPECT_EQ(parser.find_obj("nan_val_alt")->get_data(), "null");
}
+
+TEST(formatter, dump_large_item) {
+ JSONFormatter formatter;
+ formatter.open_object_section("large_item");
+
+ std::string base_url("http://example.com");
+ std::string bucket_name("bucket");
+ std::string object_key(1024, 'a');
+
+ std::string full_url = base_url + "/" + bucket_name + "/" + object_key;
+ formatter.dump_format("Location", "%s/%s/%s", base_url.c_str(), bucket_name.c_str(), object_key.c_str());
+
+ formatter.close_section();
+ bufferlist bl;
+ formatter.flush(bl);
+
+ // std::cout << std::string(bl.c_str(), bl.length()) << std::endl;
+
+ JSONParser parser;
+ parser.parse(bl.c_str(), bl.length());
+
+ EXPECT_TRUE(parser.parse(bl.c_str(), bl.length()));
+ EXPECT_EQ(parser.find_obj("Location")->get_data(), full_url);
+}
diff --git a/src/test/common/test_shared_cache.cc b/src/test/common/test_shared_cache.cc
index 91120c7e59f..b7a392426d5 100644
--- a/src/test/common/test_shared_cache.cc
+++ b/src/test/common/test_shared_cache.cc
@@ -22,6 +22,9 @@
#include <stdio.h>
#include <signal.h>
+
+#include <iostream> // for std::cout
+
#include "gtest/gtest.h"
#include "common/Thread.h"
#include "common/shared_cache.hpp"
diff --git a/src/test/common/test_tableformatter.cc b/src/test/common/test_tableformatter.cc
index b152014a2b5..90de133d315 100644
--- a/src/test/common/test_tableformatter.cc
+++ b/src/test/common/test_tableformatter.cc
@@ -250,6 +250,23 @@ TEST(tableformatter, multiline_keyval)
EXPECT_EQ(cmp, sout.str());
}
+TEST(tableformatter, dump_large_item) {
+ std::stringstream sout;
+ TableFormatter* formatter = (TableFormatter*) Formatter::create("table-kv");
+
+ std::string base_url("http://example.com");
+ std::string bucket_name("bucket");
+ std::string object_key(1024, 'a');
+
+ std::string full_url = base_url + "/" + bucket_name + "/" + object_key;
+ formatter->dump_format("Location", "%s/%s/%s", base_url.c_str(), bucket_name.c_str(), object_key.c_str());
+ formatter->flush(sout);
+ delete formatter;
+
+ std::string cmp = "key::Location=\"" + full_url + "\" \n";
+ EXPECT_EQ(cmp, sout.str());
+}
+
/*
* Local Variables:
* compile-command: "cd ../.. ; make -j4 &&
diff --git a/src/test/common/test_time.cc b/src/test/common/test_time.cc
index bc19ba573d1..80af6fad805 100644
--- a/src/test/common/test_time.cc
+++ b/src/test/common/test_time.cc
@@ -28,6 +28,8 @@ using ceph::real_time;
using ceph::real_clock;
using ceph::real_time;
+using ceph::mono_clock;
+
using ceph::coarse_real_clock;
using ceph::coarse_mono_clock;
diff --git a/src/test/common/test_url_escape.cc b/src/test/common/test_url_escape.cc
index 6c27b64da7a..52de8db8d9c 100644
--- a/src/test/common/test_url_escape.cc
+++ b/src/test/common/test_url_escape.cc
@@ -3,6 +3,8 @@
#include "common/url_escape.h"
+#include <iostream> // for std::cout
+
#include "gtest/gtest.h"
TEST(url_escape, escape) {
diff --git a/src/test/common/test_xmlformatter.cc b/src/test/common/test_xmlformatter.cc
index 9ac6dde456e..abbe9e4e25e 100644
--- a/src/test/common/test_xmlformatter.cc
+++ b/src/test/common/test_xmlformatter.cc
@@ -163,3 +163,25 @@ TEST(xmlformatter, pretty_lowercased_underscored)
"<string_item>String</string_item>\n\n";
EXPECT_EQ(cmp, sout.str());
}
+
+TEST(xmlformatter, dump_format_large_item)
+{
+ std::stringstream sout;
+ XMLFormatter formatter(
+ true, // pretty
+ false, // lowercased
+ false); // underscored
+
+ std::string base_url("http://example.com");
+ std::string bucket_name("bucket");
+ std::string object_key(1024, 'a');
+
+ formatter.dump_format("Location", "%s/%s/%s", base_url.c_str(), bucket_name.c_str(), object_key.c_str());
+
+ formatter.flush(sout);
+
+ std::string uri = base_url + "/" + bucket_name + "/" + object_key;
+ std::string expected_output = "<Location>" + uri + "</Location>\n\n";
+
+ EXPECT_EQ(expected_output, sout.str());
+} \ No newline at end of file
diff --git a/src/test/compressor/test_compression.cc b/src/test/compressor/test_compression.cc
index 98ef159dfb8..c5e4724cefc 100644
--- a/src/test/compressor/test_compression.cc
+++ b/src/test/compressor/test_compression.cc
@@ -17,6 +17,9 @@
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
+
+#include <iostream> // for std::cout
+
#include "gtest/gtest.h"
#include "common/ceph_context.h"
#include "common/config.h"
diff --git a/src/test/crimson/seastore/test_block.h b/src/test/crimson/seastore/test_block.h
index fde6ad99c41..546f357dea0 100644
--- a/src/test/crimson/seastore/test_block.h
+++ b/src/test/crimson/seastore/test_block.h
@@ -39,8 +39,8 @@ struct test_block_delta_t {
inline std::ostream &operator<<(
std::ostream &lhs, const test_extent_desc_t &rhs) {
- return lhs << "test_extent_desc_t(len=" << rhs.len
- << ", checksum=" << rhs.checksum << ")";
+ return lhs << "test_extent_desc_t(len=0x" << std::hex << rhs.len
+ << ", checksum=0x" << rhs.checksum << std::dec << ")";
}
struct TestBlock : crimson::os::seastore::LogicalCachedExtent {
@@ -51,12 +51,12 @@ struct TestBlock : crimson::os::seastore::LogicalCachedExtent {
interval_set<extent_len_t> modified_region;
- TestBlock(ceph::bufferptr &&ptr)
+ explicit TestBlock(ceph::bufferptr &&ptr)
: LogicalCachedExtent(std::move(ptr)) {}
+ explicit TestBlock(extent_len_t length)
+ : LogicalCachedExtent(length) {}
TestBlock(const TestBlock &other)
: LogicalCachedExtent(other), modified_region(other.modified_region) {}
- TestBlock(extent_len_t length)
- : LogicalCachedExtent(length) {}
CachedExtentRef duplicate_for_write(Transaction&) final {
return CachedExtentRef(new TestBlock(*this));
@@ -113,8 +113,10 @@ struct TestBlockPhysical : crimson::os::seastore::CachedExtent{
void on_rewrite(Transaction&, CachedExtent&, extent_len_t) final {}
- TestBlockPhysical(ceph::bufferptr &&ptr)
+ explicit TestBlockPhysical(ceph::bufferptr &&ptr)
: CachedExtent(std::move(ptr)) {}
+ explicit TestBlockPhysical(extent_len_t length)
+ : CachedExtent(length) {}
TestBlockPhysical(const TestBlockPhysical &other)
: CachedExtent(other) {}
diff --git a/src/test/crimson/seastore/test_btree_lba_manager.cc b/src/test/crimson/seastore/test_btree_lba_manager.cc
index 9988df3a124..7874411e0ff 100644
--- a/src/test/crimson/seastore/test_btree_lba_manager.cc
+++ b/src/test/crimson/seastore/test_btree_lba_manager.cc
@@ -112,14 +112,22 @@ struct btree_test_base :
seastar::future<> submit_transaction(TransactionRef t)
{
auto record = cache->prepare_record(*t, JOURNAL_SEQ_NULL, JOURNAL_SEQ_NULL);
- return journal->submit_record(std::move(record), t->get_handle()).safe_then(
- [this, t=std::move(t)](auto submit_result) mutable {
- cache->complete_commit(
- *t,
+ return seastar::do_with(
+ std::move(t), [this, record=std::move(record)](auto& _t) mutable {
+ auto& t = *_t;
+ return journal->submit_record(
+ std::move(record),
+ t.get_handle(),
+ t.get_src(),
+ [this, &t](auto submit_result) {
+ cache->complete_commit(
+ t,
submit_result.record_block_base,
submit_result.write_result.start_seq);
- complete_commit(*t);
- }).handle_error(crimson::ct_error::assert_all{});
+ complete_commit(t);
+ }
+ ).handle_error(crimson::ct_error::assert_all{});
+ });
}
virtual LBAManager::mkfs_ret test_structure_setup(Transaction &t) = 0;
@@ -149,7 +157,10 @@ struct btree_test_base :
}).safe_then([this] {
return seastar::do_with(
cache->create_transaction(
- Transaction::src_t::MUTATE, "test_set_up_fut", false),
+ Transaction::src_t::MUTATE,
+ "test_set_up_fut",
+ CACHE_HINT_TOUCH,
+ false),
[this](auto &ref_t) {
return with_trans_intr(*ref_t, [&](auto &t) {
cache->init();
@@ -228,7 +239,10 @@ struct lba_btree_test : btree_test_base {
template <typename F>
auto lba_btree_update(F &&f) {
auto tref = cache->create_transaction(
- Transaction::src_t::MUTATE, "test_btree_update", false);
+ Transaction::src_t::MUTATE,
+ "test_btree_update",
+ CACHE_HINT_TOUCH,
+ false);
auto &t = *tref;
with_trans_intr(
t,
@@ -273,7 +287,10 @@ struct lba_btree_test : btree_test_base {
template <typename F>
auto lba_btree_read(F &&f) {
auto t = cache->create_transaction(
- Transaction::src_t::READ, "test_btree_read", false);
+ Transaction::src_t::READ,
+ "test_btree_read",
+ CACHE_HINT_TOUCH,
+ false);
return with_trans_intr(
*t,
[this, f=std::forward<F>(f)](auto &t) mutable {
@@ -421,7 +438,10 @@ struct btree_lba_manager_test : btree_test_base {
auto create_transaction(bool create_fake_extent=true) {
auto t = test_transaction_t{
cache->create_transaction(
- Transaction::src_t::MUTATE, "test_mutate_lba", false),
+ Transaction::src_t::MUTATE,
+ "test_mutate_lba",
+ CACHE_HINT_TOUCH,
+ false),
test_lba_mappings
};
if (create_fake_extent) {
@@ -437,7 +457,10 @@ struct btree_lba_manager_test : btree_test_base {
auto create_weak_transaction() {
auto t = test_transaction_t{
cache->create_transaction(
- Transaction::src_t::READ, "test_read_weak", true),
+ Transaction::src_t::READ,
+ "test_read_weak",
+ CACHE_HINT_TOUCH,
+ true),
test_lba_mappings
};
return t;
diff --git a/src/test/crimson/seastore/test_cbjournal.cc b/src/test/crimson/seastore/test_cbjournal.cc
index d00a0f42729..47a08d68cbb 100644
--- a/src/test/crimson/seastore/test_cbjournal.cc
+++ b/src/test/crimson/seastore/test_cbjournal.cc
@@ -181,15 +181,20 @@ struct cbjournal_test_t : public seastar_test_suite_t, JournalTrimmer
auto submit_record(record_t&& record) {
entries.push_back(record);
+ entry_validator_t& back = entries.back();
OrderingHandle handle = get_dummy_ordering_handle();
- auto [addr, w_result] = cbj->submit_record(
- std::move(record),
- handle).unsafe_get();
- entries.back().seq = w_result.start_seq;
- entries.back().entries = 1;
- entries.back().magic = cbj->get_cjs().get_cbj_header().magic;
- logger().debug("submit entry to addr {}", entries.back().seq);
- return convert_paddr_to_abs_addr(entries.back().seq.offset);
+ cbj->submit_record(
+ std::move(record),
+ handle,
+ transaction_type_t::MUTATE,
+ [this, &back](auto locator) {
+ back.seq = locator.write_result.start_seq;
+ back.entries = 1;
+ back.magic = cbj->get_cjs().get_cbj_header().magic;
+ logger().debug("submit entry to addr {}", back.seq);
+ }
+ ).unsafe_get();
+ return convert_paddr_to_abs_addr(back.seq.offset);
}
seastar::future<> tear_down_fut() final {
diff --git a/src/test/crimson/seastore/test_object_data_handler.cc b/src/test/crimson/seastore/test_object_data_handler.cc
index e7aabf2c8af..a6233ad2c63 100644
--- a/src/test/crimson/seastore/test_object_data_handler.cc
+++ b/src/test/crimson/seastore/test_object_data_handler.cc
@@ -218,14 +218,20 @@ struct object_data_handler_test_t:
objaddr_t offset,
extent_len_t length) {
auto ret = with_trans_intr(t, [&](auto &t) {
- return tm->get_pins(t, laddr_t::from_byte_offset(offset), length);
+ auto &layout = onode->get_layout();
+ auto odata = layout.object_data.get();
+ auto obase = odata.get_reserved_data_base();
+ return tm->get_pins(t, (obase + offset).checked_to_laddr(), length);
}).unsafe_get();
return ret;
}
std::list<LBAMappingRef> get_mappings(objaddr_t offset, extent_len_t length) {
auto t = create_mutate_transaction();
auto ret = with_trans_intr(*t, [&](auto &t) {
- return tm->get_pins(t, laddr_t::from_byte_offset(offset), length);
+ auto &layout = onode->get_layout();
+ auto odata = layout.object_data.get();
+ auto obase = odata.get_reserved_data_base();
+ return tm->get_pins(t, (obase + offset).checked_to_laddr(), length);
}).unsafe_get();
return ret;
}
@@ -253,12 +259,19 @@ struct object_data_handler_test_t:
ObjectDataBlockRef get_extent(
Transaction &t,
- laddr_t addr,
+ loffset_t addr,
extent_len_t len) {
- auto ext = with_trans_intr(t, [&](auto& trans) {
- return tm->read_extent<ObjectDataBlock>(trans, addr, len);
- }).unsafe_get();
- EXPECT_EQ(addr, ext->get_laddr());
+ auto &layout = onode->get_layout();
+ auto odata = layout.object_data.get();
+ auto obase = odata.get_reserved_data_base();
+ auto maybe_indirect_ext = with_trans_intr(t, [&](auto& trans) {
+ return tm->read_extent<ObjectDataBlock>(
+ trans, (obase + addr).checked_to_laddr(), len);
+ }).unsafe_get();
+ EXPECT_FALSE(maybe_indirect_ext.is_clone);
+ EXPECT_FALSE(maybe_indirect_ext.is_indirect());
+ auto ext = maybe_indirect_ext.extent;
+ EXPECT_EQ((obase + addr).checked_to_laddr(), ext->get_laddr());
return ext;
}
@@ -798,7 +811,7 @@ TEST_P(object_data_handler_test_t, overwrite_then_read_within_transaction) {
auto pins = get_mappings(*t, base, len);
assert(pins.size() == 1);
auto pin1 = remap_pin(*t, std::move(pins.front()), 4096, 8192);
- auto ext = get_extent(*t, laddr_t::from_byte_offset(base + 4096), 4096 * 2);
+ auto ext = get_extent(*t, base + 4096, 4096 * 2);
ASSERT_TRUE(ext->is_exist_clean());
write(*t, base + 4096, 4096, 'y');
ASSERT_TRUE(ext->is_exist_mutation_pending());
@@ -858,6 +871,31 @@ TEST_P(object_data_handler_test_t, overwrite_then_read_within_transaction) {
});
}
+TEST_P(object_data_handler_test_t, parallel_partial_read) {
+ run_async([this] {
+ disable_max_extent_size();
+ enable_delta_based_overwrite();
+ auto t = create_mutate_transaction();
+ auto base = 0;
+ auto len = 4096 * 10;
+ write(*t, base, len, 'a');
+ submit_transaction(std::move(t));
+
+ restart();
+ epm->check_usage();
+ seastar::parallel_for_each(
+ boost::make_counting_iterator(0lu),
+ boost::make_counting_iterator(8lu),
+ [&](auto i) {
+ return seastar::async([&] {
+ read(i * 4096, 8192);
+ });
+ }).get();
+ disable_delta_based_overwrite();
+ enable_max_extent_size();
+ });
+}
+
INSTANTIATE_TEST_SUITE_P(
object_data_handler_test,
object_data_handler_test_t,
diff --git a/src/test/crimson/seastore/test_seastore_cache.cc b/src/test/crimson/seastore/test_seastore_cache.cc
index 6e24f436b98..fa774886139 100644
--- a/src/test/crimson/seastore/test_seastore_cache.cc
+++ b/src/test/crimson/seastore/test_seastore_cache.cc
@@ -87,7 +87,10 @@ struct cache_test_t : public seastar_test_suite_t {
auto get_transaction() {
return cache->create_transaction(
- Transaction::src_t::MUTATE, "test_cache", false);
+ Transaction::src_t::MUTATE,
+ "test_cache",
+ CACHE_HINT_TOUCH,
+ false);
}
template <typename T, typename... Args>
diff --git a/src/test/crimson/seastore/test_seastore_journal.cc b/src/test/crimson/seastore/test_seastore_journal.cc
index 2eb791b1d46..04a99319b11 100644
--- a/src/test/crimson/seastore/test_seastore_journal.cc
+++ b/src/test/crimson/seastore/test_seastore_journal.cc
@@ -233,12 +233,17 @@ struct journal_test_t : seastar_test_suite_t, SegmentProvider, JournalTrimmer {
auto submit_record(T&&... _record) {
auto record{std::forward<T>(_record)...};
records.push_back(record);
+ record_validator_t& back = records.back();
OrderingHandle handle = get_dummy_ordering_handle();
- auto [addr, _] = journal->submit_record(
+ journal->submit_record(
std::move(record),
- handle).unsafe_get();
- records.back().record_final_offset = addr;
- return addr;
+ handle,
+ transaction_type_t::MUTATE,
+ [&back](auto locator) {
+ back.record_final_offset = locator.record_block_base;
+ }
+ ).unsafe_get();
+ return back.record_final_offset;
}
extent_t generate_extent(size_t blocks) {
diff --git a/src/test/crimson/seastore/test_transaction_manager.cc b/src/test/crimson/seastore/test_transaction_manager.cc
index 6ad111dca5b..6e0fe65c345 100644
--- a/src/test/crimson/seastore/test_transaction_manager.cc
+++ b/src/test/crimson/seastore/test_transaction_manager.cc
@@ -26,6 +26,10 @@ namespace {
}
}
+laddr_t get_laddr_hint(uint64_t offset) {
+ return laddr_t::from_byte_offset(RootMetaBlock::SIZE + offset);
+}
+
struct test_extent_record_t {
test_extent_desc_t desc;
unsigned refcount = 0;
@@ -67,8 +71,9 @@ struct transaction_manager_test_t :
}
laddr_t get_random_laddr(size_t block_size, size_t limit) {
- return laddr_t::from_byte_offset(block_size *
- std::uniform_int_distribution<>(0, (limit / block_size) - 1)(gen));
+ auto offset = block_size *
+ std::uniform_int_distribution<>(0, (limit / block_size) - 1)(gen);
+ return get_laddr_hint(offset);
}
char get_random_contents() {
@@ -501,9 +506,10 @@ struct transaction_manager_test_t :
ceph_assert(test_mappings.contains(addr, t.mapping_delta));
ceph_assert(test_mappings.get(addr, t.mapping_delta).desc.len == len);
- auto ext = with_trans_intr(*(t.t), [&](auto& trans) {
+ auto maybe_indirect_ext = with_trans_intr(*(t.t), [&](auto& trans) {
return tm->read_pin<TestBlock>(trans, std::move(pin));
}).unsafe_get();
+ auto ext = maybe_indirect_ext.extent;
EXPECT_EQ(addr, ext->get_laddr());
return ext;
}
@@ -515,9 +521,10 @@ struct transaction_manager_test_t :
ceph_assert(test_mappings.contains(addr, t.mapping_delta));
ceph_assert(test_mappings.get(addr, t.mapping_delta).desc.len == len);
- auto ext = with_trans_intr(*(t.t), [&](auto& trans) {
+ auto maybe_indirect_ext = with_trans_intr(*(t.t), [&](auto& trans) {
return tm->read_extent<TestBlock>(trans, addr, len);
}).unsafe_get();
+ auto ext = maybe_indirect_ext.extent;
EXPECT_EQ(addr, ext->get_laddr());
return ext;
}
@@ -528,11 +535,10 @@ struct transaction_manager_test_t :
ceph_assert(test_mappings.contains(addr, t.mapping_delta));
using ertr = with_trans_ertr<TransactionManager::read_extent_iertr>;
- using ret = ertr::future<TestBlockRef>;
auto ext = with_trans_intr(*(t.t), [&](auto& trans) {
return tm->read_extent<TestBlock>(trans, addr);
- }).safe_then([](auto ext) -> ret {
- return ertr::make_ready_future<TestBlockRef>(ext);
+ }).safe_then([](auto ret) {
+ return ertr::make_ready_future<TestBlockRef>(ret.extent);
}).handle_error(
[](const crimson::ct_error::eagain &e) {
return seastar::make_ready_future<TestBlockRef>();
@@ -555,11 +561,10 @@ struct transaction_manager_test_t :
ceph_assert(test_mappings.get(addr, t.mapping_delta).desc.len == len);
using ertr = with_trans_ertr<TransactionManager::read_extent_iertr>;
- using ret = ertr::future<TestBlockRef>;
auto ext = with_trans_intr(*(t.t), [&](auto& trans) {
return tm->read_extent<TestBlock>(trans, addr, len);
- }).safe_then([](auto ext) -> ret {
- return ertr::make_ready_future<TestBlockRef>(ext);
+ }).safe_then([](auto ret) {
+ return ertr::make_ready_future<TestBlockRef>(ret.extent);
}).handle_error(
[](const crimson::ct_error::eagain &e) {
return seastar::make_ready_future<TestBlockRef>();
@@ -578,14 +583,13 @@ struct transaction_manager_test_t :
test_transaction_t &t,
LBAMappingRef &&pin) {
using ertr = with_trans_ertr<TransactionManager::base_iertr>;
- using ret = ertr::future<TestBlockRef>;
bool indirect = pin->is_indirect();
auto addr = pin->get_key();
auto im_addr = indirect ? pin->get_intermediate_base() : L_ADDR_NULL;
auto ext = with_trans_intr(*(t.t), [&](auto& trans) {
return tm->read_pin<TestBlock>(trans, std::move(pin));
- }).safe_then([](auto ext) -> ret {
- return ertr::make_ready_future<TestBlockRef>(ext);
+ }).safe_then([](auto ret) {
+ return ertr::make_ready_future<TestBlockRef>(ret.extent);
}).handle_error(
[](const crimson::ct_error::eagain &e) {
return seastar::make_ready_future<TestBlockRef>();
@@ -719,7 +723,7 @@ struct transaction_manager_test_t :
[this, &overlay](auto &t) {
return lba_manager->scan_mappings(
t,
- L_ADDR_MIN,
+ get_laddr_hint(0),
L_ADDR_MAX,
[iter=overlay.begin(), &overlay](auto l, auto p, auto len) mutable {
EXPECT_NE(iter, overlay.end());
@@ -830,9 +834,9 @@ struct transaction_manager_test_t :
auto t = create_transaction();
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * BSIZE),
+ get_laddr_hint(i * BSIZE),
BSIZE);
- ASSERT_EQ(laddr_t::from_byte_offset(i * BSIZE), extent->get_laddr());
+ ASSERT_EQ(get_laddr_hint(i * BSIZE), extent->get_laddr());
submit_transaction(std::move(t));
}
@@ -844,7 +848,7 @@ struct transaction_manager_test_t :
boost::make_counting_iterator(0lu),
boost::make_counting_iterator(BLOCKS),
[this, &t](auto i) {
- return tm->read_extent<TestBlock>(t, laddr_t::from_byte_offset(i * BSIZE), BSIZE
+ return tm->read_extent<TestBlock>(t, get_laddr_hint(i * BSIZE), BSIZE
).si_then([](auto) {
return seastar::now();
});
@@ -870,9 +874,9 @@ struct transaction_manager_test_t :
auto t = create_transaction();
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * BSIZE),
+ get_laddr_hint(i * BSIZE),
BSIZE);
- ASSERT_EQ(laddr_t::from_byte_offset(i * BSIZE), extent->get_laddr());
+ ASSERT_EQ(get_laddr_hint(i * BSIZE), extent->get_laddr());
if (try_submit_transaction(std::move(t)))
break;
}
@@ -973,6 +977,7 @@ struct transaction_manager_test_t :
extent_types_t::ROOT,
extent_types_t::LADDR_INTERNAL,
extent_types_t::LADDR_LEAF,
+ extent_types_t::ROOT_META,
extent_types_t::OMAP_INNER,
extent_types_t::OMAP_LEAF,
extent_types_t::ONODE_BLOCK_STAGED,
@@ -1346,9 +1351,9 @@ struct transaction_manager_test_t :
void test_remap_pin() {
run_async([this] {
disable_max_extent_size();
- laddr_t l_offset = laddr_t::from_byte_offset(32 << 10);
+ laddr_t l_offset = get_laddr_hint(32 << 10);
size_t l_len = 32 << 10;
- laddr_t r_offset = laddr_t::from_byte_offset(64 << 10);
+ laddr_t r_offset = get_laddr_hint(64 << 10);
size_t r_len = 32 << 10;
{
auto t = create_transaction();
@@ -1400,12 +1405,12 @@ struct transaction_manager_test_t :
void test_clone_and_remap_pin() {
run_async([this] {
disable_max_extent_size();
- laddr_t l_offset = laddr_t::from_byte_offset(32 << 10);
+ laddr_t l_offset = get_laddr_hint(32 << 10);
size_t l_len = 32 << 10;
- laddr_t r_offset = laddr_t::from_byte_offset(64 << 10);
+ laddr_t r_offset = get_laddr_hint(64 << 10);
size_t r_len = 32 << 10;
- laddr_t l_clone_offset = laddr_t::from_byte_offset(96 << 10);
- laddr_t r_clone_offset = laddr_t::from_byte_offset(128 << 10);
+ laddr_t l_clone_offset = get_laddr_hint(96 << 10);
+ laddr_t r_clone_offset = get_laddr_hint(128 << 10);
{
auto t = create_transaction();
auto lext = alloc_extent(t, l_offset, l_len);
@@ -1455,11 +1460,11 @@ struct transaction_manager_test_t :
void test_overwrite_pin() {
run_async([this] {
disable_max_extent_size();
- laddr_t m_offset = laddr_t::from_byte_offset(8 << 10);
+ laddr_t m_offset = get_laddr_hint(8 << 10);
size_t m_len = 56 << 10;
- laddr_t l_offset = laddr_t::from_byte_offset(64 << 10);
+ laddr_t l_offset = get_laddr_hint(64 << 10);
size_t l_len = 64 << 10;
- laddr_t r_offset = laddr_t::from_byte_offset(128 << 10);
+ laddr_t r_offset = get_laddr_hint(128 << 10);
size_t r_len = 64 << 10;
{
auto t = create_transaction();
@@ -1538,7 +1543,7 @@ struct transaction_manager_test_t :
run_async([this] {
disable_max_extent_size();
constexpr unsigned REMAP_NUM = 32;
- constexpr laddr_t offset = L_ADDR_MIN;
+ laddr_t offset = get_laddr_hint(0);
constexpr size_t length = 256 << 10;
{
auto t = create_transaction();
@@ -1575,7 +1580,7 @@ struct transaction_manager_test_t :
if (off == 0 || off >= 255) {
continue;
}
- auto new_off = laddr_t::from_byte_offset(off << 10)
+ auto new_off = get_laddr_hint(off << 10)
.get_byte_distance<extent_len_t>(last_pin->get_key());
auto new_len = last_pin->get_length() - new_off;
//always remap right extent at new split_point
@@ -1621,7 +1626,7 @@ struct transaction_manager_test_t :
run_async([this] {
disable_max_extent_size();
constexpr unsigned REMAP_NUM = 32;
- constexpr laddr_t offset = L_ADDR_MIN;
+ laddr_t offset = get_laddr_hint(0);
constexpr size_t length = 256 << 10;
{
auto t = create_transaction();
@@ -1661,12 +1666,12 @@ struct transaction_manager_test_t :
ASSERT_TRUE(!split_points.empty());
while(!split_points.empty()) {
// new overwrite area: start_off ~ end_off
- auto start_off = split_points.front();
+ auto start_off = split_points.front() + 4 /*RootMetaBlock*/;
split_points.pop_front();
- auto end_off = split_points.front();
+ auto end_off = split_points.front() + 4 /*RootMetaBlock*/;
split_points.pop_front();
ASSERT_TRUE(start_off <= end_off);
- if ((laddr_t::from_byte_offset(end_off << 10) == pin0->get_key() + pin0->get_length())
+ if ((get_laddr_hint(end_off << 10) == pin0->get_key() + pin0->get_length())
|| (start_off == end_off)) {
if (split_points.empty() && empty_transaction) {
early_exit++;
@@ -1675,7 +1680,7 @@ struct transaction_manager_test_t :
continue;
}
empty_transaction = false;
- auto new_off = laddr_t::from_byte_offset(start_off << 10)
+ auto new_off = get_laddr_hint(start_off << 10)
.get_byte_distance<extent_len_t>(last_rpin->get_key());
auto new_len = (end_off - start_off) << 10;
bufferlist bl;
@@ -1768,7 +1773,7 @@ struct tm_random_block_device_test_t :
TEST_P(tm_random_block_device_test_t, scatter_allocation)
{
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * 4096);
+ laddr_t ADDR = get_laddr_hint(0xFF * 4096);
epm->prefill_fragmented_devices();
auto t = create_transaction();
for (int i = 0; i < 1991; i++) {
@@ -1786,7 +1791,7 @@ TEST_P(tm_single_device_test_t, basic)
{
constexpr size_t SIZE = 4096;
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * SIZE);
+ laddr_t ADDR = get_laddr_hint(0xFF * SIZE);
{
auto t = create_transaction();
auto extent = alloc_extent(
@@ -1807,7 +1812,7 @@ TEST_P(tm_single_device_test_t, mutate)
{
constexpr size_t SIZE = 4096;
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * SIZE);
+ laddr_t ADDR = get_laddr_hint(0xFF * SIZE);
{
auto t = create_transaction();
auto extent = alloc_extent(
@@ -1845,8 +1850,8 @@ TEST_P(tm_single_device_test_t, allocate_lba_conflict)
{
constexpr size_t SIZE = 4096;
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * SIZE);
- laddr_t ADDR2 = laddr_t::from_byte_offset(0xFE * SIZE);
+ laddr_t ADDR = get_laddr_hint(0xFF * SIZE);
+ laddr_t ADDR2 = get_laddr_hint(0xFE * SIZE);
auto t = create_transaction();
auto t2 = create_transaction();
@@ -1883,7 +1888,7 @@ TEST_P(tm_single_device_test_t, mutate_lba_conflict)
for (unsigned i = 0; i < 300; ++i) {
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * SIZE),
+ get_laddr_hint(i * SIZE),
SIZE);
}
check_mappings(t);
@@ -1891,7 +1896,7 @@ TEST_P(tm_single_device_test_t, mutate_lba_conflict)
check();
}
- laddr_t ADDR = laddr_t::from_byte_offset(150 * SIZE);
+ laddr_t ADDR = get_laddr_hint(150 * SIZE);
{
auto t = create_transaction();
auto t2 = create_transaction();
@@ -1917,15 +1922,15 @@ TEST_P(tm_single_device_test_t, concurrent_mutate_lba_no_conflict)
{
constexpr size_t SIZE = 4096;
constexpr size_t NUM = 500;
- laddr_t addr = L_ADDR_MIN;
- laddr_t addr2 = laddr_t::from_byte_offset(SIZE * (NUM - 1));
+ laddr_t addr = get_laddr_hint(0);
+ laddr_t addr2 = get_laddr_hint(SIZE * (NUM - 1));
run_async([this, addr, addr2] {
{
auto t = create_transaction();
for (unsigned i = 0; i < NUM; ++i) {
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * SIZE),
+ get_laddr_hint(i * SIZE),
SIZE);
}
submit_transaction(std::move(t));
@@ -1949,7 +1954,7 @@ TEST_P(tm_single_device_test_t, create_remove_same_transaction)
{
constexpr size_t SIZE = 4096;
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * SIZE);
+ laddr_t ADDR = get_laddr_hint(0xFF * SIZE);
{
auto t = create_transaction();
auto extent = alloc_extent(
@@ -1985,7 +1990,7 @@ TEST_P(tm_single_device_test_t, split_merge_read_same_transaction)
for (unsigned i = 0; i < 300; ++i) {
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * SIZE),
+ get_laddr_hint(i * SIZE),
SIZE);
}
check_mappings(t);
@@ -1997,7 +2002,7 @@ TEST_P(tm_single_device_test_t, split_merge_read_same_transaction)
for (unsigned i = 0; i < 240; ++i) {
dec_ref(
t,
- laddr_t::from_byte_offset(i * SIZE));
+ get_laddr_hint(i * SIZE));
}
check_mappings(t);
submit_transaction(std::move(t));
@@ -2010,7 +2015,7 @@ TEST_P(tm_single_device_test_t, inc_dec_ref)
{
constexpr size_t SIZE = 4096;
run_async([this] {
- laddr_t ADDR = laddr_t::from_byte_offset(0xFF * SIZE);
+ laddr_t ADDR = get_laddr_hint(0xFF * SIZE);
{
auto t = create_transaction();
auto extent = alloc_extent(
@@ -2061,10 +2066,10 @@ TEST_P(tm_single_device_test_t, cause_lba_split)
auto t = create_transaction();
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * SIZE),
+ get_laddr_hint(i * SIZE),
SIZE,
(char)(i & 0xFF));
- ASSERT_EQ(laddr_t::from_byte_offset(i * SIZE), extent->get_laddr());
+ ASSERT_EQ(get_laddr_hint(i * SIZE), extent->get_laddr());
submit_transaction(std::move(t));
}
check();
@@ -2082,9 +2087,9 @@ TEST_P(tm_single_device_test_t, random_writes)
auto t = create_transaction();
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * BSIZE),
+ get_laddr_hint(i * BSIZE),
BSIZE);
- ASSERT_EQ(laddr_t::from_byte_offset(i * BSIZE), extent->get_laddr());
+ ASSERT_EQ(get_laddr_hint(i * BSIZE), extent->get_laddr());
submit_transaction(std::move(t));
}
@@ -2100,7 +2105,7 @@ TEST_P(tm_single_device_test_t, random_writes)
// pad out transaction
auto paddings = alloc_extents(
t,
- laddr_t::from_byte_offset(TOTAL + (k * PADDING_SIZE)),
+ get_laddr_hint(TOTAL + (k * PADDING_SIZE)),
PADDING_SIZE);
for (auto &padding : paddings) {
dec_ref(t, padding->get_laddr());
@@ -2133,7 +2138,7 @@ TEST_P(tm_single_device_test_t, find_hole_assert_trigger)
TEST_P(tm_single_device_intergrity_check_test_t, remap_lazy_read)
{
- constexpr laddr_t offset = L_ADDR_MIN;
+ laddr_t offset = get_laddr_hint(0);
constexpr size_t length = 256 << 10;
run_async([this, offset] {
disable_max_extent_size();
@@ -2183,10 +2188,10 @@ TEST_P(tm_single_device_test_t, invalid_lba_mapping_detect)
using namespace crimson::os::seastore::lba_manager::btree;
{
auto t = create_transaction();
- for (int i = 0; i < LEAF_NODE_CAPACITY; i++) {
+ for (unsigned i = 0; i < LEAF_NODE_CAPACITY; i++) {
auto extent = alloc_extent(
t,
- laddr_t::from_byte_offset(i * 4096),
+ get_laddr_hint(i * 4096),
4096,
'a');
}
@@ -2195,18 +2200,20 @@ TEST_P(tm_single_device_test_t, invalid_lba_mapping_detect)
{
auto t = create_transaction();
- auto pin = get_pin(t, laddr_t::from_byte_offset((LEAF_NODE_CAPACITY - 1) * 4096));
+ auto pin = get_pin(t, get_laddr_hint((LEAF_NODE_CAPACITY - 1) * 4096));
assert(pin->is_parent_viewable());
- auto extent = alloc_extent(t, laddr_t::from_byte_offset(LEAF_NODE_CAPACITY * 4096), 4096, 'a');
+ auto extent = alloc_extent(t, get_laddr_hint(LEAF_NODE_CAPACITY * 4096), 4096, 'a');
assert(!pin->is_parent_viewable());
- pin = get_pin(t, laddr_t::from_byte_offset(LEAF_NODE_CAPACITY * 4096));
- std::ignore = alloc_extent(t, laddr_t::from_byte_offset((LEAF_NODE_CAPACITY + 1) * 4096), 4096, 'a');
+ pin = get_pin(t, get_laddr_hint(LEAF_NODE_CAPACITY * 4096));
+ std::ignore = alloc_extent(t, get_laddr_hint((LEAF_NODE_CAPACITY + 1) * 4096), 4096, 'a');
assert(pin->is_parent_viewable());
assert(pin->parent_modified());
pin->maybe_fix_pos();
- auto v = pin->get_logical_extent(*t.t);
- assert(v.has_child());
- auto extent2 = v.get_child_fut().unsafe_get();
+ auto extent2 = with_trans_intr(*(t.t), [&pin](auto& trans) {
+ auto v = pin->get_logical_extent(trans);
+ assert(v.has_child());
+ return std::move(v.get_child_fut());
+ }).unsafe_get();
assert(extent.get() == extent2.get());
submit_transaction(std::move(t));
}
diff --git a/src/test/crimson/test_backfill.cc b/src/test/crimson/test_backfill.cc
index 7e058c80ed6..e0fc5821d08 100644
--- a/src/test/crimson/test_backfill.cc
+++ b/src/test/crimson/test_backfill.cc
@@ -119,6 +119,11 @@ class BackfillFixture : public crimson::osd::BackfillState::BackfillListener {
events_to_dispatch.emplace_back(event.intrusive_from_this());
}
+ template <class EventT>
+ void schedule_event_immediate(const EventT& event) {
+ events_to_dispatch.emplace_front(event.intrusive_from_this());
+ }
+
// BackfillListener {
void request_replica_scan(
const pg_shard_t& target,
@@ -188,12 +193,11 @@ public:
struct PGFacade;
void cancel() {
- events_to_dispatch.clear();
- schedule_event(crimson::osd::BackfillState::CancelBackfill{});
+ schedule_event_immediate(crimson::osd::BackfillState::CancelBackfill{});
}
void resume() {
- schedule_event(crimson::osd::BackfillState::Triggered{});
+ schedule_event_immediate(crimson::osd::BackfillState::Triggered{});
}
};
@@ -274,6 +278,9 @@ struct BackfillFixture::PGFacade : public crimson::osd::BackfillState::PGFacade
return backfill_source.projected_log;
}
+ std::ostream &print(std::ostream &out) const override {
+ return out << "FakePGFacade";
+ }
};
BackfillFixture::BackfillFixture(
@@ -452,7 +459,69 @@ TEST(backfill, two_empty_replicas)
EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
}
-TEST(backfill, cancel_resume)
+TEST(backfill, cancel_resume_middle_of_primaryscan)
+{
+ const auto reference_store = FakeStore{ {
+ { "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
+ { "1:00ed7f8e:::rbd_data.1018ac3e755.00000000000000af:head", {10, 196} },
+ { "1:01483aea:::rbd_data.1018ac3e755.0000000000000095:head", {10, 169} },
+ }};
+ auto cluster_fixture = BackfillFixtureBuilder::add_source(
+ reference_store.objs
+ ).add_target(
+ { /* nothing 1 */ }
+ ).add_target(
+ { /* nothing 2 */ }
+ ).get_result();
+
+ EXPECT_CALL(cluster_fixture, backfilled);
+ cluster_fixture.cancel();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
+ cluster_fixture.resume();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_till_done();
+
+ EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
+}
+
+TEST(backfill, cancel_resume_middle_of_replicascan1)
+{
+ const auto reference_store = FakeStore{ {
+ { "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
+ { "1:00ed7f8e:::rbd_data.1018ac3e755.00000000000000af:head", {10, 196} },
+ { "1:01483aea:::rbd_data.1018ac3e755.0000000000000095:head", {10, 169} },
+ }};
+ auto cluster_fixture = BackfillFixtureBuilder::add_source(
+ reference_store.objs
+ ).add_target(
+ { /* nothing 1 */ }
+ ).add_target(
+ { /* nothing 2 */ }
+ ).get_result();
+
+ EXPECT_CALL(cluster_fixture, backfilled);
+ cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
+ cluster_fixture.cancel();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
+ cluster_fixture.resume();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_till_done();
+
+ EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
+}
+
+TEST(backfill, cancel_resume_middle_of_replicascan2)
{
const auto reference_store = FakeStore{ {
{ "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
@@ -469,12 +538,43 @@ TEST(backfill, cancel_resume)
EXPECT_CALL(cluster_fixture, backfilled);
cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
cluster_fixture.cancel();
cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
cluster_fixture.resume();
cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_till_done();
+
+ EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
+}
+
+TEST(backfill, cancel_resume_middle_of_push1)
+{
+ const auto reference_store = FakeStore{ {
+ { "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
+ { "1:00ed7f8e:::rbd_data.1018ac3e755.00000000000000af:head", {10, 196} },
+ { "1:01483aea:::rbd_data.1018ac3e755.0000000000000095:head", {10, 169} },
+ }};
+ auto cluster_fixture = BackfillFixtureBuilder::add_source(
+ reference_store.objs
+ ).add_target(
+ { /* nothing 1 */ }
+ ).add_target(
+ { /* nothing 2 */ }
+ ).get_result();
+
+ EXPECT_CALL(cluster_fixture, backfilled);
+ cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.cancel();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
+ cluster_fixture.resume();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
@@ -483,7 +583,7 @@ TEST(backfill, cancel_resume)
EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
}
-TEST(backfill, cancel_resume_middle_of_scan)
+TEST(backfill, cancel_resume_middle_of_push2)
{
const auto reference_store = FakeStore{ {
{ "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
@@ -501,14 +601,46 @@ TEST(backfill, cancel_resume_middle_of_scan)
EXPECT_CALL(cluster_fixture, backfilled);
cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
cluster_fixture.cancel();
cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
cluster_fixture.resume();
cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.next_till_done();
+
+ EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
+}
+
+TEST(backfill, cancel_resume_middle_of_push3)
+{
+ const auto reference_store = FakeStore{ {
+ { "1:00058bcc:::rbd_data.1018ac3e755.00000000000000d5:head", {10, 234} },
+ { "1:00ed7f8e:::rbd_data.1018ac3e755.00000000000000af:head", {10, 196} },
+ { "1:01483aea:::rbd_data.1018ac3e755.0000000000000095:head", {10, 169} },
+ }};
+ auto cluster_fixture = BackfillFixtureBuilder::add_source(
+ reference_store.objs
+ ).add_target(
+ { /* nothing 1 */ }
+ ).add_target(
+ { /* nothing 2 */ }
+ ).get_result();
+
+ EXPECT_CALL(cluster_fixture, backfilled);
+ cluster_fixture.next_round2<crimson::osd::BackfillState::PrimaryScanned>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ReplicaScanned>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.cancel();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::CancelBackfill>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
cluster_fixture.next_round2<crimson::osd::BackfillState::ObjectPushed>();
+ cluster_fixture.resume();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::Triggered>();
+ cluster_fixture.next_round2<crimson::osd::BackfillState::RequestDone>();
cluster_fixture.next_till_done();
EXPECT_TRUE(cluster_fixture.all_stores_look_like(reference_store));
diff --git a/src/test/crimson/test_fixed_kv_node_layout.cc b/src/test/crimson/test_fixed_kv_node_layout.cc
index e6377ec14e3..9b6d19661ac 100644
--- a/src/test/crimson/test_fixed_kv_node_layout.cc
+++ b/src/test/crimson/test_fixed_kv_node_layout.cc
@@ -88,12 +88,14 @@ struct TestNode : FixedKVNodeLayout<
uint32_t, ceph_le32,
test_val_t, test_val_le_t> {
char buf[4096];
- TestNode() : FixedKVNodeLayout(buf) {
+ TestNode() : FixedKVNodeLayout() {
+ set_layout_buf(buf);
memset(buf, 0, sizeof(buf));
set_meta({0, std::numeric_limits<uint32_t>::max()});
}
TestNode(const TestNode &rhs)
- : FixedKVNodeLayout(buf) {
+ : FixedKVNodeLayout() {
+ set_layout_buf(buf);
::memcpy(buf, rhs.buf, sizeof(buf));
}
diff --git a/src/test/crimson/test_messenger_thrash.cc b/src/test/crimson/test_messenger_thrash.cc
index 72e3f221755..246613f4446 100644
--- a/src/test/crimson/test_messenger_thrash.cc
+++ b/src/test/crimson/test_messenger_thrash.cc
@@ -22,6 +22,8 @@
#include "crimson/net/Messenger.h"
#include "test/crimson/ctest_utils.h"
+#include <boost/random/uniform_int.hpp>
+
using namespace std::chrono_literals;
namespace bpo = boost::program_options;
using crimson::common::local_conf;
diff --git a/src/test/crimson/test_monc.cc b/src/test/crimson/test_monc.cc
index c30098fe87f..7152110d646 100644
--- a/src/test/crimson/test_monc.cc
+++ b/src/test/crimson/test_monc.cc
@@ -2,6 +2,7 @@
#include "common/ceph_argparse.h"
#include "crimson/common/auth_handler.h"
#include "crimson/common/config_proxy.h"
+#include "crimson/common/perf_counters_collection.h"
#include "crimson/mon/MonClient.h"
#include "crimson/net/Connection.h"
#include "crimson/net/Messenger.h"
diff --git a/src/test/crypto.cc b/src/test/crypto.cc
index 819d41c7218..67fb440eeb9 100644
--- a/src/test/crypto.cc
+++ b/src/test/crypto.cc
@@ -1,6 +1,8 @@
#include <errno.h>
#include <time.h>
+#include <iostream> // for std::cout
+
#include <boost/container/small_vector.hpp>
#include "gtest/gtest.h"
diff --git a/src/test/daemon_config.cc b/src/test/daemon_config.cc
index cdea3b05932..4c7abd70b20 100644
--- a/src/test/daemon_config.cc
+++ b/src/test/daemon_config.cc
@@ -21,6 +21,8 @@
#include "include/rados/librados.h"
#include <errno.h>
+
+#include <iostream> // for std::cout
#include <sstream>
#include <string>
#include <string.h>
diff --git a/src/test/encoding.cc b/src/test/encoding.cc
index 3c83716b048..3d508909d6d 100644
--- a/src/test/encoding.cc
+++ b/src/test/encoding.cc
@@ -4,6 +4,8 @@
#include <fmt/format.h>
#include "gtest/gtest.h"
+#include <iostream> // for std::cout
+
using namespace std;
template < typename T >
diff --git a/src/test/fio/fio_ceph_objectstore.cc b/src/test/fio/fio_ceph_objectstore.cc
index ade043f0cd1..f5fa9ceca73 100644
--- a/src/test/fio/fio_ceph_objectstore.cc
+++ b/src/test/fio/fio_ceph_objectstore.cc
@@ -15,6 +15,7 @@
#include "os/ObjectStore.h"
#include "global/global_init.h"
+#include "common/debug.h"
#include "common/errno.h"
#include "include/intarith.h"
#include "include/stringify.h"
@@ -29,6 +30,12 @@
#include "include/ceph_assert.h" // fio.h clobbers our assert.h
#include <algorithm>
+#if defined(WITH_SEASTAR) && !defined(WITH_ALIEN)
+#include "crimson/common/perf_counters_collection.h"
+#else
+#include "common/perf_counters_collection.h"
+#endif
+
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_
diff --git a/src/test/fio/fio_librgw.cc b/src/test/fio/fio_librgw.cc
index bac4ff2daac..89c09647b61 100644
--- a/src/test/fio/fio_librgw.cc
+++ b/src/test/fio/fio_librgw.cc
@@ -300,8 +300,6 @@ namespace {
*/
static void fio_librgw_cleanup(struct thread_data *td)
{
- int r = 0;
-
dprint(FD_IO, "fio_librgw_cleanup\n");
/* cleanup specific data */
@@ -312,9 +310,9 @@ namespace {
data->release_handles();
if (data->bucket_fh) {
- r = rgw_fh_rele(data->fs, data->bucket_fh, 0 /* flags */);
+ rgw_fh_rele(data->fs, data->bucket_fh, 0 /* flags */);
}
- r = rgw_umount(data->fs, RGW_UMOUNT_FLAG_NONE);
+ rgw_umount(data->fs, RGW_UMOUNT_FLAG_NONE);
librgw_shutdown(data->rgw_h);
td->io_ops_data = nullptr;
delete data;
diff --git a/src/test/immutable_object_cache/test_DomainSocket.cc b/src/test/immutable_object_cache/test_DomainSocket.cc
index 31d1b9adc20..98ef1722071 100644
--- a/src/test/immutable_object_cache/test_DomainSocket.cc
+++ b/src/test/immutable_object_cache/test_DomainSocket.cc
@@ -6,6 +6,7 @@
#include "gtest/gtest.h"
#include "include/Context.h"
+#include "include/unordered_set.h"
#include "global/global_init.h"
#include "global/global_context.h"
@@ -13,6 +14,7 @@
#include "tools/immutable_object_cache/CacheClient.h"
#include "tools/immutable_object_cache/CacheServer.h"
+using ceph::unordered_set;
using namespace ceph::immutable_obj_cache;
class TestCommunication :public ::testing::Test {
diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc
index 6f10d2bbd4e..8760f594ae6 100644
--- a/src/test/libcephfs/test.cc
+++ b/src/test/libcephfs/test.cc
@@ -2706,6 +2706,19 @@ TEST(LibCephFS, Statxat) {
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_2, &stx, 0, 0), 0);
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+ // test relative to root with empty relpath
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+ int dir_fd = ceph_openat(cmount, fd, dir_name, O_DIRECTORY | O_RDONLY, 0);
+ ASSERT_LE(0, dir_fd);
+ ASSERT_EQ(ceph_statxat(cmount, dir_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+ ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
+ ASSERT_EQ(0, ceph_close(cmount, dir_fd));
+ int file_fd = ceph_openat(cmount, fd, rel_file_name_2, O_RDONLY, 0);
+ ASSERT_LE(0, file_fd);
+ ASSERT_EQ(ceph_statxat(cmount, file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+ ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+ ASSERT_EQ(0, ceph_close(cmount, file_fd));
+#endif
ASSERT_EQ(0, ceph_close(cmount, fd));
// test relative to dir
@@ -2713,6 +2726,14 @@ TEST(LibCephFS, Statxat) {
ASSERT_LE(0, fd);
ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_1, &stx, 0, 0), 0);
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+ // test relative to dir with empty relpath
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+ int rel_file_fd = ceph_openat(cmount, fd, rel_file_name_1, O_RDONLY, 0);
+ ASSERT_LE(0, rel_file_fd);
+ ASSERT_EQ(ceph_statxat(cmount, rel_file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+ ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+ ASSERT_EQ(0, ceph_close(cmount, rel_file_fd));
+#endif
// delete the dirtree, recreate and verify
ASSERT_EQ(0, ceph_unlink(cmount, file_path));
@@ -3265,6 +3286,13 @@ TEST(LibCephFS, Chownat) {
// change ownership to nobody -- we assume nobody exists and id is always 65534
ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
ASSERT_EQ(ceph_chownat(cmount, fd, rel_file_path, 65534, 65534, 0), 0);
+ // change relative fd ownership with AT_EMPTY_PATH
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+ int file_fd = ceph_openat(cmount, fd, rel_file_path, O_RDONLY, 0);
+ ASSERT_LE(0, file_fd);
+ ASSERT_EQ(ceph_chownat(cmount, file_fd, "", 65534, 65534, AT_EMPTY_PATH), 0);
+ ceph_close(cmount, file_fd);
+#endif
ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
ceph_close(cmount, fd);
diff --git a/src/test/librados/aio.cc b/src/test/librados/aio.cc
index 68587fe87d1..7fb90bdd38e 100644
--- a/src/test/librados/aio.cc
+++ b/src/test/librados/aio.cc
@@ -1722,3 +1722,59 @@ TEST(LibRadosAioEC, MultiWrite) {
rados_aio_release(my_completion2);
rados_aio_release(my_completion3);
}
+
+TEST(LibRadosAio, CancelBeforeSubmit) {
+ AioTestData test_data;
+ ASSERT_EQ("", test_data.init());
+
+ rados_completion_t completion;
+ ASSERT_EQ(0, rados_aio_create_completion2(nullptr, nullptr, &completion));
+
+ ASSERT_EQ(0, rados_aio_cancel(test_data.m_ioctx, completion));
+ rados_aio_release(completion);
+}
+
+TEST(LibRadosAio, CancelBeforeComplete) {
+ AioTestData test_data;
+ ASSERT_EQ("", test_data.init());
+
+ // cancellation tests are racy, so retry if completion beats the cancellation
+ int ret = 0;
+ int tries = 10;
+ do {
+ rados_completion_t completion;
+ ASSERT_EQ(0, rados_aio_create_completion2(nullptr, nullptr, &completion));
+ char buf[128];
+ ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent",
+ completion, buf, sizeof(buf), 0));
+
+ ASSERT_EQ(0, rados_aio_cancel(test_data.m_ioctx, completion));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, rados_aio_wait_for_complete(completion));
+ }
+ ret = rados_aio_get_return_value(completion);
+ rados_aio_release(completion);
+ } while (ret == -ENOENT && --tries);
+
+ ASSERT_EQ(-ECANCELED, ret);
+}
+
+TEST(LibRadosAio, CancelAfterComplete) {
+ AioTestData test_data;
+ rados_completion_t completion;
+ ASSERT_EQ("", test_data.init());
+
+ ASSERT_EQ(0, rados_aio_create_completion2(nullptr, nullptr, &completion));
+ char buf[128];
+ ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent",
+ completion, buf, sizeof(buf), 0));
+
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, rados_aio_wait_for_complete(completion));
+ }
+ ASSERT_EQ(0, rados_aio_cancel(test_data.m_ioctx, completion));
+ ASSERT_EQ(-ENOENT, rados_aio_get_return_value(completion));
+ rados_aio_release(completion);
+}
diff --git a/src/test/librados/aio_cxx.cc b/src/test/librados/aio_cxx.cc
index 92326e4dbc0..5e35869b5c2 100644
--- a/src/test/librados/aio_cxx.cc
+++ b/src/test/librados/aio_cxx.cc
@@ -1,5 +1,6 @@
#include <errno.h>
#include <fcntl.h>
+#include <deque>
#include <sstream>
#include <string>
#include <utility>
@@ -2466,3 +2467,92 @@ TEST(LibRadosAio, MultiReads) {
ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
}
}
+
+// cancellation test fixture for global setup/teardown
+// parameterized to test both IoCtx::aio_cancel() and AioCompletion::cancel()
+class Cancel : public ::testing::TestWithParam<bool> {
+ static constexpr auto pool_prefix = "ceph_test_rados_api_pp";
+ static Rados rados;
+ static std::string pool_name;
+ protected:
+ static IoCtx ioctx;
+ public:
+ static void SetUpTestCase() {
+ pool_name = get_temp_pool_name(pool_prefix);
+ ASSERT_EQ("", create_one_pool_pp(pool_name, rados));
+ ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx));
+ }
+ static void TearDownTestCase() {
+ destroy_one_pool_pp(pool_name, rados);
+ }
+};
+Rados Cancel::rados;
+std::string Cancel::pool_name;
+IoCtx Cancel::ioctx;
+
+TEST_P(Cancel, BeforeSubmit)
+{
+ const bool use_completion = GetParam();
+
+ auto c = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
+ if (use_completion) {
+ ASSERT_EQ(0, c->cancel());
+ } else {
+ ASSERT_EQ(0, ioctx.aio_cancel(c.get()));
+ }
+}
+
+TEST_P(Cancel, BeforeComplete)
+{
+ const bool use_completion = GetParam();
+
+ // cancellation tests are racy, so retry if completion beats the cancellation
+ int ret = 0;
+ int tries = 10;
+ do {
+ auto c = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
+ ObjectReadOperation op;
+ op.assert_exists();
+ ioctx.aio_operate("nonexistent", c.get(), &op, nullptr);
+
+ if (use_completion) {
+ EXPECT_EQ(0, c->cancel());
+ } else {
+ EXPECT_EQ(0, ioctx.aio_cancel(c.get()));
+ }
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, c->wait_for_complete());
+ }
+ ret = c->get_return_value();
+ } while (ret == -ENOENT && --tries);
+
+ EXPECT_EQ(-ECANCELED, ret);
+}
+
+TEST_P(Cancel, AfterComplete)
+{
+ const bool use_completion = GetParam();
+
+ auto c = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
+ ObjectReadOperation op;
+ op.assert_exists();
+ ioctx.aio_operate("nonexistent", c.get(), &op, nullptr);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, c->wait_for_complete());
+ }
+ if (use_completion) {
+ EXPECT_EQ(0, c->cancel());
+ } else {
+ EXPECT_EQ(0, ioctx.aio_cancel(c.get()));
+ }
+ EXPECT_EQ(-ENOENT, c->get_return_value());
+}
+
+std::string cancel_test_name(const testing::TestParamInfo<Cancel::ParamType>& info)
+{
+ return info.param ? "cancel" : "aio_cancel";
+}
+
+INSTANTIATE_TEST_SUITE_P(LibRadosAio, Cancel, testing::Bool(), cancel_test_name);
diff --git a/src/test/librados/asio.cc b/src/test/librados/asio.cc
index 01ebb957150..500f36508a7 100644
--- a/src/test/librados/asio.cc
+++ b/src/test/librados/asio.cc
@@ -21,10 +21,14 @@
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
+#include <boost/asio/bind_cancellation_slot.hpp>
+#include <boost/asio/cancellation_signal.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>
+#include <optional>
+
#define dout_subsys ceph_subsys_rados
#define dout_context g_ceph_context
@@ -78,6 +82,15 @@ void rethrow(std::exception_ptr eptr) {
if (eptr) std::rethrow_exception(eptr);
}
+auto capture(std::optional<error_code>& out) {
+ return [&out] (error_code ec, ...) { out = ec; };
+}
+
+auto capture(boost::asio::cancellation_signal& signal,
+ std::optional<error_code>& out) {
+ return boost::asio::bind_cancellation_slot(signal.slot(), capture(out));
+}
+
TEST_F(AsioRados, AsyncReadCallback)
{
boost::asio::io_context service;
@@ -385,6 +398,130 @@ TEST_F(AsioRados, AsyncWriteOperationYield)
service.run();
}
+// FIXME: this crashes on windows with:
+// Thread 1 received signal SIGILL, Illegal instruction.
+#ifndef _WIN32
+
+TEST_F(AsioRados, AsyncReadOperationCancelTerminal)
+{
+ // cancellation tests are racy, so retry if completion beats the cancellation
+ boost::system::error_code ec;
+ int tries = 10;
+ do {
+ boost::asio::io_context service;
+ boost::asio::cancellation_signal signal;
+ std::optional<error_code> result;
+
+ librados::ObjectReadOperation op;
+ op.assert_exists();
+ librados::async_operate(service, io, "noexist", &op, 0, nullptr,
+ capture(signal, result));
+
+ service.poll();
+ EXPECT_FALSE(service.stopped());
+ EXPECT_FALSE(result);
+
+ signal.emit(boost::asio::cancellation_type::terminal);
+
+ service.run();
+ ASSERT_TRUE(result);
+ ec = *result;
+
+ signal.emit(boost::asio::cancellation_type::all); // noop
+ } while (ec == std::errc::no_such_file_or_directory && --tries);
+
+ EXPECT_EQ(ec, boost::asio::error::operation_aborted);
+}
+
+TEST_F(AsioRados, AsyncReadOperationCancelTotal)
+{
+ // cancellation tests are racy, so retry if completion beats the cancellation
+ boost::system::error_code ec;
+ int tries = 10;
+ do {
+ boost::asio::io_context service;
+ boost::asio::cancellation_signal signal;
+ std::optional<error_code> result;
+
+ librados::ObjectReadOperation op;
+ op.assert_exists();
+ librados::async_operate(service, io, "noexist", &op, 0, nullptr,
+ capture(signal, result));
+
+ service.poll();
+ EXPECT_FALSE(service.stopped());
+ EXPECT_FALSE(result);
+
+ signal.emit(boost::asio::cancellation_type::total);
+
+ service.run();
+ ASSERT_TRUE(result);
+ ec = *result;
+
+ signal.emit(boost::asio::cancellation_type::all); // noop
+ } while (ec == std::errc::no_such_file_or_directory && --tries);
+
+ EXPECT_EQ(ec, boost::asio::error::operation_aborted);
+}
+
+TEST_F(AsioRados, AsyncWriteOperationCancelTerminal)
+{
+ // cancellation tests are racy, so retry if completion beats the cancellation
+ boost::system::error_code ec;
+ int tries = 10;
+ do {
+ boost::asio::io_context service;
+ boost::asio::cancellation_signal signal;
+ std::optional<error_code> result;
+
+ librados::ObjectWriteOperation op;
+ op.assert_exists();
+ librados::async_operate(service, io, "noexist", &op, 0, nullptr,
+ capture(signal, result));
+
+ service.poll();
+ EXPECT_FALSE(service.stopped());
+ EXPECT_FALSE(result);
+
+ signal.emit(boost::asio::cancellation_type::terminal);
+
+ service.run();
+ ASSERT_TRUE(result);
+ ec = *result;
+
+ signal.emit(boost::asio::cancellation_type::all); // noop
+ } while (ec == std::errc::no_such_file_or_directory && --tries);
+
+ EXPECT_EQ(ec, boost::asio::error::operation_aborted);
+}
+
+TEST_F(AsioRados, AsyncWriteOperationCancelTotal)
+{
+ boost::asio::io_context service;
+ boost::asio::cancellation_signal signal;
+ std::optional<error_code> ec;
+
+ librados::ObjectWriteOperation op;
+ op.assert_exists();
+ librados::async_operate(service, io, "noexist", &op, 0, nullptr,
+ capture(signal, ec));
+
+ service.poll();
+ EXPECT_FALSE(service.stopped());
+ EXPECT_FALSE(ec);
+
+ // noop, write only supports terminal
+ signal.emit(boost::asio::cancellation_type::total);
+
+ service.run();
+ ASSERT_TRUE(ec);
+ EXPECT_EQ(ec, std::errc::no_such_file_or_directory);
+
+ signal.emit(boost::asio::cancellation_type::all); // noop
+}
+
+#endif // not _WIN32
+
int main(int argc, char **argv)
{
auto args = argv_to_vec(argc, argv);
diff --git a/src/test/librados/misc.cc b/src/test/librados/misc.cc
index 6425d3aac02..ced9fb5f2ee 100644
--- a/src/test/librados/misc.cc
+++ b/src/test/librados/misc.cc
@@ -12,6 +12,8 @@
#include "include/scope_guard.h"
#include "include/stringify.h"
#include "common/Checksummer.h"
+#include "common/Clock.h" // for ceph_clock_now()
+#include "common/config_proxy.h" // for class ConfigProxy
#include "global/global_context.h"
#include "test/librados/test.h"
#include "test/librados/TestCase.h"
diff --git a/src/test/librados/misc_cxx.cc b/src/test/librados/misc_cxx.cc
index 1f8c212beaf..46bda84a638 100644
--- a/src/test/librados/misc_cxx.cc
+++ b/src/test/librados/misc_cxx.cc
@@ -16,6 +16,7 @@
#include "include/scope_guard.h"
#include "include/stringify.h"
#include "common/Checksummer.h"
+#include "common/config_proxy.h" // for class ConfigProxy
#include "mds/mdstypes.h"
#include "global/global_context.h"
#include "test/librados/testcase_cxx.h"
diff --git a/src/test/librados/test_common.cc b/src/test/librados/test_common.cc
index 647a9ff4858..e6e6c21bdf1 100644
--- a/src/test/librados/test_common.cc
+++ b/src/test/librados/test_common.cc
@@ -2,6 +2,7 @@
// vim: ts=8 sw=2 smarttab
#include "common/Formatter.h"
+#include "include/ceph_assert.h"
#include "include/stringify.h"
#include "json_spirit/json_spirit.h"
#include "test_common.h"
diff --git a/src/test/librados_test_stub/TestMemIoCtxImpl.cc b/src/test/librados_test_stub/TestMemIoCtxImpl.cc
index 248fd5b8feb..363bc9b62fc 100644
--- a/src/test/librados_test_stub/TestMemIoCtxImpl.cc
+++ b/src/test/librados_test_stub/TestMemIoCtxImpl.cc
@@ -6,6 +6,7 @@
#include "common/Clock.h"
#include "include/err.h"
#include <functional>
+#include <shared_mutex> // for std::shared_lock
#include <boost/algorithm/string/predicate.hpp>
#include <errno.h>
#include <include/compat.h>
diff --git a/src/test/librados_test_stub/TestMemRadosClient.cc b/src/test/librados_test_stub/TestMemRadosClient.cc
index 37d45327c30..09cd20c465e 100644
--- a/src/test/librados_test_stub/TestMemRadosClient.cc
+++ b/src/test/librados_test_stub/TestMemRadosClient.cc
@@ -5,6 +5,7 @@
#include "test/librados_test_stub/TestMemCluster.h"
#include "test/librados_test_stub/TestMemIoCtxImpl.h"
#include <errno.h>
+#include <shared_mutex> // for std::shared_lock
#include <sstream>
namespace librados {
diff --git a/src/test/librbd/fsx.cc b/src/test/librbd/fsx.cc
index 4ba00ad1555..27029ed6330 100644
--- a/src/test/librbd/fsx.cc
+++ b/src/test/librbd/fsx.cc
@@ -60,6 +60,7 @@
#include "include/rados/librados.hpp"
#include "include/rbd/librbd.h"
#include "include/rbd/librbd.hpp"
+#include "include/rbd_types.h" // for RBD_DATA_PREFIX
#include "common/Cond.h"
#include "common/SubProcess.h"
#include "common/safe_io.h"
diff --git a/src/test/librbd/io/test_mock_ImageRequest.cc b/src/test/librbd/io/test_mock_ImageRequest.cc
index 6ee67fe5f1c..b68009304d5 100644
--- a/src/test/librbd/io/test_mock_ImageRequest.cc
+++ b/src/test/librbd/io/test_mock_ImageRequest.cc
@@ -10,6 +10,8 @@
#include "librbd/io/ObjectDispatchSpec.h"
#include "librbd/io/Utils.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/journal/test_Replay.cc b/src/test/librbd/journal/test_Replay.cc
index 9b4580e6472..1fb3f6225ad 100644
--- a/src/test/librbd/journal/test_Replay.cc
+++ b/src/test/librbd/journal/test_Replay.cc
@@ -22,6 +22,8 @@
#include "librbd/io/ReadResult.h"
#include "librbd/journal/Types.h"
+#include <shared_mutex> // for std::shared_lock
+
void register_test_journal_replay() {
}
diff --git a/src/test/librbd/migration/test_mock_HttpClient.cc b/src/test/librbd/migration/test_mock_HttpClient.cc
index f3888755c79..901c4231dd0 100644
--- a/src/test/librbd/migration/test_mock_HttpClient.cc
+++ b/src/test/librbd/migration/test_mock_HttpClient.cc
@@ -307,7 +307,7 @@ TEST_F(TestMockMigrationHttpClient, OpenCloseHttps) {
boost::asio::ssl::context ssl_context{boost::asio::ssl::context::tlsv12};
load_server_certificate(ssl_context);
- boost::beast::ssl_stream<boost::beast::tcp_stream> ssl_stream{
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_stream{
std::move(socket), ssl_context};
C_SaferCond on_ssl_handshake_ctx;
@@ -341,7 +341,7 @@ TEST_F(TestMockMigrationHttpClient, OpenHttpsHandshakeFail) {
boost::asio::ssl::context ssl_context{boost::asio::ssl::context::tlsv12};
load_server_certificate(ssl_context);
- boost::beast::ssl_stream<boost::beast::tcp_stream> ssl_stream{
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_stream{
std::move(socket), ssl_context};
C_SaferCond on_ssl_handshake_ctx;
diff --git a/src/test/librbd/mock/MockObjectMap.h b/src/test/librbd/mock/MockObjectMap.h
index 5e3235cf023..427d064e150 100644
--- a/src/test/librbd/mock/MockObjectMap.h
+++ b/src/test/librbd/mock/MockObjectMap.h
@@ -8,6 +8,8 @@
#include "librbd/Utils.h"
#include "gmock/gmock.h"
+#include <boost/optional/optional_io.hpp>
+
namespace librbd {
struct MockObjectMap {
diff --git a/src/test/librbd/object_map/test_mock_InvalidateRequest.cc b/src/test/librbd/object_map/test_mock_InvalidateRequest.cc
index 5ea40c03d69..eabce9cca5c 100644
--- a/src/test/librbd/object_map/test_mock_InvalidateRequest.cc
+++ b/src/test/librbd/object_map/test_mock_InvalidateRequest.cc
@@ -10,6 +10,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace object_map {
diff --git a/src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc b/src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc
index 7f77aaf839f..0c78d9fdaf5 100644
--- a/src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc
+++ b/src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc
@@ -12,6 +12,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace object_map {
diff --git a/src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc b/src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc
index 20318743d30..8d3cb2a2b81 100644
--- a/src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc
+++ b/src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc
@@ -12,6 +12,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace object_map {
diff --git a/src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc b/src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc
index 7b89a0996c1..bfae75ce680 100644
--- a/src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc
+++ b/src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc
@@ -11,6 +11,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace object_map {
diff --git a/src/test/librbd/object_map/test_mock_UpdateRequest.cc b/src/test/librbd/object_map/test_mock_UpdateRequest.cc
index c240dec0004..5c4934d4ad5 100644
--- a/src/test/librbd/object_map/test_mock_UpdateRequest.cc
+++ b/src/test/librbd/object_map/test_mock_UpdateRequest.cc
@@ -14,6 +14,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace object_map {
diff --git a/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc b/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc
index 171ac41a71a..db6b21d024d 100644
--- a/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc
+++ b/src/test/librbd/operation/test_mock_DisableFeaturesRequest.cc
@@ -20,6 +20,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc b/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc
index b7bf7d1781d..615e471d114 100644
--- a/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc
+++ b/src/test/librbd/operation/test_mock_EnableFeaturesRequest.cc
@@ -19,6 +19,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/operation/test_mock_Request.cc b/src/test/librbd/operation/test_mock_Request.cc
index 5c5e7a37535..f23a3386c7f 100644
--- a/src/test/librbd/operation/test_mock_Request.cc
+++ b/src/test/librbd/operation/test_mock_Request.cc
@@ -8,6 +8,8 @@
#include "librbd/AsyncRequest.h"
#include "librbd/operation/Request.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/operation/test_mock_ResizeRequest.cc b/src/test/librbd/operation/test_mock_ResizeRequest.cc
index 552ba5c9756..b80ef20f0a4 100644
--- a/src/test/librbd/operation/test_mock_ResizeRequest.cc
+++ b/src/test/librbd/operation/test_mock_ResizeRequest.cc
@@ -14,6 +14,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace util {
diff --git a/src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc b/src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc
index 218fc6b0417..2756a616090 100644
--- a/src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc
+++ b/src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc
@@ -13,6 +13,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace mirror {
namespace snapshot {
diff --git a/src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc b/src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc
index aa8c1e78dc7..bd488fc511d 100644
--- a/src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc
+++ b/src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc
@@ -15,6 +15,8 @@
// template definitions
#include "librbd/operation/SnapshotProtectRequest.cc"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace operation {
diff --git a/src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc b/src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc
index 4469cb80dde..e55c6e8687c 100644
--- a/src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc
+++ b/src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc
@@ -15,6 +15,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace image {
diff --git a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc
index 65eac7a6d6c..d11378ec4de 100644
--- a/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc
+++ b/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc
@@ -14,6 +14,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc b/src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc
index 26b1be2066a..9b48e0c0009 100644
--- a/src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc
+++ b/src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc
@@ -17,6 +17,8 @@
// template definitions
#include "librbd/operation/SnapshotUnprotectRequest.cc"
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace operation {
diff --git a/src/test/librbd/operation/test_mock_TrimRequest.cc b/src/test/librbd/operation/test_mock_TrimRequest.cc
index 1771e741377..aebd2117dae 100644
--- a/src/test/librbd/operation/test_mock_TrimRequest.cc
+++ b/src/test/librbd/operation/test_mock_TrimRequest.cc
@@ -16,6 +16,8 @@
#include "gtest/gtest.h"
#include <boost/variant.hpp>
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/librbd/test_DeepCopy.cc b/src/test/librbd/test_DeepCopy.cc
index fcce0c642e2..457f958e68a 100644
--- a/src/test/librbd/test_DeepCopy.cc
+++ b/src/test/librbd/test_DeepCopy.cc
@@ -11,6 +11,8 @@
#include "librbd/io/ReadResult.h"
#include "test/librados/crimson_utils.h"
+#include <shared_mutex> // for std::shared_lock
+
void register_test_deep_copy() {
}
diff --git a/src/test/librbd/test_ImageWatcher.cc b/src/test/librbd/test_ImageWatcher.cc
index 780ce7c0e3a..1adc5b4149d 100644
--- a/src/test/librbd/test_ImageWatcher.cc
+++ b/src/test/librbd/test_ImageWatcher.cc
@@ -25,6 +25,7 @@
#include <iostream>
#include <map>
#include <set>
+#include <shared_mutex> // for std::shared_lock
#include <sstream>
#include <vector>
diff --git a/src/test/librbd/test_Migration.cc b/src/test/librbd/test_Migration.cc
index 8c0f4b61b21..b017fbba7e6 100644
--- a/src/test/librbd/test_Migration.cc
+++ b/src/test/librbd/test_Migration.cc
@@ -20,6 +20,8 @@
#include "common/Cond.h"
#include <boost/scope_exit.hpp>
+#include <shared_mutex> // for std::shared_lock
+
void register_test_migration() {
}
diff --git a/src/test/librbd/test_ObjectMap.cc b/src/test/librbd/test_ObjectMap.cc
index 32d223a1d27..15d5db37cde 100644
--- a/src/test/librbd/test_ObjectMap.cc
+++ b/src/test/librbd/test_ObjectMap.cc
@@ -17,6 +17,8 @@
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_sum.hpp>
+#include <shared_mutex> // for std::shared_lock
+
void register_test_object_map() {
}
diff --git a/src/test/librbd/test_fixture.cc b/src/test/librbd/test_fixture.cc
index 9ddebec482e..d2a3d469ece 100644
--- a/src/test/librbd/test_fixture.cc
+++ b/src/test/librbd/test_fixture.cc
@@ -17,6 +17,7 @@
#include "test/librados/test.h"
#include "test/librados/test_cxx.h"
#include <iostream>
+#include <shared_mutex> // for std::shared_lock
#include <sstream>
#include <stdlib.h>
diff --git a/src/test/librbd/test_internal.cc b/src/test/librbd/test_internal.cc
index 37930cb26bb..8f6cbb9e807 100644
--- a/src/test/librbd/test_internal.cc
+++ b/src/test/librbd/test_internal.cc
@@ -27,6 +27,7 @@
#include <boost/scope_exit.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/assign/list_of.hpp>
+#include <shared_mutex> // for std::shared_lock
#include <utility>
#include <vector>
#include "test/librados/crimson_utils.h"
@@ -1570,6 +1571,83 @@ TEST_F(TestInternal, FlattenNoEmptyObjects)
rados_ioctx_destroy(d_ioctx);
}
+TEST_F(TestInternal, FlattenInconsistentObjectMap)
+{
+ REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
+ REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2));
+
+ librbd::ImageCtx* ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ librbd::NoOpProgressContext no_op;
+ ASSERT_EQ(0, ictx->operations->resize((1 << ictx->order) * 5, true, no_op));
+
+ bufferlist bl;
+ bl.append(std::string(256, '1'));
+ for (int i = 1; i < 5; i++) {
+ ASSERT_EQ(256, api::Io<>::write(*ictx, (1 << ictx->order) * i, 256,
+ bufferlist{bl}, 0));
+ }
+
+ ASSERT_EQ(0, snap_create(*ictx, "snap"));
+ ASSERT_EQ(0, snap_protect(*ictx, "snap"));
+
+ uint64_t features;
+ ASSERT_EQ(0, librbd::get_features(ictx, &features));
+
+ std::string clone_name = get_temp_image_name();
+ int order = ictx->order;
+ ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx,
+ clone_name.c_str(), features, &order, 0, 0));
+
+ close_image(ictx);
+ ASSERT_EQ(0, open_image(clone_name, &ictx));
+
+ C_SaferCond lock_ctx;
+ {
+ std::shared_lock owner_locker{ictx->owner_lock};
+ ictx->exclusive_lock->try_acquire_lock(&lock_ctx);
+ }
+ ASSERT_EQ(0, lock_ctx.wait());
+ ASSERT_TRUE(ictx->exclusive_lock->is_lock_owner());
+
+ ceph::BitVector<2> inconsistent_object_map;
+ inconsistent_object_map.resize(5);
+ inconsistent_object_map[0] = OBJECT_NONEXISTENT;
+ inconsistent_object_map[1] = OBJECT_NONEXISTENT;
+ inconsistent_object_map[2] = OBJECT_EXISTS;
+ inconsistent_object_map[3] = OBJECT_EXISTS_CLEAN;
+ // OBJECT_PENDING shouldn't happen within parent overlap, but test
+ // anyway
+ inconsistent_object_map[4] = OBJECT_PENDING;
+
+ auto object_map = new librbd::ObjectMap<>(*ictx, CEPH_NOSNAP);
+ C_SaferCond save_ctx;
+ {
+ std::shared_lock owner_locker{ictx->owner_lock};
+ std::unique_lock image_locker{ictx->image_lock};
+ object_map->set_object_map(inconsistent_object_map);
+ object_map->aio_save(&save_ctx);
+ }
+ ASSERT_EQ(0, save_ctx.wait());
+ object_map->put();
+
+ close_image(ictx);
+ ASSERT_EQ(0, open_image(clone_name, &ictx));
+ ASSERT_EQ(0, ictx->operations->flatten(no_op));
+
+ bufferptr read_ptr(256);
+ bufferlist read_bl;
+ read_bl.push_back(read_ptr);
+
+ librbd::io::ReadResult read_result{&read_bl};
+ for (int i = 1; i < 5; i++) {
+ ASSERT_EQ(256, api::Io<>::read(*ictx, (1 << ictx->order) * i, 256,
+ librbd::io::ReadResult{read_result}, 0));
+ EXPECT_TRUE(bl.contents_equal(read_bl));
+ }
+}
+
TEST_F(TestInternal, PoolMetadataConfApply) {
REQUIRE_FORMAT_V2();
diff --git a/src/test/librbd/test_mock_ExclusiveLock.cc b/src/test/librbd/test_mock_ExclusiveLock.cc
index 6feb54ec661..259adab9d0b 100644
--- a/src/test/librbd/test_mock_ExclusiveLock.cc
+++ b/src/test/librbd/test_mock_ExclusiveLock.cc
@@ -15,6 +15,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <list>
+#include <shared_mutex> // for std::shared_lock
#include <boost/scope_exit.hpp>
namespace librbd {
diff --git a/src/test/librbd/test_mock_Journal.cc b/src/test/librbd/test_mock_Journal.cc
index 589695c50b3..d39f9c75c02 100644
--- a/src/test/librbd/test_mock_Journal.cc
+++ b/src/test/librbd/test_mock_Journal.cc
@@ -9,6 +9,7 @@
#include "test/librbd/mock/io/MockObjectDispatch.h"
#include "common/Cond.h"
#include "common/ceph_mutex.h"
+#include "common/debug.h"
#include "common/WorkQueue.h"
#include "cls/journal/cls_journal_types.h"
#include "journal/Journaler.h"
@@ -28,6 +29,7 @@
#include "gtest/gtest.h"
#include <functional>
#include <list>
+#include <shared_mutex> // for std::shared_lock
#include <boost/scope_exit.hpp>
#define dout_context g_ceph_context
diff --git a/src/test/librbd/test_mock_ObjectMap.cc b/src/test/librbd/test_mock_ObjectMap.cc
index 39e29172c58..e2085d093cb 100644
--- a/src/test/librbd/test_mock_ObjectMap.cc
+++ b/src/test/librbd/test_mock_ObjectMap.cc
@@ -10,6 +10,8 @@
#include "librbd/object_map/UpdateRequest.h"
#include <boost/scope_exit.hpp>
+#include <shared_mutex> // for std::shared_lock
+
namespace librbd {
namespace {
diff --git a/src/test/mon/PGMap.cc b/src/test/mon/PGMap.cc
index 43d6de4c783..c8f167a4594 100644
--- a/src/test/mon/PGMap.cc
+++ b/src/test/mon/PGMap.cc
@@ -14,6 +14,7 @@
#include "mon/PGMap.h"
#include "gtest/gtest.h"
+#include "common/TextTable.h"
#include "include/stringify.h"
using namespace std;
diff --git a/src/test/neorados/read_operations.cc b/src/test/neorados/read_operations.cc
index adf5f34ae5e..d5df84585b8 100644
--- a/src/test/neorados/read_operations.cc
+++ b/src/test/neorados/read_operations.cc
@@ -15,6 +15,7 @@
#include <initializer_list>
#include <memory>
#include <string_view>
+#include <unordered_set>
#include <utility>
#include <boost/asio/use_awaitable.hpp>
@@ -27,6 +28,7 @@
#include <xxHash/xxhash.h>
#include "include/neorados/RADOS.hpp"
+#include "include/rbd/features.h" // for RBD_FEATURES_ALL
#include "osd/error_code.h"
diff --git a/src/test/objectstore/Allocator_bench.cc b/src/test/objectstore/Allocator_bench.cc
index 1758d8c338e..0c577f4fe1b 100644
--- a/src/test/objectstore/Allocator_bench.cc
+++ b/src/test/objectstore/Allocator_bench.cc
@@ -14,6 +14,7 @@
#include "include/Context.h"
#include "os/bluestore/Allocator.h"
+#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
typedef boost::mt11213b gen_type;
diff --git a/src/test/objectstore/Allocator_test.cc b/src/test/objectstore/Allocator_test.cc
index 47d29e8590a..1a66303add3 100644
--- a/src/test/objectstore/Allocator_test.cc
+++ b/src/test/objectstore/Allocator_test.cc
@@ -5,6 +5,7 @@
* Author: Ramesh Chander, Ramesh.Chander@sandisk.com
*/
#include <iostream>
+#include <boost/random/mersenne_twister.hpp> // for boost::mt11213b
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
diff --git a/src/test/objectstore/CMakeLists.txt b/src/test/objectstore/CMakeLists.txt
index bddff3f6727..08388640043 100644
--- a/src/test/objectstore/CMakeLists.txt
+++ b/src/test/objectstore/CMakeLists.txt
@@ -48,6 +48,18 @@ add_executable(unittest_rocksdb_option
add_ceph_unittest(unittest_rocksdb_option)
target_link_libraries(unittest_rocksdb_option global os ${BLKID_LIBRARIES})
+# ceph_test_bluefs (a clone of unittest_bluefs)
+add_executable(ceph_test_bluefs
+ test_bluefs.cc
+ )
+target_link_libraries(ceph_test_bluefs
+ os
+ global
+ ${UNITTEST_LIBS}
+ )
+install(TARGETS ceph_test_bluefs
+ DESTINATION ${CMAKE_INSTALL_BINDIR})
+
if(WITH_EVENTTRACE)
add_dependencies(os eventtrace_tp)
endif()
diff --git a/src/test/objectstore/Fragmentation_simulator.cc b/src/test/objectstore/Fragmentation_simulator.cc
index 02a2991cd0c..1dbaaa8e58c 100644
--- a/src/test/objectstore/Fragmentation_simulator.cc
+++ b/src/test/objectstore/Fragmentation_simulator.cc
@@ -7,6 +7,7 @@
#include "common/ceph_argparse.h"
#include "common/ceph_mutex.h"
#include "common/common_init.h"
+#include "common/debug.h"
#include "common/hobject.h"
#include "global/global_context.h"
@@ -18,6 +19,7 @@
#include "os/ObjectStore.h"
#include "test/objectstore/ObjectStoreImitator.h"
#include <fstream>
+#include <boost/random/mersenne_twister.hpp> // for boost::mt11213b
#include <boost/random/uniform_int.hpp>
#include <fmt/core.h>
#include <mutex>
diff --git a/src/test/objectstore/ObjectStoreImitator.cc b/src/test/objectstore/ObjectStoreImitator.cc
index 6b4e7d9eaa8..14cc20c1622 100644
--- a/src/test/objectstore/ObjectStoreImitator.cc
+++ b/src/test/objectstore/ObjectStoreImitator.cc
@@ -6,6 +6,7 @@
*/
#include "test/objectstore/ObjectStoreImitator.h"
#include "common/Clock.h"
+#include "common/debug.h"
#include "common/Finisher.h"
#include "common/errno.h"
#include "include/ceph_assert.h"
@@ -13,6 +14,7 @@
#include "os/bluestore/bluestore_types.h"
#include <algorithm>
#include <cmath>
+#include <shared_mutex> // for std::shared_lock
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_test
diff --git a/src/test/objectstore/ObjectStoreImitator.h b/src/test/objectstore/ObjectStoreImitator.h
index d71d7f2fe58..875f9041b83 100644
--- a/src/test/objectstore/ObjectStoreImitator.h
+++ b/src/test/objectstore/ObjectStoreImitator.h
@@ -347,6 +347,16 @@ public:
) override {
return {};
}
+
+ int omap_iterate(CollectionHandle &c, ///< [in] collection
+ const ghobject_t &oid, ///< [in] object
+ /// [in] where the iterator should point to at the beginning
+ omap_iter_seek_t start_from,
+ std::function<omap_iter_ret_t(std::string_view, std::string_view)> f
+ ) override {
+ return 0;
+ }
+
void set_fsid(uuid_d u) override {}
uuid_d get_fsid() override { return {}; }
uint64_t estimate_objects_overhead(uint64_t num_objects) override {
diff --git a/src/test/objectstore/allocsim/ops_replayer.cc b/src/test/objectstore/allocsim/ops_replayer.cc
index fd947f5c454..c5908d9f576 100644
--- a/src/test/objectstore/allocsim/ops_replayer.cc
+++ b/src/test/objectstore/allocsim/ops_replayer.cc
@@ -1,4 +1,5 @@
#include <algorithm>
+#include <functional>
#include <boost/program_options/value_semantic.hpp>
#include <cassert>
#include <cctype>
@@ -13,26 +14,46 @@
#include <fstream>
#include <filesystem>
#include <mutex>
-#include "include/rados/buffer_fwd.h"
-#include "include/rados/librados.hpp"
#include <atomic>
-#include <fmt/format.h>
#include <map>
#include <memory>
#include <random>
#include <string>
#include <iostream>
#include <vector>
+#include <format>
+
+#include <fmt/format.h>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
+#include "include/rados/buffer_fwd.h"
+#include "include/rados/librados.hpp"
+
namespace po = boost::program_options;
using namespace std;
using namespace ceph;
+namespace settings {
+
+// Returns a function which restricts a value to a specified range by throwing if it is not in range:
+// (Note: std::clamp() does not throw.)
+auto clamp_or_throw(auto min, auto max)
+{
+ return [=](auto& x) {
+ if(std::less<>{}(x, min) or std::greater<>{}(x, max)) {
+ throw std::out_of_range(fmt::format("value expected between {} and {}, but got {}", min, max, x));
+ }
+
+ return x;
+ };
+}
+
+} // namespace settings
+
// compare shared_ptr<string>
struct StringPtrCompare
{
@@ -338,8 +359,8 @@ int main(int argc, char** argv) {
// options
uint64_t io_depth = 8;
- uint64_t nparser_threads = 16;
- uint64_t nworker_threads = 16;
+ int nparser_threads = 16;
+ int nworker_threads = 16;
string file("input.txt");
string ceph_conf_path("./ceph.conf");
string pool("test_pool");
@@ -351,8 +372,8 @@ int main(int argc, char** argv) {
("input-files,i", po::value<vector<string>>()->multitoken(), "List of input files (output of op_scraper.py). Multiple files will be merged and sorted by time order")
("ceph-conf", po::value<string>(&ceph_conf_path)->default_value("ceph.conf"), "Path to ceph conf")
("io-depth", po::value<uint64_t>(&io_depth)->default_value(64), "I/O depth")
- ("parser-threads", po::value<uint64_t>(&nparser_threads)->default_value(16), "Number of parser threads")
- ("worker-threads", po::value<uint64_t>(&nworker_threads)->default_value(16), "Number of I/O worker threads")
+ ("parser-threads", po::value<int>(&nparser_threads)->default_value(16)->notifier(settings::clamp_or_throw(1, 256)), "Number of parser threads")
+ ("worker-threads", po::value<int>(&nworker_threads)->default_value(16)->notifier(settings::clamp_or_throw(1, 256)), "Number of I/O worker threads")
("pool", po::value<string>(&pool)->default_value("test_pool"), "Pool to use for I/O")
("skip-do-ops", po::bool_switch(&skip_do_ops)->default_value(false), "Skip doing operations")
;
diff --git a/src/test/objectstore/store_test.cc b/src/test/objectstore/store_test.cc
index 38b62f3ea6d..a75857e5e97 100644
--- a/src/test/objectstore/store_test.cc
+++ b/src/test/objectstore/store_test.cc
@@ -39,6 +39,7 @@
#include "global/global_init.h"
#include "common/ceph_mutex.h"
#include "common/Cond.h"
+#include "common/debug.h"
#include "common/errno.h"
#include "common/options.h" // for the size literals
#include "common/pretty_binary.h"
diff --git a/src/test/objectstore/test_bluefs.cc b/src/test/objectstore/test_bluefs.cc
index e2f95dd6c80..32173d61afe 100644
--- a/src/test/objectstore/test_bluefs.cc
+++ b/src/test/objectstore/test_bluefs.cc
@@ -23,6 +23,11 @@
using namespace std;
+// some test should not be executed on jenkins make check
+#define SKIP_JENKINS() \
+ if (getenv("JENKINS_HOME") != nullptr) GTEST_SKIP_("test disabled on jenkins");
+
+
std::unique_ptr<char[]> gen_buffer(uint64_t size)
{
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size);
@@ -174,6 +179,7 @@ TEST(BlueFS, small_appends) {
}
TEST(BlueFS, very_large_write) {
+ SKIP_JENKINS();
// we'll write a ~5G file, so allocate more than that for the whole fs
uint64_t size = 1048576 * 1024 * 6ull;
TempBdev bdev{size};
@@ -248,6 +254,7 @@ TEST(BlueFS, very_large_write) {
}
TEST(BlueFS, very_large_write2) {
+ SKIP_JENKINS();
// we'll write a ~5G file, so allocate more than that for the whole fs
uint64_t size_full = 1048576 * 1024 * 6ull;
uint64_t size = 1048576 * 1024 * 5ull;
@@ -1419,6 +1426,87 @@ TEST(BlueFS, test_concurrent_dir_link_and_compact_log_56210) {
}
}
+TEST(BlueFS, truncate_drops_allocations) {
+ constexpr uint64_t K = 1024;
+ constexpr uint64_t M = 1024 * K;
+ uuid_d fsid;
+ const char* DIR_NAME="dir";
+ const char* FILE_NAME="file1";
+ struct {
+ uint64_t preallocated_size;
+ uint64_t write_size;
+ uint64_t truncate_to;
+ uint64_t allocated_after_truncate;
+ uint64_t slow_size = 0;
+ uint64_t slow_alloc_size = 64*K;
+ uint64_t db_size = 128*M;
+ uint64_t db_alloc_size = 1*M;
+ } scenarios [] = {
+ // on DB(which is SLOW) : 1 => 1, 64K remains
+ { 1*M, 1, 1, 64*K },
+ // on DB(which is SLOW), alloc 4K : 1 => 1, 4K remains
+ { 1*M, 1, 1, 4*K, 0, 4*K },
+ // on DB(which is SLOW), truncation on AU boundary : 128K => 128K, 128K remains
+ { 1*M, 128*K, 128*K, 128*K },
+ // on DB(which is SLOW), no prealloc, truncation to 0 : 1666K => 0, 0 remains
+ { 0, 1666*K, 0, 0 },
+ // on DB, truncate to 123K, expect 1M occupied
+ { 1234*K, 123*K, 123*K, 1*M, 128*M, 64*K, 10*M, 1*M },
+ // on DB, truncate to 0, expect 0 occupied
+ { 1234*K, 345*K, 0, 0, 128*M, 64*K, 10*M, 1*M },
+ // on DB, truncate to AU boundary, expect exactly 1M occupied
+ { 1234*K, 1123*K, 1*M, 1*M, 128*M, 64*K, 10*M, 1*M },
+ // on DB and SLOW, truncate only data on SLOW
+ { 0, 10*M+1, 10*M+1, 10*M+64*K, 128*M, 64*K, 10*M, 1*M },
+ // on DB and SLOW, preallocate and truncate only data on SLOW
+ { 6*M, 12*M, 10*M+1, 10*M+64*K, 128*M, 64*K, 10*M, 1*M },
+ // on DB and SLOW, preallocate and truncate all in SLOW and some on DB
+ // note! prealloc 6M is important, one allocation for 12M will fallback to SLOW
+ // in 6M + 6M we can be sure that 6M is on DB and 6M is on SLOW
+ { 6*M, 12*M, 3*M+1, 4*M, 128*M, 64*K, 11*M, 1*M },
+ };
+ for (auto& s : scenarios) {
+ ConfSaver conf(g_ceph_context->_conf);
+ conf.SetVal("bluefs_shared_alloc_size", stringify(s.slow_alloc_size).c_str());
+ conf.SetVal("bluefs_alloc_size", stringify(s.db_alloc_size).c_str());
+
+ g_ceph_context->_conf.set_val("bluefs_shared_alloc_size", stringify(s.slow_alloc_size));
+ g_ceph_context->_conf.set_val("bluefs_alloc_size", stringify(s.db_alloc_size));
+ TempBdev bdev_db{s.db_size};
+ TempBdev bdev_slow{s.slow_size};
+
+ BlueFS fs(g_ceph_context);
+ if (s.db_size != 0) {
+ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev_db.path, false, 0));
+ }
+ if (s.slow_size != 0) {
+ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_SLOW, bdev_slow.path, false, 0));
+ }
+
+ ASSERT_EQ(0, fs.mkfs(fsid, {BlueFS::BDEV_DB, false, false}));
+ ASSERT_EQ(0, fs.mount());
+ ASSERT_EQ(0, fs.maybe_verify_layout({BlueFS::BDEV_DB, false, false}));
+ BlueFS::FileWriter *h;
+ ASSERT_EQ(0, fs.mkdir("dir"));
+ ASSERT_EQ(0, fs.open_for_write(DIR_NAME, FILE_NAME, &h, false));
+ uint64_t pre = fs.get_used();
+ ASSERT_EQ(0, fs.preallocate(h->file, 0, s.preallocated_size));
+ const std::string content(s.write_size, 'x');
+ h->append(content.c_str(), content.length());
+ fs.fsync(h);
+ ASSERT_EQ(0, fs.truncate(h, s.truncate_to));
+ fs.fsync(h);
+ uint64_t post = fs.get_used();
+ fs.close_writer(h);
+ EXPECT_EQ(pre, post - s.allocated_after_truncate);
+
+ fs.umount();
+ }
+}
+
+
+
+
TEST(BlueFS, test_log_runway) {
uint64_t max_log_runway = 65536;
ConfSaver conf(g_ceph_context->_conf);
@@ -1601,6 +1689,91 @@ TEST(BlueFS, test_log_runway_advance_seq) {
fs.compact_log();
}
+TEST(BlueFS, test_69481_truncate_corrupts_log) {
+ uint64_t size = 1048576 * 128;
+ TempBdev bdev{size};
+ BlueFS fs(g_ceph_context);
+ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev.path, false));
+ uuid_d fsid;
+ ASSERT_EQ(0, fs.mkfs(fsid, { BlueFS::BDEV_DB, false, false }));
+ ASSERT_EQ(0, fs.mount());
+ ASSERT_EQ(0, fs.maybe_verify_layout({ BlueFS::BDEV_DB, false, false }));
+
+ BlueFS::FileWriter *f = nullptr;
+ BlueFS::FileWriter *a = nullptr;
+ ASSERT_EQ(0, fs.mkdir("dir"));
+ ASSERT_EQ(0, fs.open_for_write("dir", "test-file", &f, false));
+ ASSERT_EQ(0, fs.open_for_write("dir", "just-allocate", &a, false));
+
+ // create 4 distinct extents in file f
+ // a is here only to prevent f from merging extents together
+ fs.preallocate(f->file, 0, 0x10000);
+ fs.preallocate(a->file, 0, 0x10000);
+ fs.preallocate(f->file, 0, 0x20000);
+ fs.preallocate(a->file, 0, 0x20000);
+ fs.preallocate(f->file, 0, 0x30000);
+ fs.preallocate(a->file, 0, 0x30000);
+ fs.preallocate(f->file, 0, 0x40000);
+ fs.preallocate(a->file, 0, 0x40000);
+ fs.close_writer(a);
+
+ fs.truncate(f, 0);
+ fs.fsync(f);
+
+ bufferlist bl;
+ bl.append(std::string(" ", 0x15678));
+ f->append(bl);
+ fs.truncate(f, 0x15678);
+ fs.fsync(f);
+ fs.close_writer(f);
+
+ fs.umount();
+ // remount to verify
+ ASSERT_EQ(0, fs.mount());
+ fs.umount();
+}
+
+TEST(BlueFS, test_69481_truncate_asserts) {
+ uint64_t size = 1048576 * 128;
+ TempBdev bdev{size};
+ BlueFS fs(g_ceph_context);
+ ASSERT_EQ(0, fs.add_block_device(BlueFS::BDEV_DB, bdev.path, false));
+ uuid_d fsid;
+ ASSERT_EQ(0, fs.mkfs(fsid, { BlueFS::BDEV_DB, false, false }));
+ ASSERT_EQ(0, fs.mount());
+ ASSERT_EQ(0, fs.maybe_verify_layout({ BlueFS::BDEV_DB, false, false }));
+
+ BlueFS::FileWriter *f = nullptr;
+ BlueFS::FileWriter *a = nullptr;
+ ASSERT_EQ(0, fs.mkdir("dir"));
+ ASSERT_EQ(0, fs.open_for_write("dir", "test-file", &f, false));
+ ASSERT_EQ(0, fs.open_for_write("dir", "just-allocate", &a, false));
+
+ // create 4 distinct extents in file f
+ // a is here only to prevent f from merging extents together
+ fs.preallocate(f->file, 0, 0x10000);
+ fs.preallocate(a->file, 0, 0x10000);
+ fs.preallocate(f->file, 0, 0x20000);
+ fs.preallocate(a->file, 0, 0x20000);
+ fs.preallocate(f->file, 0, 0x30000);
+ fs.preallocate(a->file, 0, 0x30000);
+ fs.preallocate(f->file, 0, 0x40000);
+ fs.preallocate(a->file, 0, 0x40000);
+ fs.close_writer(a);
+
+ fs.truncate(f, 0);
+ fs.fsync(f);
+
+ bufferlist bl;
+ bl.append(std::string(" ", 0x35678));
+ f->append(bl);
+ fs.truncate(f, 0x35678);
+ fs.fsync(f);
+ fs.close_writer(f);
+
+ fs.umount();
+}
+
int main(int argc, char **argv) {
auto args = argv_to_vec(argc, argv);
map<string,string> defaults = {
diff --git a/src/test/objectstore/test_deferred.cc b/src/test/objectstore/test_deferred.cc
index 1b5608101c8..4c2790eaac7 100644
--- a/src/test/objectstore/test_deferred.cc
+++ b/src/test/objectstore/test_deferred.cc
@@ -2,6 +2,7 @@
// vim: ts=8 sw=2 smarttab
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <memory>
@@ -44,10 +45,11 @@ void create_deferred_and_terminate() {
coll_t cid;
ghobject_t hoid;
ObjectStore::CollectionHandle ch;
- ceph_assert(::mkdir("bluestore.test_temp_dir", 0777) == 0);
+ std::string const db_store_dir = "bluestore.test_temp_dir_" + std::to_string(time(NULL));
+ ceph_assert(::mkdir(db_store_dir.c_str(), 0777) == 0);
store = ObjectStore::create(g_ceph_context,
"bluestore",
- "bluestore.test_temp_dir",
+ db_store_dir.c_str(),
"store_test_temp_journal");
ceph_assert(store->mkfs() == 0);
ceph_assert(store->mount() == 0);
diff --git a/src/test/objectstore/test_memstore_clone.cc b/src/test/objectstore/test_memstore_clone.cc
index 507f74d22d2..b4ef66933e1 100644
--- a/src/test/objectstore/test_memstore_clone.cc
+++ b/src/test/objectstore/test_memstore_clone.cc
@@ -17,6 +17,7 @@
#include "os/ObjectStore.h"
#include <gtest/gtest.h>
#include "include/ceph_assert.h"
+#include "common/debug.h"
#include "common/errno.h"
#include "store_test_fixture.h"
diff --git a/src/test/objectstore_bench.cc b/src/test/objectstore_bench.cc
index 65a2987d08d..ef5392efb45 100644
--- a/src/test/objectstore_bench.cc
+++ b/src/test/objectstore_bench.cc
@@ -12,6 +12,7 @@
#include "global/global_init.h"
+#include "common/debug.h"
#include "common/strtol.h"
#include "common/ceph_argparse.h"
diff --git a/src/test/osd/CMakeLists.txt b/src/test/osd/CMakeLists.txt
index f2d1471e22e..798558ebbe0 100644
--- a/src/test/osd/CMakeLists.txt
+++ b/src/test/osd/CMakeLists.txt
@@ -22,7 +22,7 @@ install(TARGETS
add_executable(ceph_test_rados_io_sequence
${CMAKE_CURRENT_SOURCE_DIR}/ceph_test_rados_io_sequence.cc)
target_link_libraries(ceph_test_rados_io_sequence
- librados global object_io_exerciser)
+ librados global object_io_exerciser json_structures)
install(TARGETS
ceph_test_rados_io_sequence
DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/test/osd/ceph_test_rados_io_sequence.cc b/src/test/osd/ceph_test_rados_io_sequence.cc
index 5e340c5c9c5..96808ea37e5 100644
--- a/src/test/osd/ceph_test_rados_io_sequence.cc
+++ b/src/test/osd/ceph_test_rados_io_sequence.cc
@@ -1,82 +1,104 @@
#include "ceph_test_rados_io_sequence.h"
+#include <boost/asio/io_context.hpp>
#include <iostream>
#include <vector>
-#include <boost/asio/io_context.hpp>
-
-#include "include/random.h"
-
-#include "librados/librados_asio.h"
-#include "common/ceph_argparse.h"
-#include "include/interval_set.h"
-#include "global/global_init.h"
-#include "global/global_context.h"
+#include "common/Formatter.h"
#include "common/Thread.h"
+#include "common/ceph_argparse.h"
+#include "common/ceph_json.h"
#include "common/debug.h"
#include "common/dout.h"
#include "common/split.h"
+#include "common/strtol.h" // for strict_iecstrtoll()
+#include "common/ceph_json.h"
+#include "common/Formatter.h"
#include "common/io_exerciser/DataGenerator.h"
+#include "common/io_exerciser/EcIoSequence.h"
+#include "common/io_exerciser/IoOp.h"
+#include "common/io_exerciser/IoSequence.h"
#include "common/io_exerciser/Model.h"
#include "common/io_exerciser/ObjectModel.h"
#include "common/io_exerciser/RadosIo.h"
-#include "common/io_exerciser/IoOp.h"
-#include "common/io_exerciser/IoSequence.h"
+#include "common/json/BalancerStructures.h"
+#include "common/json/ConfigStructures.h"
+#include "common/json/OSDStructures.h"
+#include "fmt/format.h"
+#include "global/global_context.h"
+#include "global/global_init.h"
+#include "include/interval_set.h"
+#include "include/random.h"
+#include "json_spirit/json_spirit.h"
+#include "librados/librados_asio.h"
#define dout_subsys ceph_subsys_rados
#define dout_context g_ceph_context
+using OpType = ceph::io_exerciser::OpType;
+
+using DoneOp = ceph::io_exerciser::DoneOp;
+using BarrierOp = ceph::io_exerciser::BarrierOp;
+using CreateOp = ceph::io_exerciser::CreateOp;
+using RemoveOp = ceph::io_exerciser::RemoveOp;
+using SingleReadOp = ceph::io_exerciser::SingleReadOp;
+using DoubleReadOp = ceph::io_exerciser::DoubleReadOp;
+using TripleReadOp = ceph::io_exerciser::TripleReadOp;
+using SingleWriteOp = ceph::io_exerciser::SingleWriteOp;
+using DoubleWriteOp = ceph::io_exerciser::DoubleWriteOp;
+using TripleWriteOp = ceph::io_exerciser::TripleWriteOp;
+using SingleFailedWriteOp = ceph::io_exerciser::SingleFailedWriteOp;
+using DoubleFailedWriteOp = ceph::io_exerciser::DoubleFailedWriteOp;
+using TripleFailedWriteOp = ceph::io_exerciser::TripleFailedWriteOp;
+
namespace {
- struct Size {};
- void validate(boost::any& v, const std::vector<std::string>& values,
- Size *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
-
- std::string parse_error;
- uint64_t size = strict_iecstrtoll(s, &parse_error);
- if (!parse_error.empty()) {
- throw po::validation_error(po::validation_error::invalid_option_value);
- }
- v = boost::any(size);
- }
-
- struct Pair {};
- void validate(boost::any& v, const std::vector<std::string>& values,
- Pair *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
- auto part = ceph::split(s).begin();
- std::string parse_error;
- int first = strict_iecstrtoll(*part++, &parse_error);
- int second = strict_iecstrtoll(*part, &parse_error);
- if (!parse_error.empty()) {
- throw po::validation_error(po::validation_error::invalid_option_value);
- }
- v = boost::any(std::pair<int,int>{first,second});
- }
-
- struct PluginString {};
- void validate(boost::any& v, const std::vector<std::string>& values,
- PluginString *target_type, int) {
- po::validators::check_first_occurrence(v);
- const std::string &s = po::validators::get_single_string(values);
-
- const std::string_view* pluginIt = std::find(
- ceph::io_sequence::tester::pluginChoices.begin(),
- ceph::io_sequence::tester::pluginChoices.end(),
- s
- );
- if(ceph::io_sequence::tester::pluginChoices.end() == pluginIt)
- {
- throw po::validation_error(po::validation_error::invalid_option_value);
- }
+struct Size {};
+void validate(boost::any& v, const std::vector<std::string>& values,
+ Size* target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string& s = po::validators::get_single_string(values);
- v = boost::any(*pluginIt);
+ std::string parse_error;
+ uint64_t size = strict_iecstrtoll(s, &parse_error);
+ if (!parse_error.empty()) {
+ throw po::validation_error(po::validation_error::invalid_option_value);
}
+ v = boost::any(size);
+}
+
+struct Pair {};
+void validate(boost::any& v, const std::vector<std::string>& values,
+ Pair* target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string& s = po::validators::get_single_string(values);
+ auto part = ceph::split(s).begin();
+ std::string parse_error;
+ int first = strict_iecstrtoll(*part++, &parse_error);
+ int second = strict_iecstrtoll(*part, &parse_error);
+ if (!parse_error.empty()) {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+ v = boost::any(std::pair<int, int>{first, second});
+}
+
+struct PluginString {};
+void validate(boost::any& v, const std::vector<std::string>& values,
+ PluginString* target_type, int) {
+ po::validators::check_first_occurrence(v);
+ const std::string& s = po::validators::get_single_string(values);
+
+ const std::string_view* pluginIt =
+ std::find(ceph::io_sequence::tester::pluginChoices.begin(),
+ ceph::io_sequence::tester::pluginChoices.end(), s);
+ if (ceph::io_sequence::tester::pluginChoices.end() == pluginIt) {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+
+ v = boost::any(*pluginIt);
+}
- constexpr std::string_view usage[] = {
+constexpr std::string_view usage[] = {
"Basic usage:",
"",
"ceph_test_rados_io_sequence",
@@ -118,103 +140,99 @@ namespace {
"\t are specified with unit of blocksize. Supported commands:",
"\t\t create <len>",
"\t\t remove",
- "\t\t read|write <off> <len>",
- "\t\t read2|write2 <off> <len> <off> <len>",
- "\t\t read3|write3 <off> <len> <off> <len> <off> <len>",
- "\t\t done"
- };
-
- po::options_description get_options_description()
- {
- po::options_description desc("ceph_test_rados_io options");
- desc.add_options()
- ("help,h",
- "show help message")
- ("listsequence,l",
- "show list of sequences")
- ("dryrun,d",
- "test sequence, do not issue any I/O")
- ("verbose",
- "more verbose output during test")
- ("sequence,s", po::value<int>(),
- "test specified sequence")
- ("seed", po::value<int>(),
- "seed for whole test")
- ("seqseed", po::value<int>(),
- "seed for sequence")
- ("blocksize,b", po::value<Size>(),
- "block size (default 2048)")
- ("chunksize,c", po::value<Size>(),
- "chunk size (default 4096)")
- ("pool,p", po::value<std::string>(),
- "pool name")
- ("object,o", po::value<std::string>()->default_value("test"),
- "object name")
- ("km", po::value<Pair>(),
- "k,m EC pool profile (default 2,2)")
- ("plugin", po::value<PluginString>(),
- "EC plugin (isa or jerasure)")
- ("objectsize", po::value<Pair>(),
- "min,max object size in blocks (default 1,32)")
- ("threads,t", po::value<int>(),
- "number of threads of I/O per object (default 1)")
- ("parallel,p", po::value<int>()->default_value(1),
- "number of objects to exercise in parallel")
- ("interactive",
- "interactive mode, execute IO commands from stdin");
-
- return desc;
- }
-
- int parse_io_seq_options(
- po::variables_map& vm,
- int argc,
- char** argv)
- {
- std::vector<std::string> unrecognized_options;
- try {
- po::options_description desc = get_options_description();
-
- auto parsed = po::command_line_parser(argc, argv)
- .options(desc)
- .allow_unregistered()
- .run();
- po::store(parsed, vm);
- po::notify(vm);
- unrecognized_options = po::collect_unrecognized(parsed.options,
- po::include_positional);
-
- if (!unrecognized_options.empty())
- {
- std::stringstream ss;
- ss << "Unrecognised command options supplied: ";
- while (unrecognized_options.size() > 1)
- {
- ss << unrecognized_options.back().c_str() << ", ";
- unrecognized_options.pop_back();
- }
- ss << unrecognized_options.back();
- dout(0) << ss.str() << dendl;
- return 1;
+ "\t\t read|write|failedwrite <off> <len>",
+ "\t\t read2|write2|failedwrite2 <off> <len> <off> <len>",
+ "\t\t read3|write3|failedwrite3 <off> <len> <off> <len> <off> <len>",
+ "\t\t injecterror <type> <shard> <good_count> <fail_count>",
+ "\t\t clearinject <type> <shard>",
+ "\t\t done"};
+
+po::options_description get_options_description() {
+ po::options_description desc("ceph_test_rados_io options");
+ desc.add_options()("help,h", "show help message")("listsequence,l",
+ "show list of sequences")(
+ "dryrun,d", "test sequence, do not issue any I/O")(
+ "verbose", "more verbose output during test")(
+ "sequence,s", po::value<int>(), "test specified sequence")(
+ "seed", po::value<int>(), "seed for whole test")(
+ "seqseed", po::value<int>(), "seed for sequence")(
+ "blocksize,b", po::value<Size>(), "block size (default 2048)")(
+ "chunksize,c", po::value<Size>(), "chunk size (default 4096)")(
+ "pool,p", po::value<std::string>(), "pool name")(
+ "object,o", po::value<std::string>()->default_value("test"),
+ "object name")("km", po::value<Pair>(),
+ "k,m EC pool profile (default 2,2)")(
+ "plugin", po::value<PluginString>(), "EC plugin (isa or jerasure)")(
+ "objectsize", po::value<Pair>(),
+ "min,max object size in blocks (default 1,32)")(
+ "threads,t", po::value<int>(),
+ "number of threads of I/O per object (default 1)")(
+ "parallel,p", po::value<int>()->default_value(1),
+ "number of objects to exercise in parallel")(
+ "testrecovery",
+ "Inject errors during sequences to test recovery processes of OSDs")(
+ "interactive", "interactive mode, execute IO commands from stdin")(
+ "allow_pool_autoscaling",
+ "Allows pool autoscaling. Disabled by default.")(
+ "allow_pool_balancer", "Enables pool balancing. Disabled by default.")(
+ "allow_pool_deep_scrubbing",
+ "Enables pool deep scrub. Disabled by default.")(
+ "allow_pool_scrubbing", "Enables pool scrubbing. Disabled by default.");
+
+ return desc;
+}
+
+int parse_io_seq_options(po::variables_map& vm, int argc, char** argv) {
+ std::vector<std::string> unrecognized_options;
+ try {
+ po::options_description desc = get_options_description();
+
+ auto parsed = po::command_line_parser(argc, argv)
+ .options(desc)
+ .allow_unregistered()
+ .run();
+ po::store(parsed, vm);
+ po::notify(vm);
+ unrecognized_options =
+ po::collect_unrecognized(parsed.options, po::include_positional);
+
+ if (!unrecognized_options.empty()) {
+ std::stringstream ss;
+ ss << "Unrecognised command options supplied: ";
+ while (unrecognized_options.size() > 1) {
+ ss << unrecognized_options.back().c_str() << ", ";
+ unrecognized_options.pop_back();
}
- } catch(const po::error& e) {
- std::cerr << "error: " << e.what() << std::endl;
+ ss << unrecognized_options.back();
+ dout(0) << ss.str() << dendl;
return 1;
}
-
- return 0;
+ } catch (const po::error& e) {
+ std::cerr << "error: " << e.what() << std::endl;
+ return 1;
}
+
+ return 0;
}
+template <typename S>
+int send_mon_command(S& s, librados::Rados& rados, const char* name,
+ ceph::buffer::list& inbl, ceph::buffer::list* outbl, Formatter* f) {
+ std::ostringstream oss;
+ encode_json(name, s, f);
+ f->flush(oss);
+ int rc = rados.mon_command(oss.str(), inbl, outbl, nullptr);
+ return rc;
+}
+
+} // namespace
+
template <typename T, int N, const std::array<T, N>& Ts>
-ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>
- ::ProgramOptionSelector(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm,
- const std::string& option_name,
- bool set_forced,
- bool select_first)
- : rng(rng),
- option_name(option_name) {
+ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>::
+ ProgramOptionSelector(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm, const std::string& option_name,
+ bool set_forced, bool select_first)
+ : rng(rng), option_name(option_name) {
if (set_forced && vm.count(option_name)) {
force_value = vm[option_name].as<T>();
}
@@ -225,76 +243,54 @@ ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>
}
template <typename T, int N, const std::array<T, N>& Ts>
-bool ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>::isForced()
-{
+bool ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>::isForced() {
return force_value.has_value();
}
template <typename T, int N, const std::array<T, N>& Ts>
-const T ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>::choose()
-{
+const T ceph::io_sequence::tester::ProgramOptionSelector<T, N, Ts>::choose() {
if (force_value.has_value()) {
return *force_value;
} else if (first_value.has_value()) {
return *std::exchange(first_value, std::nullopt);
} else {
- return choices[rng(N-1)];
+ return choices[rng(N - 1)];
}
}
-
-
ceph::io_sequence::tester::SelectObjectSize::SelectObjectSize(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "objectsize", true, true)
-{
-}
-
-
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "objectsize", true, true) {}
ceph::io_sequence::tester::SelectBlockSize::SelectBlockSize(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "blocksize", true, true)
-{
-}
-
-
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "blocksize", true, true) {}
ceph::io_sequence::tester::SelectNumThreads::SelectNumThreads(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "threads", true, true)
-{
-}
-
-
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "threads", true, true) {}
ceph::io_sequence::tester::SelectSeqRange::SelectSeqRange(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "sequence", false, false)
-{
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "sequence", false, false) {
if (vm.count(option_name)) {
ceph::io_exerciser::Sequence s =
- static_cast<ceph::io_exerciser::Sequence>(vm["sequence"].as<int>());
+ static_cast<ceph::io_exerciser::Sequence>(vm["sequence"].as<int>());
if (s < ceph::io_exerciser::Sequence::SEQUENCE_BEGIN ||
s >= ceph::io_exerciser::Sequence::SEQUENCE_END) {
dout(0) << "Sequence argument out of range" << dendl;
throw po::validation_error(po::validation_error::invalid_option_value);
}
ceph::io_exerciser::Sequence e = s;
- force_value = std::make_optional<std::pair<ceph::io_exerciser::Sequence,
- ceph::io_exerciser::Sequence>>(
- std::make_pair(s, ++e));
+ force_value = std::make_optional<
+ std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>>(
+ std::make_pair(s, ++e));
}
}
-const std::pair<ceph::io_exerciser::Sequence,ceph::io_exerciser::Sequence>
- ceph::io_sequence::tester::SelectSeqRange::choose() {
- if (force_value.has_value())
- {
+const std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>
+ceph::io_sequence::tester::SelectSeqRange::choose() {
+ if (force_value.has_value()) {
return *force_value;
} else {
return std::make_pair(ceph::io_exerciser::Sequence::SEQUENCE_BEGIN,
@@ -302,45 +298,34 @@ const std::pair<ceph::io_exerciser::Sequence,ceph::io_exerciser::Sequence>
}
}
-
-
ceph::io_sequence::tester::SelectErasureKM::SelectErasureKM(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "km", true, true)
-{
-}
-
-
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "km", true, true) {}
ceph::io_sequence::tester::SelectErasurePlugin::SelectErasurePlugin(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "plugin", true, false)
-{
-}
-
-
-
-ceph::io_sequence::tester::SelectErasureChunkSize::SelectErasureChunkSize(ceph::util::random_number_generator<int>& rng, po::variables_map vm)
- : ProgramOptionSelector(rng, vm, "stripe_unit", true, false)
-{
-}
-
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "plugin", true, false) {}
+ceph::io_sequence::tester::SelectErasureChunkSize::SelectErasureChunkSize(
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm)
+ : ProgramOptionSelector(rng, vm, "chunksize", true, true) {}
ceph::io_sequence::tester::SelectECPool::SelectECPool(
- ceph::util::random_number_generator<int>& rng,
- po::variables_map vm,
- librados::Rados& rados,
- bool dry_run)
- : ProgramOptionSelector(rng, vm, "pool", false, false),
- rados(rados),
- dry_run(dry_run),
- skm(SelectErasureKM(rng, vm)),
- spl(SelectErasurePlugin(rng, vm)),
- scs(SelectErasureChunkSize(rng, vm))
-{
+ ceph::util::random_number_generator<int>& rng, po::variables_map vm,
+ librados::Rados& rados, bool dry_run, bool allow_pool_autoscaling,
+ bool allow_pool_balancer, bool allow_pool_deep_scrubbing,
+ bool allow_pool_scrubbing, bool test_recovery)
+ : ProgramOptionSelector(rng, vm, "pool", false, false),
+ rados(rados),
+ dry_run(dry_run),
+ allow_pool_autoscaling(allow_pool_autoscaling),
+ allow_pool_balancer(allow_pool_balancer),
+ allow_pool_deep_scrubbing(allow_pool_deep_scrubbing),
+ allow_pool_scrubbing(allow_pool_scrubbing),
+ test_recovery(test_recovery),
+ skm(SelectErasureKM(rng, vm)),
+ spl(SelectErasurePlugin(rng, vm)),
+ scs(SelectErasureChunkSize(rng, vm)) {
if (!skm.isForced()) {
if (vm.count("pool")) {
force_value = vm["pool"].as<std::string>();
@@ -348,147 +333,239 @@ ceph::io_sequence::tester::SelectECPool::SelectECPool(
}
}
-const std::string ceph::io_sequence::tester::SelectECPool::choose()
-{
- std::pair<int,int> value;
+const std::string ceph::io_sequence::tester::SelectECPool::choose() {
+ std::pair<int, int> value;
if (!skm.isForced() && force_value.has_value()) {
+ int rc;
+ bufferlist inbl, outbl;
+ auto formatter = std::make_unique<JSONFormatter>(false);
+
+ ceph::messaging::osd::OSDPoolGetRequest osdPoolGetRequest{*force_value};
+ rc = send_mon_command(osdPoolGetRequest, rados, "OSDPoolGetRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+
+ JSONParser p;
+ bool success = p.parse(outbl.c_str(), outbl.length());
+ ceph_assert(success);
+
+ ceph::messaging::osd::OSDPoolGetReply osdPoolGetReply;
+ osdPoolGetReply.decode_json(&p);
+
+ ceph::messaging::osd::OSDECProfileGetRequest osdECProfileGetRequest{
+ osdPoolGetReply.erasure_code_profile};
+ rc = send_mon_command(osdECProfileGetRequest, rados,
+ "OSDECProfileGetRequest", inbl, &outbl,
+ formatter.get());
+ ceph_assert(rc == 0);
+
+ success = p.parse(outbl.c_str(), outbl.length());
+ ceph_assert(success);
+
+ ceph::messaging::osd::OSDECProfileGetReply reply;
+ reply.decode_json(&p);
+ k = reply.k;
+ m = reply.m;
return *force_value;
} else {
value = skm.choose();
}
- int k = value.first;
- int m = value.second;
+ k = value.first;
+ m = value.second;
const std::string plugin = std::string(spl.choose());
const uint64_t chunk_size = scs.choose();
- std::string pool_name = "ec_" + plugin +
- "_cs" + std::to_string(chunk_size) +
- "_k" + std::to_string(k) +
- "_m" + std::to_string(m);
- if (!dry_run)
- {
+ std::string pool_name = "ec_" + plugin + "_cs" + std::to_string(chunk_size) +
+ "_k" + std::to_string(k) + "_m" + std::to_string(m);
+ if (!dry_run) {
create_pool(rados, pool_name, plugin, chunk_size, k, m);
}
return pool_name;
}
void ceph::io_sequence::tester::SelectECPool::create_pool(
- librados::Rados& rados,
- const std::string& pool_name,
- const std::string& plugin,
- uint64_t chunk_size,
- int k, int m)
-{
+ librados::Rados& rados, const std::string& pool_name,
+ const std::string& plugin, uint64_t chunk_size, int k, int m) {
int rc;
bufferlist inbl, outbl;
- std::string profile_create =
- "{\"prefix\": \"osd erasure-code-profile set\", \
- \"name\": \"testprofile-" + pool_name + "\", \
- \"profile\": [ \"plugin=" + plugin + "\", \
- \"k=" + std::to_string(k) + "\", \
- \"m=" + std::to_string(m) + "\", \
- \"stripe_unit=" + std::to_string(chunk_size) + "\", \
- \"crush-failure-domain=osd\"]}";
- rc = rados.mon_command(profile_create, inbl, &outbl, nullptr);
+ auto formatter = std::make_unique<JSONFormatter>(false);
+
+ ceph::messaging::osd::OSDECProfileSetRequest ecProfileSetRequest{
+ fmt::format("testprofile-{}", pool_name),
+ {fmt::format("plugin={}", plugin), fmt::format("k={}", k),
+ fmt::format("m={}", m), fmt::format("stripe_unit={}", chunk_size),
+ fmt::format("crush-failure-domain=osd")}};
+ rc = send_mon_command(ecProfileSetRequest, rados, "OSDECProfileSetRequest",
+ inbl, &outbl, formatter.get());
ceph_assert(rc == 0);
- std::string cmdstr =
- "{\"prefix\": \"osd pool create\", \
- \"pool\": \"" + pool_name + "\", \
- \"pool_type\": \"erasure\", \
- \"pg_num\": 8, \
- \"pgp_num\": 8, \
- \"erasure_code_profile\": \"testprofile-" + pool_name + "\"}";
- rc = rados.mon_command(cmdstr, inbl, &outbl, nullptr);
+
+ ceph::messaging::osd::OSDECPoolCreateRequest poolCreateRequest{
+ pool_name, "erasure", 8, 8, fmt::format("testprofile-{}", pool_name)};
+ rc = send_mon_command(poolCreateRequest, rados, "OSDECPoolCreateRequest",
+ inbl, &outbl, formatter.get());
ceph_assert(rc == 0);
-}
+ if (allow_pool_autoscaling) {
+ ceph::messaging::osd::OSDSetRequest setNoAutoscaleRequest{"noautoscale",
+ std::nullopt};
+ rc = send_mon_command(setNoAutoscaleRequest, rados, "OSDSetRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+ }
+
+ if (allow_pool_balancer) {
+ ceph::messaging::balancer::BalancerOffRequest balancerOffRequest{};
+ rc = send_mon_command(balancerOffRequest, rados, "BalancerOffRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+
+ ceph::messaging::balancer::BalancerStatusRequest balancerStatusRequest{};
+ rc = send_mon_command(balancerStatusRequest, rados, "BalancerStatusRequest",
+ inbl, &outbl, formatter.get());
+ ceph_assert(rc == 0);
+
+ JSONParser p;
+ bool success = p.parse(outbl.c_str(), outbl.length());
+ ceph_assert(success);
+
+ ceph::messaging::balancer::BalancerStatusReply reply;
+ reply.decode_json(&p);
+ ceph_assert(!reply.active);
+ }
+ if (allow_pool_deep_scrubbing) {
+ ceph::messaging::osd::OSDSetRequest setNoDeepScrubRequest{"nodeep-scrub",
+ std::nullopt};
+ rc = send_mon_command(setNoDeepScrubRequest, rados, "setNoDeepScrubRequest",
+ inbl, &outbl, formatter.get());
+ ceph_assert(rc == 0);
+ }
+
+ if (allow_pool_scrubbing) {
+ ceph::messaging::osd::OSDSetRequest setNoScrubRequest{"noscrub",
+ std::nullopt};
+ rc = send_mon_command(setNoScrubRequest, rados, "OSDSetRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+ }
+
+ if (test_recovery) {
+ ceph::messaging::config::ConfigSetRequest configSetBluestoreDebugRequest{
+ "global", "bluestore_debug_inject_read_err", "true", std::nullopt};
+ rc = send_mon_command(configSetBluestoreDebugRequest, rados,
+ "ConfigSetRequest", inbl, &outbl,
+ formatter.get());
+ ceph_assert(rc == 0);
+
+ ceph::messaging::config::ConfigSetRequest configSetMaxMarkdownRequest{
+ "global", "osd_max_markdown_count", "99999999", std::nullopt};
+ rc =
+ send_mon_command(configSetMaxMarkdownRequest, rados, "ConfigSetRequest",
+ inbl, &outbl, formatter.get());
+ ceph_assert(rc == 0);
+ }
+}
-ceph::io_sequence::tester::TestObject::TestObject( const std::string oid,
- librados::Rados& rados,
- boost::asio::io_context& asio,
- SelectBlockSize& sbs,
- SelectECPool& spo,
- SelectObjectSize& sos,
- SelectNumThreads& snt,
- SelectSeqRange& ssr,
- ceph::util::random_number_generator<int>& rng,
- ceph::mutex& lock,
- ceph::condition_variable& cond,
- bool dryrun,
- bool verbose,
- std::optional<int> seqseed) :
- rng(rng), verbose(verbose), seqseed(seqseed)
-{
+ceph::io_sequence::tester::TestObject::TestObject(
+ const std::string oid, librados::Rados& rados,
+ boost::asio::io_context& asio, SelectBlockSize& sbs, SelectECPool& spo,
+ SelectObjectSize& sos, SelectNumThreads& snt, SelectSeqRange& ssr,
+ ceph::util::random_number_generator<int>& rng, ceph::mutex& lock,
+ ceph::condition_variable& cond, bool dryrun, bool verbose,
+ std::optional<int> seqseed, bool testrecovery)
+ : rng(rng), verbose(verbose), seqseed(seqseed), testrecovery(testrecovery) {
if (dryrun) {
- verbose = true;
- exerciser_model = std::make_unique<ceph::io_exerciser::ObjectModel>(oid,
- sbs.choose(),
- rng());
+ exerciser_model = std::make_unique<ceph::io_exerciser::ObjectModel>(
+ oid, sbs.choose(), rng());
} else {
const std::string pool = spo.choose();
+ poolK = spo.getChosenK();
+ poolM = spo.getChosenM();
+
int threads = snt.choose();
- exerciser_model = std::make_unique<ceph::io_exerciser::RadosIo>(rados,
- asio,
- pool,
- oid,
- sbs.choose(),
- rng(),
- threads,
- lock,
- cond);
- dout(0) << "= " << oid << " pool=" << pool
- << " threads=" << threads
- << " blocksize=" << exerciser_model->get_block_size()
- << " =" << dendl;
+
+ bufferlist inbl, outbl;
+ auto formatter = std::make_unique<JSONFormatter>(false);
+
+ std::optional<std::vector<int>> cached_shard_order = std::nullopt;
+
+ if (!spo.get_allow_pool_autoscaling() && !spo.get_allow_pool_balancer() &&
+ !spo.get_allow_pool_deep_scrubbing() &&
+ !spo.get_allow_pool_scrubbing()) {
+ ceph::messaging::osd::OSDMapRequest osdMapRequest{pool, oid, ""};
+ int rc = send_mon_command(osdMapRequest, rados, "OSDMapRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+
+ JSONParser p;
+ bool success = p.parse(outbl.c_str(), outbl.length());
+ ceph_assert(success);
+
+ ceph::messaging::osd::OSDMapReply reply{};
+ reply.decode_json(&p);
+ cached_shard_order = reply.acting;
+ }
+
+ exerciser_model = std::make_unique<ceph::io_exerciser::RadosIo>(
+ rados, asio, pool, oid, cached_shard_order, sbs.choose(), rng(),
+ threads, lock, cond);
+ dout(0) << "= " << oid << " pool=" << pool << " threads=" << threads
+ << " blocksize=" << exerciser_model->get_block_size() << " ="
+ << dendl;
}
obj_size_range = sos.choose();
seq_range = ssr.choose();
curseq = seq_range.first;
- seq = ceph::io_exerciser::IoSequence::generate_sequence(curseq,
- obj_size_range,
- seqseed.value_or(rng()));
+
+ if (testrecovery) {
+ seq = ceph::io_exerciser::EcIoSequence::generate_sequence(
+ curseq, obj_size_range, poolK, poolM, seqseed.value_or(rng()));
+ } else {
+ seq = ceph::io_exerciser::IoSequence::generate_sequence(
+ curseq, obj_size_range, seqseed.value_or(rng()));
+ }
+
op = seq->next();
done = false;
- dout(0) << "== " << exerciser_model->get_oid() << " "
- << curseq << " "
- << seq->get_name()
- << " ==" <<dendl;
+ dout(0) << "== " << exerciser_model->get_oid() << " " << curseq << " "
+ << seq->get_name_with_seqseed() << " ==" << dendl;
}
-bool ceph::io_sequence::tester::TestObject::readyForIo()
-{
+bool ceph::io_sequence::tester::TestObject::readyForIo() {
return exerciser_model->readyForIoOp(*op);
}
-bool ceph::io_sequence::tester::TestObject::next()
-{
+bool ceph::io_sequence::tester::TestObject::next() {
if (!done) {
if (verbose) {
- dout(0) << exerciser_model->get_oid()
- << " Step " << seq->get_step() << ": "
- << op->to_string(exerciser_model->get_block_size()) << dendl;
+ dout(0) << exerciser_model->get_oid() << " Step " << seq->get_step()
+ << ": " << op->to_string(exerciser_model->get_block_size())
+ << dendl;
} else {
- dout(5) << exerciser_model->get_oid()
- << " Step " << seq->get_step() << ": "
- << op->to_string(exerciser_model->get_block_size()) << dendl;
+ dout(5) << exerciser_model->get_oid() << " Step " << seq->get_step()
+ << ": " << op->to_string(exerciser_model->get_block_size())
+ << dendl;
}
exerciser_model->applyIoOp(*op);
- if (op->done()) {
- ++curseq;
- if (curseq == seq_range.second) {
+ if (op->getOpType() == ceph::io_exerciser::OpType::Done) {
+ curseq = seq->getNextSupportedSequenceId();
+ if (curseq >= seq_range.second) {
done = true;
dout(0) << exerciser_model->get_oid()
<< " Number of IOs = " << exerciser_model->get_num_io()
<< dendl;
} else {
- seq = ceph::io_exerciser::IoSequence::generate_sequence(curseq,
- obj_size_range,
- seqseed.value_or(rng()));
- dout(0) << "== " << exerciser_model->get_oid() << " "
- << curseq << " " << seq->get_name()
- << " ==" <<dendl;
+ if (testrecovery) {
+ seq = ceph::io_exerciser::EcIoSequence::generate_sequence(
+ curseq, obj_size_range, poolK, poolM, seqseed.value_or(rng()));
+ } else {
+ seq = ceph::io_exerciser::IoSequence::generate_sequence(
+ curseq, obj_size_range, seqseed.value_or(rng()));
+ }
+
+ dout(0) << "== " << exerciser_model->get_oid() << " " << curseq << " "
+ << seq->get_name_with_seqseed() << " ==" << dendl;
op = seq->next();
}
} else {
@@ -498,27 +575,30 @@ bool ceph::io_sequence::tester::TestObject::next()
return done;
}
-bool ceph::io_sequence::tester::TestObject::finished()
-{
- return done;
-}
+bool ceph::io_sequence::tester::TestObject::finished() { return done; }
-int ceph::io_sequence::tester::TestObject::get_num_io()
-{
+int ceph::io_sequence::tester::TestObject::get_num_io() {
return exerciser_model->get_num_io();
}
ceph::io_sequence::tester::TestRunner::TestRunner(po::variables_map& vm,
- librados::Rados& rados) :
- rados(rados),
- seed(vm.contains("seed") ? vm["seed"].as<int>() : time(nullptr)),
- rng(ceph::util::random_number_generator<int>(seed)),
- sbs{rng, vm},
- sos{rng, vm},
- spo{rng, vm, rados, vm.contains("dryrun")},
- snt{rng, vm},
- ssr{rng, vm}
-{
+ librados::Rados& rados)
+ : rados(rados),
+ seed(vm.contains("seed") ? vm["seed"].as<int>() : time(nullptr)),
+ rng(ceph::util::random_number_generator<int>(seed)),
+ sbs{rng, vm},
+ sos{rng, vm},
+ spo{rng,
+ vm,
+ rados,
+ vm.contains("dryrun"),
+ vm.contains("allow_pool_autoscaling"),
+ vm.contains("allow_pool_balancer"),
+ vm.contains("allow_pool_deep_scrubbing"),
+ vm.contains("allow_pool_scrubbing"),
+ vm.contains("test_recovery")},
+ snt{rng, vm},
+ ssr{rng, vm} {
dout(0) << "Test using seed " << seed << dendl;
verbose = vm.contains("verbose");
@@ -531,19 +611,23 @@ ceph::io_sequence::tester::TestRunner::TestRunner(po::variables_map& vm,
num_objects = vm["parallel"].as<int>();
object_name = vm["object"].as<std::string>();
interactive = vm.contains("interactive");
+ testrecovery = vm.contains("testrecovery");
+
+ allow_pool_autoscaling = vm.contains("allow_pool_autoscaling");
+ allow_pool_balancer = vm.contains("allow_pool_balancer");
+ allow_pool_deep_scrubbing = vm.contains("allow_pool_deep_scrubbing");
+ allow_pool_scrubbing = vm.contains("allow_pool_scrubbing");
- if (!dryrun)
- {
+ if (!dryrun) {
guard.emplace(boost::asio::make_work_guard(asio));
- thread = make_named_thread("io_thread",[&asio = asio] { asio.run(); });
+ thread = make_named_thread("io_thread", [&asio = asio] { asio.run(); });
}
show_help = vm.contains("help");
show_sequence = vm.contains("listsequence");
}
-ceph::io_sequence::tester::TestRunner::~TestRunner()
-{
+ceph::io_sequence::tester::TestRunner::~TestRunner() {
if (!dryrun) {
guard = std::nullopt;
asio.stop();
@@ -552,34 +636,38 @@ ceph::io_sequence::tester::TestRunner::~TestRunner()
}
}
-void ceph::io_sequence::tester::TestRunner::help()
-{
+void ceph::io_sequence::tester::TestRunner::help() {
std::cout << get_options_description() << std::endl;
for (auto line : usage) {
std::cout << line << std::endl;
}
}
-void ceph::io_sequence::tester::TestRunner::list_sequence()
-{
+void ceph::io_sequence::tester::TestRunner::list_sequence(bool testrecovery) {
// List seqeunces
- std::pair<int,int> obj_size_range = sos.choose();
- for (ceph::io_exerciser::Sequence s
- = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN;
- s < ceph::io_exerciser::Sequence::SEQUENCE_END; ++s) {
- std::unique_ptr<ceph::io_exerciser::IoSequence> seq =
- ceph::io_exerciser::IoSequence::generate_sequence(s,
- obj_size_range,
- seqseed.value_or(rng()));
- dout(0) << s << " " << seq->get_name() << dendl;
+ std::pair<int, int> obj_size_range = sos.choose();
+ ceph::io_exerciser::Sequence s = ceph::io_exerciser::Sequence::SEQUENCE_BEGIN;
+ std::unique_ptr<ceph::io_exerciser::IoSequence> seq;
+ if (testrecovery) {
+ seq = ceph::io_exerciser::EcIoSequence::generate_sequence(
+ s, obj_size_range, spo.getChosenK(), spo.getChosenM(),
+ seqseed.value_or(rng()));
+ } else {
+ seq = ceph::io_exerciser::IoSequence::generate_sequence(
+ s, obj_size_range, seqseed.value_or(rng()));
}
+
+ do {
+ dout(0) << s << " " << seq->get_name_with_seqseed() << dendl;
+ s = seq->getNextSupportedSequenceId();
+ } while (s != ceph::io_exerciser::Sequence::SEQUENCE_END);
}
-std::string ceph::io_sequence::tester::TestRunner::get_token()
-{
- static std::string line;
- static ceph::split split = ceph::split("");
- static ceph::spliterator tokens;
+void ceph::io_sequence::tester::TestRunner::clear_tokens() {
+ tokens = split.end();
+}
+
+std::string ceph::io_sequence::tester::TestRunner::get_token() {
while (line.empty() || tokens == split.end()) {
if (!std::getline(std::cin, line)) {
throw std::runtime_error("End of input");
@@ -590,127 +678,211 @@ std::string ceph::io_sequence::tester::TestRunner::get_token()
return std::string(*tokens++);
}
-uint64_t ceph::io_sequence::tester::TestRunner::get_numeric_token()
-{
+std::optional<std::string>
+ceph::io_sequence::tester::TestRunner ::get_optional_token() {
+ std::optional<std::string> ret = std::nullopt;
+ if (tokens != split.end()) {
+ ret = std::string(*tokens++);
+ }
+ return ret;
+}
+
+uint64_t ceph::io_sequence::tester::TestRunner::get_numeric_token() {
std::string parse_error;
std::string token = get_token();
uint64_t num = strict_iecstrtoll(token, &parse_error);
if (!parse_error.empty()) {
- throw std::runtime_error("Invalid number "+token);
+ throw std::runtime_error("Invalid number " + token);
}
return num;
}
-bool ceph::io_sequence::tester::TestRunner::run_test()
-{
- if (show_help)
- {
+std::optional<uint64_t>
+ceph::io_sequence::tester::TestRunner ::get_optional_numeric_token() {
+ std::string parse_error;
+ std::optional<std::string> token = get_optional_token();
+ if (token) {
+ uint64_t num = strict_iecstrtoll(*token, &parse_error);
+ if (!parse_error.empty()) {
+ throw std::runtime_error("Invalid number " + *token);
+ }
+ return num;
+ }
+
+ return std::optional<uint64_t>(std::nullopt);
+}
+
+bool ceph::io_sequence::tester::TestRunner::run_test() {
+ if (show_help) {
help();
return true;
- }
- else if (show_sequence)
- {
- list_sequence();
+ } else if (show_sequence) {
+ list_sequence(testrecovery);
return true;
- }
- else if (interactive)
- {
+ } else if (interactive) {
return run_interactive_test();
- }
- else
- {
+ } else {
return run_automated_test();
}
}
-bool ceph::io_sequence::tester::TestRunner::run_interactive_test()
-{
+bool ceph::io_sequence::tester::TestRunner::run_interactive_test() {
bool done = false;
std::unique_ptr<ceph::io_exerciser::IoOp> ioop;
std::unique_ptr<ceph::io_exerciser::Model> model;
if (dryrun) {
- model = std::make_unique<ceph::io_exerciser::ObjectModel>(object_name,
- sbs.choose(),
- rng());
+ model = std::make_unique<ceph::io_exerciser::ObjectModel>(
+ object_name, sbs.choose(), rng());
} else {
const std::string pool = spo.choose();
- model = std::make_unique<ceph::io_exerciser::RadosIo>(rados, asio, pool,
- object_name, sbs.choose(),
- rng(), 1, // 1 thread
- lock, cond);
+
+ bufferlist inbl, outbl;
+ auto formatter = std::make_unique<JSONFormatter>(false);
+
+ ceph::messaging::osd::OSDMapRequest osdMapRequest{pool, object_name, ""};
+ int rc = send_mon_command(osdMapRequest, rados, "OSDMapRequest", inbl,
+ &outbl, formatter.get());
+ ceph_assert(rc == 0);
+
+ JSONParser p;
+ bool success = p.parse(outbl.c_str(), outbl.length());
+ ceph_assert(success);
+
+ ceph::messaging::osd::OSDMapReply reply{};
+ reply.decode_json(&p);
+
+ model = std::make_unique<ceph::io_exerciser::RadosIo>(
+ rados, asio, pool, object_name, reply.acting, sbs.choose(), rng(),
+ 1, // 1 thread
+ lock, cond);
}
while (!done) {
const std::string op = get_token();
- if (!op.compare("done") || !op.compare("q") || !op.compare("quit")) {
- ioop = ceph::io_exerciser::IoOp::generate_done();
- } else if (!op.compare("create")) {
- ioop = ceph::io_exerciser::IoOp::generate_create(get_numeric_token());
- } else if (!op.compare("remove") || !op.compare("delete")) {
- ioop = ceph::io_exerciser::IoOp::generate_remove();
- } else if (!op.compare("read")) {
+ if (op == "done" || op == "q" || op == "quit") {
+ ioop = ceph::io_exerciser::DoneOp::generate();
+ } else if (op == "create") {
+ ioop = ceph::io_exerciser::CreateOp::generate(get_numeric_token());
+ } else if (op == "remove" || op == "delete") {
+ ioop = ceph::io_exerciser::RemoveOp::generate();
+ } else if (op == "read") {
uint64_t offset = get_numeric_token();
uint64_t length = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_read(offset, length);
- } else if (!op.compare("read2")) {
+ ioop = ceph::io_exerciser::SingleReadOp::generate(offset, length);
+ } else if (op == "read2") {
uint64_t offset1 = get_numeric_token();
uint64_t length1 = get_numeric_token();
uint64_t offset2 = get_numeric_token();
uint64_t length2 = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_read2(offset1, length1,
- offset2, length2);
- } else if (!op.compare("read3")) {
+ ioop = DoubleReadOp::generate(offset1, length1, offset2, length2);
+ } else if (op == "read3") {
uint64_t offset1 = get_numeric_token();
uint64_t length1 = get_numeric_token();
uint64_t offset2 = get_numeric_token();
uint64_t length2 = get_numeric_token();
uint64_t offset3 = get_numeric_token();
uint64_t length3 = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_read3(offset1, length1,
- offset2, length2,
- offset3, length3);
- } else if (!op.compare("write")) {
+ ioop = TripleReadOp::generate(offset1, length1, offset2, length2, offset3,
+ length3);
+ } else if (op == "write") {
uint64_t offset = get_numeric_token();
uint64_t length = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_write(offset, length);
- } else if (!op.compare("write2")) {
+ ioop = SingleWriteOp::generate(offset, length);
+ } else if (op == "write2") {
uint64_t offset1 = get_numeric_token();
uint64_t length1 = get_numeric_token();
uint64_t offset2 = get_numeric_token();
uint64_t length2 = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_write2(offset1, length1,
- offset2, length2);
- } else if (!op.compare("write3")) {
+ ioop = DoubleWriteOp::generate(offset1, length1, offset2, length2);
+ } else if (op == "write3") {
uint64_t offset1 = get_numeric_token();
uint64_t length1 = get_numeric_token();
uint64_t offset2 = get_numeric_token();
uint64_t length2 = get_numeric_token();
uint64_t offset3 = get_numeric_token();
uint64_t length3 = get_numeric_token();
- ioop = ceph::io_exerciser::IoOp::generate_write3(offset1, length1,
- offset2, length2,
- offset3, length3);
+ ioop = TripleWriteOp::generate(offset1, length1, offset2, length2,
+ offset3, length3);
+ } else if (op == "failedwrite") {
+ uint64_t offset = get_numeric_token();
+ uint64_t length = get_numeric_token();
+ ioop = SingleFailedWriteOp::generate(offset, length);
+ } else if (op == "failedwrite2") {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ ioop = DoubleFailedWriteOp::generate(offset1, length1, offset2, length2);
+ } else if (op == "failedwrite3") {
+ uint64_t offset1 = get_numeric_token();
+ uint64_t length1 = get_numeric_token();
+ uint64_t offset2 = get_numeric_token();
+ uint64_t length2 = get_numeric_token();
+ uint64_t offset3 = get_numeric_token();
+ uint64_t length3 = get_numeric_token();
+ ioop = TripleFailedWriteOp::generate(offset1, length1, offset2, length2,
+ offset3, length3);
+ } else if (op == "injecterror") {
+ std::string inject_type = get_token();
+ int shard = get_numeric_token();
+ std::optional<int> type = get_optional_numeric_token();
+ std::optional<int> when = get_optional_numeric_token();
+ std::optional<int> duration = get_optional_numeric_token();
+ if (inject_type == "read") {
+ ioop = ceph::io_exerciser::InjectReadErrorOp::generate(shard, type,
+ when, duration);
+ } else if (inject_type == "write") {
+ ioop = ceph::io_exerciser::InjectWriteErrorOp::generate(shard, type,
+ when, duration);
+ } else {
+ clear_tokens();
+ ioop.reset();
+ dout(0) << fmt::format("Invalid error inject {}. No action performed.",
+ inject_type)
+ << dendl;
+ }
+ } else if (op == "clearinject") {
+ std::string inject_type = get_token();
+ int shard = get_numeric_token();
+ std::optional<int> type = get_optional_numeric_token();
+ if (inject_type == "read") {
+ ioop =
+ ceph::io_exerciser::ClearReadErrorInjectOp::generate(shard, type);
+ } else if (inject_type == "write") {
+ ioop =
+ ceph::io_exerciser::ClearWriteErrorInjectOp::generate(shard, type);
+ } else {
+ clear_tokens();
+ ioop.reset();
+ dout(0) << fmt::format("Invalid error inject {}. No action performed.",
+ inject_type)
+ << dendl;
+ }
} else {
- throw std::runtime_error("Invalid operation "+op);
+ clear_tokens();
+ ioop.reset();
+ dout(0) << fmt::format("Invalid op {}. No action performed.", op)
+ << dendl;
}
- dout(0) << ioop->to_string(model->get_block_size()) << dendl;
- model->applyIoOp(*ioop);
- done = ioop->done();
- if (!done) {
- ioop = ceph::io_exerciser::IoOp::generate_barrier();
+ if (ioop) {
+ dout(0) << ioop->to_string(model->get_block_size()) << dendl;
model->applyIoOp(*ioop);
+ done = ioop->getOpType() == ceph::io_exerciser::OpType::Done;
+ if (!done) {
+ ioop = ceph::io_exerciser::BarrierOp::generate();
+ model->applyIoOp(*ioop);
+ }
}
}
return true;
}
-bool ceph::io_sequence::tester::TestRunner::run_automated_test()
-{
+bool ceph::io_sequence::tester::TestRunner::run_automated_test() {
// Create a test for each object
- std::vector<std::shared_ptr<
- ceph::io_sequence::tester::TestObject>> test_objects;
+ std::vector<std::shared_ptr<ceph::io_sequence::tester::TestObject>>
+ test_objects;
for (int obj = 0; obj < num_objects; obj++) {
std::string name;
@@ -720,15 +892,9 @@ bool ceph::io_sequence::tester::TestRunner::run_automated_test()
name = object_name + std::to_string(obj);
}
test_objects.push_back(
- std::make_shared<ceph::io_sequence::tester::TestObject>(
- name,
- rados, asio,
- sbs, spo, sos, snt, ssr,
- rng, lock, cond,
- dryrun, verbose,
- seqseed
- )
- );
+ std::make_shared<ceph::io_sequence::tester::TestObject>(
+ name, rados, asio, sbs, spo, sos, snt, ssr, rng, lock, cond, dryrun,
+ verbose, seqseed, testrecovery));
}
if (!dryrun) {
rados.wait_for_latest_osdmap();
@@ -747,16 +913,15 @@ bool ceph::io_sequence::tester::TestRunner::run_automated_test()
for (auto obj = test_objects.begin(); obj != test_objects.end(); ++obj) {
std::shared_ptr<ceph::io_sequence::tester::TestObject> to = *obj;
if (!to->finished()) {
- lock.lock();
- bool ready = to->readyForIo();
- lock.unlock();
- if (ready)
- {
- to->next();
- started_io = true;
- } else {
- need_wait = true;
- }
+ lock.lock();
+ bool ready = to->readyForIo();
+ lock.unlock();
+ if (ready) {
+ to->next();
+ started_io = true;
+ } else {
+ need_wait = true;
+ }
}
}
if (!started_io && need_wait) {
@@ -766,8 +931,7 @@ bool ceph::io_sequence::tester::TestRunner::run_automated_test()
std::shared_ptr<ceph::io_sequence::tester::TestObject> to = *obj;
if (!to->finished()) {
need_wait = !to->readyForIo();
- if (!need_wait)
- {
+ if (!need_wait) {
break;
}
}
@@ -787,18 +951,16 @@ bool ceph::io_sequence::tester::TestRunner::run_automated_test()
return true;
}
-int main(int argc, char **argv)
-{
+int main(int argc, char** argv) {
auto args = argv_to_vec(argc, argv);
env_to_vec(args);
auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
- CODE_ENVIRONMENT_UTILITY, 0);
+ CODE_ENVIRONMENT_UTILITY, 0);
common_init_finish(cct.get());
po::variables_map vm;
int rc = parse_io_seq_options(vm, argc, argv);
- if (rc != 0)
- {
+ if (rc != 0) {
return rc;
}
@@ -813,7 +975,7 @@ int main(int argc, char **argv)
std::unique_ptr<ceph::io_sequence::tester::TestRunner> runner;
try {
runner = std::make_unique<ceph::io_sequence::tester::TestRunner>(vm, rados);
- } catch(const po::error& e) {
+ } catch (const po::error& e) {
return 1;
}
runner->run_test();
diff --git a/src/test/osd/ceph_test_rados_io_sequence.h b/src/test/osd/ceph_test_rados_io_sequence.h
index 4f77c940274..9af5f706b2f 100644
--- a/src/test/osd/ceph_test_rados_io_sequence.h
+++ b/src/test/osd/ceph_test_rados_io_sequence.h
@@ -1,33 +1,36 @@
+#include <boost/program_options.hpp>
+#include <optional>
#include <utility>
-#include "include/random.h"
-
-#include "global/global_init.h"
-#include "global/global_context.h"
-
#include "common/io_exerciser/IoOp.h"
#include "common/io_exerciser/IoSequence.h"
#include "common/io_exerciser/Model.h"
-
+#include "common/split.h"
+#include "global/global_context.h"
+#include "global/global_init.h"
+#include "include/random.h"
#include "librados/librados_asio.h"
+#include <boost/asio/io_context.hpp>
#include <boost/program_options.hpp>
+#include <optional>
+
/* Overview
*
* class ProgramOptionSelector
- * Base class for selector objects below with common code for
+ * Base class for selector objects below with common code for
* selecting options
- *
+ *
* class SelectObjectSize
* Selects min and max object sizes for a test
*
* class SelectErasureKM
* Selects an EC k and m value for a test
- *
+ *
* class SelectErasurePlugin
* Selects an plugin for a test
- *
+ *
* class SelectECPool
* Selects an EC pool (plugin,k and m) for a test. Also creates the
* pool as well.
@@ -57,287 +60,279 @@
namespace po = boost::program_options;
-namespace ceph
-{
- namespace io_sequence::tester
- {
- // Choices for min and max object size
- inline constexpr size_t objectSizeSize = 10;
- inline constexpr std::array<std::pair<int,int>,objectSizeSize>
- objectSizeChoices = {{
- {1,32}, // Default - best for boundary checking
- {12,14},
- {28,30},
- {36,38},
- {42,44},
- {52,54},
- {66,68},
- {72,74},
- {83,83},
- {97,97}
- }};
-
- // Choices for block size
- inline constexpr int blockSizeSize = 5;
- inline constexpr std::array<uint64_t, blockSizeSize> blockSizeChoices = {{
- 2048, // Default - test boundaries for EC 4K chunk size
- 512,
- 3767,
- 4096,
- 32768
- }};
-
- // Choices for number of threads
- inline constexpr int threadArraySize = 4;
- inline constexpr std::array<int, threadArraySize> threadCountChoices = {{
- 1, // Default
- 2,
- 4,
- 8
- }};
-
- // Choices for EC k+m profile
- inline constexpr int kmSize = 6;
- inline constexpr std::array<std::pair<int,int>, kmSize> kmChoices = {{
- {2,2}, // Default - reasonable coverage
- {2,1},
- {2,3},
- {3,2},
- {4,2},
- {5,1}
- }};
-
- // Choices for EC chunk size
- inline constexpr int chunkSizeSize = 3;
- inline constexpr std::array<uint64_t, chunkSizeSize> chunkSizeChoices = {{
- 4*1024,
- 64*1024,
- 256*1024
- }};
-
- // Choices for plugin
- inline constexpr int pluginListSize = 2;
- inline constexpr std::array<std::string_view,
- pluginListSize> pluginChoices = {{
- "jerasure",
- "isa"
- }};
-
- inline constexpr std::array<std::pair<ceph::io_exerciser::Sequence,
- ceph::io_exerciser::Sequence>,
- 0> sequencePairs = {{}};
-
- inline constexpr std::array<std::string, 0> poolChoices = {{}};
-
- template <typename T, int N, const std::array<T, N>& Ts>
- class ProgramOptionSelector
- {
- public:
- ProgramOptionSelector(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm,
- const std::string& option_name,
- bool set_forced,
- bool select_first
- );
- virtual ~ProgramOptionSelector() = default;
- bool isForced();
- virtual const T choose();
-
- protected:
- ceph::util::random_number_generator<int>& rng;
- static constexpr std::array<T, N> choices = Ts;
-
- std::optional<T> force_value;
- std::optional<T> first_value;
-
- std::string option_name;
- };
-
- class SelectObjectSize
- : public ProgramOptionSelector<std::pair<int, int>,
- io_sequence::tester::objectSizeSize,
- io_sequence::tester::objectSizeChoices>
- {
- public:
- SelectObjectSize(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm);
- };
-
- class SelectBlockSize
- : public ProgramOptionSelector<uint64_t,
- io_sequence::tester::blockSizeSize,
- io_sequence::tester::blockSizeChoices>
- {
- public:
- SelectBlockSize(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm);
- };
-
- class SelectNumThreads
- : public ProgramOptionSelector<int,
- io_sequence::tester::threadArraySize,
- io_sequence::tester::threadCountChoices>
- {
- public:
- SelectNumThreads(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm);
- };
-
- class SelectSeqRange
- : public ProgramOptionSelector<std::pair<ceph::io_exerciser::Sequence,
- ceph::io_exerciser::Sequence>,
- 0, io_sequence::tester::sequencePairs>
- {
- public:
- SelectSeqRange(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm);
-
- const std::pair<ceph::io_exerciser::Sequence,
- ceph::io_exerciser::Sequence> choose() override;
- };
-
- class SelectErasureKM
- : public ProgramOptionSelector<std::pair<int,int>,
- io_sequence::tester::kmSize,
- io_sequence::tester::kmChoices>
- {
- public:
- SelectErasureKM(ceph::util::random_number_generator<int>& rng,
+namespace ceph {
+namespace io_sequence::tester {
+// Choices for min and max object size
+inline constexpr size_t objectSizeSize = 10;
+inline constexpr std::array<std::pair<int, int>, objectSizeSize>
+ objectSizeChoices = {{{1, 32}, // Default - best for boundary checking
+ {12, 14},
+ {28, 30},
+ {36, 38},
+ {42, 44},
+ {52, 54},
+ {66, 68},
+ {72, 74},
+ {83, 83},
+ {97, 97}}};
+
+// Choices for block size
+inline constexpr int blockSizeSize = 5;
+inline constexpr std::array<uint64_t, blockSizeSize> blockSizeChoices = {
+ {2048, // Default - test boundaries for EC 4K chunk size
+ 512, 3767, 4096, 32768}};
+
+// Choices for number of threads
+inline constexpr int threadArraySize = 4;
+inline constexpr std::array<int, threadArraySize> threadCountChoices = {
+ {1, // Default
+ 2, 4, 8}};
+
+// Choices for EC k+m profile
+inline constexpr int kmSize = 6;
+inline constexpr std::array<std::pair<int, int>, kmSize> kmChoices = {
+ {{2, 2}, // Default - reasonable coverage
+ {2, 1},
+ {2, 3},
+ {3, 2},
+ {4, 2},
+ {5, 1}}};
+
+// Choices for EC chunk size
+inline constexpr int chunkSizeSize = 3;
+inline constexpr std::array<uint64_t, chunkSizeSize> chunkSizeChoices = {
+ {4 * 1024, 64 * 1024, 256 * 1024}};
+
+// Choices for plugin
+inline constexpr int pluginListSize = 2;
+inline constexpr std::array<std::string_view, pluginListSize> pluginChoices = {
+ {"jerasure", "isa"}};
+
+inline constexpr std::array<
+ std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>, 0>
+ sequencePairs = {{}};
+
+inline constexpr std::array<std::string, 0> poolChoices = {{}};
+
+template <typename T, int N, const std::array<T, N>& Ts>
+class ProgramOptionSelector {
+ public:
+ ProgramOptionSelector(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm, const std::string& option_name,
+ bool set_forced, bool select_first);
+ virtual ~ProgramOptionSelector() = default;
+ bool isForced();
+ virtual const T choose();
+
+ protected:
+ ceph::util::random_number_generator<int>& rng;
+ static constexpr std::array<T, N> choices = Ts;
+
+ std::optional<T> force_value;
+ std::optional<T> first_value;
+
+ std::string option_name;
+};
+
+class SelectObjectSize
+ : public ProgramOptionSelector<std::pair<int, int>,
+ io_sequence::tester::objectSizeSize,
+ io_sequence::tester::objectSizeChoices> {
+ public:
+ SelectObjectSize(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+};
+
+class SelectBlockSize
+ : public ProgramOptionSelector<uint64_t, io_sequence::tester::blockSizeSize,
+ io_sequence::tester::blockSizeChoices> {
+ public:
+ SelectBlockSize(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+};
+
+class SelectNumThreads
+ : public ProgramOptionSelector<int, io_sequence::tester::threadArraySize,
+ io_sequence::tester::threadCountChoices> {
+ public:
+ SelectNumThreads(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+};
+
+class SelectSeqRange
+ : public ProgramOptionSelector<
+ std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>,
+ 0, io_sequence::tester::sequencePairs> {
+ public:
+ SelectSeqRange(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+
+ const std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>
+ choose() override;
+};
+
+class SelectErasureKM
+ : public ProgramOptionSelector<std::pair<int, int>,
+ io_sequence::tester::kmSize,
+ io_sequence::tester::kmChoices> {
+ public:
+ SelectErasureKM(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+};
+
+class SelectErasurePlugin
+ : public ProgramOptionSelector<std::string_view,
+ io_sequence::tester::pluginListSize,
+ io_sequence::tester::pluginChoices> {
+ public:
+ SelectErasurePlugin(ceph::util::random_number_generator<int>& rng,
po::variables_map vm);
- };
-
- class SelectErasurePlugin
- : public ProgramOptionSelector<std::string_view,
- io_sequence::tester::pluginListSize,
- io_sequence::tester::pluginChoices>
- {
- public:
- SelectErasurePlugin(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm);
- };
-
- class SelectErasureChunkSize
- : public ProgramOptionSelector<uint64_t,
- io_sequence::tester::chunkSizeSize,
- io_sequence::tester::chunkSizeChoices>
- {
- public:
- SelectErasureChunkSize(ceph::util::random_number_generator<int>& rng, po::variables_map vm);
- };
-
- class SelectECPool
- : public ProgramOptionSelector<std::string,
- 0,
- io_sequence::tester::poolChoices>
- {
- public:
- SelectECPool(ceph::util::random_number_generator<int>& rng,
- po::variables_map vm,
- librados::Rados& rados,
- bool dry_run);
- const std::string choose() override;
-
- private:
- void create_pool(librados::Rados& rados,
- const std::string& pool_name,
- const std::string& plugin,
- uint64_t chunk_size,
- int k, int m);
-
- protected:
- librados::Rados& rados;
- bool dry_run;
-
- SelectErasureKM skm;
- SelectErasurePlugin spl;
- SelectErasureChunkSize scs;
- };
-
- class TestObject
- {
- public:
- TestObject( const std::string oid,
- librados::Rados& rados,
- boost::asio::io_context& asio,
- ceph::io_sequence::tester::SelectBlockSize& sbs,
- ceph::io_sequence::tester::SelectECPool& spl,
- ceph::io_sequence::tester::SelectObjectSize& sos,
- ceph::io_sequence::tester::SelectNumThreads& snt,
- ceph::io_sequence::tester::SelectSeqRange& ssr,
- ceph::util::random_number_generator<int>& rng,
- ceph::mutex& lock,
- ceph::condition_variable& cond,
- bool dryrun,
- bool verbose,
- std::optional<int> seqseed);
-
- int get_num_io();
- bool readyForIo();
- bool next();
- bool finished();
-
- protected:
- std::unique_ptr<ceph::io_exerciser::Model> exerciser_model;
- std::pair<int,int> obj_size_range;
- std::pair<ceph::io_exerciser::Sequence,
- ceph::io_exerciser::Sequence> seq_range;
- ceph::io_exerciser::Sequence curseq;
- std::unique_ptr<ceph::io_exerciser::IoSequence> seq;
- std::unique_ptr<ceph::io_exerciser::IoOp> op;
- bool done;
- ceph::util::random_number_generator<int>& rng;
- bool verbose;
- std::optional<int> seqseed;
- };
-
- class TestRunner
- {
- public:
- TestRunner(po::variables_map& vm, librados::Rados& rados);
- ~TestRunner();
-
- bool run_test();
-
- private:
- librados::Rados& rados;
- int seed;
- ceph::util::random_number_generator<int> rng;
-
- ceph::io_sequence::tester::SelectBlockSize sbs;
- ceph::io_sequence::tester::SelectObjectSize sos;
- ceph::io_sequence::tester::SelectECPool spo;
- ceph::io_sequence::tester::SelectNumThreads snt;
- ceph::io_sequence::tester::SelectSeqRange ssr;
-
- boost::asio::io_context asio;
- std::thread thread;
- std::optional<boost::asio::executor_work_guard<
- boost::asio::io_context::executor_type>> guard;
- ceph::mutex lock = ceph::make_mutex("RadosIo::lock");
- ceph::condition_variable cond;
-
- bool input_valid;
-
- bool verbose;
- bool dryrun;
- std::optional<int> seqseed;
- bool interactive;
-
- bool show_sequence;
- bool show_help;
-
- int num_objects;
- std::string object_name;
-
- std::string get_token();
- uint64_t get_numeric_token();
-
- bool run_automated_test();
-
- bool run_interactive_test();
-
- void help();
- void list_sequence();
- };
- }
-} \ No newline at end of file
+};
+
+class SelectErasureChunkSize
+ : public ProgramOptionSelector<uint64_t, io_sequence::tester::chunkSizeSize,
+ io_sequence::tester::chunkSizeChoices> {
+ public:
+ SelectErasureChunkSize(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm);
+};
+
+class SelectECPool
+ : public ProgramOptionSelector<std::string, 0,
+ io_sequence::tester::poolChoices> {
+ public:
+ SelectECPool(ceph::util::random_number_generator<int>& rng,
+ po::variables_map vm, librados::Rados& rados, bool dry_run,
+ bool allow_pool_autoscaling, bool allow_pool_balancer,
+ bool allow_pool_deep_scrubbing, bool allow_pool_scrubbing,
+ bool test_recovery);
+ const std::string choose() override;
+
+ bool get_allow_pool_autoscaling() { return allow_pool_autoscaling; }
+ bool get_allow_pool_balancer() { return allow_pool_balancer; }
+ bool get_allow_pool_deep_scrubbing() { return allow_pool_deep_scrubbing; }
+ bool get_allow_pool_scrubbing() { return allow_pool_scrubbing; }
+ int getChosenK() const { return k; }
+ int getChosenM() const { return m; }
+
+ private:
+ void create_pool(librados::Rados& rados, const std::string& pool_name,
+ const std::string& plugin, uint64_t chunk_size, int k,
+ int m);
+
+ protected:
+ librados::Rados& rados;
+ bool dry_run;
+ bool allow_pool_autoscaling;
+ bool allow_pool_balancer;
+ bool allow_pool_deep_scrubbing;
+ bool allow_pool_scrubbing;
+ bool test_recovery;
+ int k;
+ int m;
+
+ SelectErasureKM skm;
+ SelectErasurePlugin spl;
+ SelectErasureChunkSize scs;
+};
+
+class TestObject {
+ public:
+ TestObject(const std::string oid, librados::Rados& rados,
+ boost::asio::io_context& asio,
+ ceph::io_sequence::tester::SelectBlockSize& sbs,
+ ceph::io_sequence::tester::SelectECPool& spl,
+ ceph::io_sequence::tester::SelectObjectSize& sos,
+ ceph::io_sequence::tester::SelectNumThreads& snt,
+ ceph::io_sequence::tester::SelectSeqRange& ssr,
+ ceph::util::random_number_generator<int>& rng, ceph::mutex& lock,
+ ceph::condition_variable& cond, bool dryrun, bool verbose,
+ std::optional<int> seqseed, bool testRecovery);
+
+ int get_num_io();
+ bool readyForIo();
+ bool next();
+ bool finished();
+
+ protected:
+ std::unique_ptr<ceph::io_exerciser::Model> exerciser_model;
+ std::pair<int, int> obj_size_range;
+ std::pair<ceph::io_exerciser::Sequence, ceph::io_exerciser::Sequence>
+ seq_range;
+ ceph::io_exerciser::Sequence curseq;
+ std::unique_ptr<ceph::io_exerciser::IoSequence> seq;
+ std::unique_ptr<ceph::io_exerciser::IoOp> op;
+ bool done;
+ ceph::util::random_number_generator<int>& rng;
+ bool verbose;
+ std::optional<int> seqseed;
+ int poolK;
+ int poolM;
+ bool testrecovery;
+};
+
+class TestRunner {
+ public:
+ TestRunner(po::variables_map& vm, librados::Rados& rados);
+ ~TestRunner();
+
+ bool run_test();
+
+ private:
+ librados::Rados& rados;
+ int seed;
+ ceph::util::random_number_generator<int> rng;
+
+ ceph::io_sequence::tester::SelectBlockSize sbs;
+ ceph::io_sequence::tester::SelectObjectSize sos;
+ ceph::io_sequence::tester::SelectECPool spo;
+ ceph::io_sequence::tester::SelectNumThreads snt;
+ ceph::io_sequence::tester::SelectSeqRange ssr;
+
+ boost::asio::io_context asio;
+ std::thread thread;
+ std::optional<
+ boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>
+ guard;
+ ceph::mutex lock = ceph::make_mutex("RadosIo::lock");
+ ceph::condition_variable cond;
+
+ bool input_valid;
+
+ bool verbose;
+ bool dryrun;
+ std::optional<int> seqseed;
+ bool interactive;
+
+ bool testrecovery;
+
+ bool allow_pool_autoscaling;
+ bool allow_pool_balancer;
+ bool allow_pool_deep_scrubbing;
+ bool allow_pool_scrubbing;
+
+ bool show_sequence;
+ bool show_help;
+
+ int num_objects;
+ std::string object_name;
+
+ std::string line;
+ ceph::split split = ceph::split("");
+ ceph::spliterator tokens;
+
+ void clear_tokens();
+ std::string get_token();
+ std::optional<std::string> get_optional_token();
+ uint64_t get_numeric_token();
+ std::optional<uint64_t> get_optional_numeric_token();
+
+ bool run_automated_test();
+
+ bool run_interactive_test();
+
+ void help();
+ void list_sequence(bool testrecovery);
+};
+} // namespace io_sequence::tester
+} // namespace ceph
diff --git a/src/test/osd/test_ec_transaction.cc b/src/test/osd/test_ec_transaction.cc
index c17df4802ed..64397ce88bf 100644
--- a/src/test/osd/test_ec_transaction.cc
+++ b/src/test/osd/test_ec_transaction.cc
@@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include "osd/PGTransaction.h"
#include "osd/ECTransaction.h"
+#include "common/debug.h"
#include "test/unit.cc"
diff --git a/src/test/osd/types.cc b/src/test/osd/types.cc
index 2dc870411bb..062980d8655 100644
--- a/src/test/osd/types.cc
+++ b/src/test/osd/types.cc
@@ -23,6 +23,8 @@
#include "common/Thread.h"
#include "include/stringify.h"
#include "osd/ReplicatedBackend.h"
+
+#include <iostream> // for std::cout
#include <sstream>
using namespace std;
diff --git a/src/test/osdc/MemWriteback.cc b/src/test/osdc/MemWriteback.cc
index 4cb11291a98..bcc828e064b 100644
--- a/src/test/osdc/MemWriteback.cc
+++ b/src/test/osdc/MemWriteback.cc
@@ -1,6 +1,8 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include "MemWriteback.h"
+
#include <errno.h>
#include <time.h>
@@ -11,8 +13,7 @@
#include "common/ceph_mutex.h"
#include "include/ceph_assert.h"
#include "common/ceph_time.h"
-
-#include "MemWriteback.h"
+#include "common/snap_types.h" // for class SnapContext
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_objectcacher
diff --git a/src/test/osdc/object_cacher_stress.cc b/src/test/osdc/object_cacher_stress.cc
index 0bfdd48eb98..b32c5660112 100644
--- a/src/test/osdc/object_cacher_stress.cc
+++ b/src/test/osdc/object_cacher_stress.cc
@@ -23,6 +23,7 @@
#include "MemWriteback.h"
#include <atomic>
+#include <iostream> // for std::cout
using namespace std;
diff --git a/src/test/perf_counters.cc b/src/test/perf_counters.cc
index 7ab9561bc19..b75e6a50825 100644
--- a/src/test/perf_counters.cc
+++ b/src/test/perf_counters.cc
@@ -15,7 +15,7 @@
#include "include/types.h" // FIXME: ordering shouldn't be important, but right
// now, this include has to come before the others.
-
+#include "include/utime.h"
#include "common/perf_counters_key.h"
#include "common/perf_counters_collection.h"
#include "common/admin_socket_client.h"
diff --git a/src/test/pybind/pytest.ini b/src/test/pybind/pytest.ini
index dccf2a346dc..97569e88299 100644
--- a/src/test/pybind/pytest.ini
+++ b/src/test/pybind/pytest.ini
@@ -7,3 +7,4 @@ markers =
stats
tier
watch
+ wait
diff --git a/src/test/pybind/test_ceph_argparse.py b/src/test/pybind/test_ceph_argparse.py
index 3039223abdf..630e6046b24 100755
--- a/src/test/pybind/test_ceph_argparse.py
+++ b/src/test/pybind/test_ceph_argparse.py
@@ -217,7 +217,7 @@ class TestPG(TestArgparse):
def test_pg_missing_args_output(self):
ret, _, stderr = self._capture_output(['pg'], stderr=True)
self.assertEqual({}, ret)
- self.assertRegexpMatches(stderr, re.compile('no valid command found.* closest matches'))
+ self.assertRegex(stderr, re.compile('no valid command found.* closest matches'))
def test_pg_wrong_arg_output(self):
ret, _, stderr = self._capture_output(['pg', 'map', 'bad-pgid'],
@@ -416,10 +416,10 @@ class TestMDS(TestArgparse):
class TestFS(TestArgparse):
-
+
def test_dump(self):
self.check_0_or_1_natural_arg('fs', 'dump')
-
+
def test_fs_new(self):
self._assert_valid_command(['fs', 'new', 'default', 'metadata', 'data'])
@@ -912,7 +912,7 @@ class TestOSD(TestArgparse):
'1.2.3.4/567', '600.40'])
self._assert_valid_command(['osd', 'blocklist', action,
'1.2.3.4', '600.40'])
-
+
self._assert_valid_command(['osd', 'blocklist', action,
'v1:1.2.3.4', '600.40'])
self._assert_valid_command(['osd', 'blocklist', action,
@@ -925,7 +925,7 @@ class TestOSD(TestArgparse):
'v2:[2607:f298:4:2243::5522]:0/0', '600.40'])
self._assert_valid_command(['osd', 'blocklist', action,
'[2001:0db8::85a3:0000:8a2e:0370:7334]:0/0', '600.40'])
-
+
self.assertEqual({}, validate_command(sigdict, ['osd', 'blocklist',
action,
'invalid',
diff --git a/src/test/pybind/test_rados.py b/src/test/pybind/test_rados.py
index 0288527c4f9..881b29c9152 100644
--- a/src/test/pybind/test_rados.py
+++ b/src/test/pybind/test_rados.py
@@ -207,7 +207,7 @@ class TestRados(object):
def test_get_fsid(self):
fsid = self.rados.get_fsid()
- assert re.match('[0-9a-f\-]{36}', fsid, re.I)
+ assert re.match(r'[0-9a-f\-]{36}', fsid, re.I)
def test_blocklist_add(self):
self.rados.blocklist_add("1.2.3.4/123", 1)
diff --git a/src/test/rbd_mirror/test_ImageReplayer.cc b/src/test/rbd_mirror/test_ImageReplayer.cc
index abe163cfd69..360c85a76b6 100644
--- a/src/test/rbd_mirror/test_ImageReplayer.cc
+++ b/src/test/rbd_mirror/test_ImageReplayer.cc
@@ -47,6 +47,8 @@
#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
+#include <shared_mutex> // for std::shared_lock
+
void register_test_rbd_mirror() {
}
diff --git a/src/test/rbd_mirror/test_ImageSync.cc b/src/test/rbd_mirror/test_ImageSync.cc
index 93349ca1163..9418496bce2 100644
--- a/src/test/rbd_mirror/test_ImageSync.cc
+++ b/src/test/rbd_mirror/test_ImageSync.cc
@@ -24,6 +24,8 @@
#include "tools/rbd_mirror/Throttler.h"
#include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
+#include <shared_mutex> // for std::shared_lock
+
void register_test_image_sync() {
}
diff --git a/src/test/rgw/bucket_notification/api.py b/src/test/rgw/bucket_notification/api.py
index e7ec31f1711..e84aa16edc7 100644
--- a/src/test/rgw/bucket_notification/api.py
+++ b/src/test/rgw/bucket_notification/api.py
@@ -247,12 +247,16 @@ def delete_all_topics(conn, tenant, cluster):
if tenant == '':
topics_result = admin(['topic', 'list'], cluster)
topics_json = json.loads(topics_result[0])
+ if 'topics' not in topics_json:
+ topics_json = topics_json.get('result',{})
for topic in topics_json['topics']:
rm_result = admin(['topic', 'rm', '--topic', topic['name']], cluster)
print(rm_result)
else:
topics_result = admin(['topic', 'list', '--tenant', tenant], cluster)
topics_json = json.loads(topics_result[0])
+ if 'topics' not in topics_json:
+ topics_json = topics_json.get('result',{})
for topic in topics_json['topics']:
rm_result = admin(['topic', 'rm', '--tenant', tenant, '--topic', topic['name']], cluster)
print(rm_result)
diff --git a/src/test/rgw/bucket_notification/requirements.txt b/src/test/rgw/bucket_notification/requirements.txt
index a3cff2bedab..bb74eceedc3 100644
--- a/src/test/rgw/bucket_notification/requirements.txt
+++ b/src/test/rgw/bucket_notification/requirements.txt
@@ -1,4 +1,4 @@
-nose >=1.0.0
+nose-py3 >=1.0.0
boto >=2.6.0
boto3 >=1.0.0
configparser >=5.0.0
diff --git a/src/test/rgw/bucket_notification/test_bn.py b/src/test/rgw/bucket_notification/test_bn.py
index 359990b3531..665fbca7494 100644
--- a/src/test/rgw/bucket_notification/test_bn.py
+++ b/src/test/rgw/bucket_notification/test_bn.py
@@ -410,17 +410,25 @@ kafka_server = 'localhost'
class KafkaReceiver(object):
"""class for receiving and storing messages on a topic from the kafka broker"""
- def __init__(self, topic, security_type):
+ def __init__(self, topic, security_type, kafka_server='localhost'):
from kafka import KafkaConsumer
remaining_retries = 10
port = 9092
if security_type != 'PLAINTEXT':
security_type = 'SSL'
port = 9093
+
+ if kafka_server is None:
+ endpoint = "localhost" + ":" + str(port)
+ elif ":" not in kafka_server:
+ endpoint = kafka_server + ":" + str(port)
+ else:
+ endpoint = kafka_server
+
while remaining_retries > 0:
try:
self.consumer = KafkaConsumer(topic,
- bootstrap_servers = kafka_server+':'+str(port),
+ bootstrap_servers=endpoint,
security_protocol=security_type,
consumer_timeout_ms=16000,
auto_offset_reset='earliest')
@@ -468,9 +476,9 @@ def kafka_receiver_thread_runner(receiver):
print('Kafka receiver ended unexpectedly: ' + str(error))
-def create_kafka_receiver_thread(topic, security_type='PLAINTEXT'):
+def create_kafka_receiver_thread(topic, security_type='PLAINTEXT', kafka_brokers=None):
"""create kafka receiver and thread"""
- receiver = KafkaReceiver(topic, security_type)
+ receiver = KafkaReceiver(topic, security_type, kafka_server=kafka_brokers)
task = threading.Thread(target=kafka_receiver_thread_runner, args=(receiver,))
task.daemon = True
return task, receiver
@@ -1304,7 +1312,7 @@ def test_ps_s3_notification_errors_on_master():
conn.delete_bucket(bucket_name)
-def notification_push(endpoint_type, conn, account=None, cloudevents=False):
+def notification_push(endpoint_type, conn, account=None, cloudevents=False, kafka_brokers=None):
""" test pushinging notification """
zonegroup = get_config_zonegroup()
# create bucket
@@ -1359,11 +1367,13 @@ def notification_push(endpoint_type, conn, account=None, cloudevents=False):
assert_equal(status/100, 2)
elif endpoint_type == 'kafka':
# start amqp receiver
- task, receiver = create_kafka_receiver_thread(topic_name)
+ task, receiver = create_kafka_receiver_thread(topic_name, kafka_brokers=kafka_brokers)
task.start()
endpoint_address = 'kafka://' + kafka_server
# without acks from broker
endpoint_args = 'push-endpoint='+endpoint_address+'&kafka-ack-level=broker'
+ if kafka_brokers is not None:
+ endpoint_args += '&kafka-brokers=' + kafka_brokers
# create s3 topic
topic_conf = PSTopicS3(conn, topic_name, zonegroup, endpoint_args=endpoint_args)
topic_arn = topic_conf.set_config()
@@ -1581,6 +1591,20 @@ def test_notification_push_kafka():
notification_push('kafka', conn)
+@attr('kafka_failover')
+def test_notification_push_kafka_multiple_brokers_override():
+ """ test pushing kafka s3 notification on master """
+ conn = connection()
+ notification_push('kafka', conn, kafka_brokers='localhost:9092,localhost:19092')
+
+
+@attr('kafka_failover')
+def test_notification_push_kafka_multiple_brokers_append():
+ """ test pushing kafka s3 notification on master """
+ conn = connection()
+ notification_push('kafka', conn, kafka_brokers='localhost:19092')
+
+
@attr('http_test')
def test_ps_s3_notification_multi_delete_on_master():
""" test deletion of multiple keys on master """
@@ -2981,7 +3005,6 @@ def wait_for_queue_to_drain(topic_name, tenant=None, account=None, http_port=Non
log.info('waited for %ds for queue %s to drain', time_diff, topic_name)
-@attr('kafka_test')
def persistent_topic_stats(conn, endpoint_type):
zonegroup = get_config_zonegroup()
@@ -2993,12 +3016,13 @@ def persistent_topic_stats(conn, endpoint_type):
host = get_ip()
task = None
port = None
+ wrong_port = 1234
+ endpoint_address = endpoint_type+'://'+host+':'+str(wrong_port)
if endpoint_type == 'http':
# create random port for the http server
port = random.randint(10000, 20000)
# start an http server in a separate thread
receiver = HTTPServerWithEvents((host, port))
- endpoint_address = 'http://'+host+':'+str(port)
endpoint_args = 'push-endpoint='+endpoint_address+'&persistent=true'+ \
'&retry_sleep_duration=1'
elif endpoint_type == 'amqp':
@@ -3006,23 +3030,18 @@ def persistent_topic_stats(conn, endpoint_type):
exchange = 'ex1'
task, receiver = create_amqp_receiver_thread(exchange, topic_name)
task.start()
- endpoint_address = 'amqp://' + host
endpoint_args = 'push-endpoint='+endpoint_address+'&amqp-exchange='+exchange+'&amqp-ack-level=broker&persistent=true'+ \
'&retry_sleep_duration=1'
elif endpoint_type == 'kafka':
# start kafka receiver
task, receiver = create_kafka_receiver_thread(topic_name)
task.start()
- endpoint_address = 'kafka://' + host
endpoint_args = 'push-endpoint='+endpoint_address+'&kafka-ack-level=broker&persistent=true'+ \
'&retry_sleep_duration=1'
else:
return SkipTest('Unknown endpoint type: ' + endpoint_type)
# create s3 topic
- endpoint_address = 'kafka://' + host + ':1234' # wrong port
- endpoint_args = 'push-endpoint='+endpoint_address+'&kafka-ack-level=broker&persistent=true'+ \
- '&retry_sleep_duration=1'
topic_conf = PSTopicS3(conn, topic_name, zonegroup, endpoint_args=endpoint_args)
topic_arn = topic_conf.set_config()
# create s3 notification
@@ -3070,9 +3089,19 @@ def persistent_topic_stats(conn, endpoint_type):
get_stats_persistent_topic(topic_name, 2 * number_of_objects)
# change the endpoint port
- endpoint_address = 'kafka://' + host
- endpoint_args = 'push-endpoint='+endpoint_address+'&kafka-ack-level=broker&persistent=true'+ \
- '&retry_sleep_duration=1'
+ if endpoint_type == 'http':
+ endpoint_address = endpoint_type+'://'+host+':'+str(port)
+ endpoint_args = 'push-endpoint='+endpoint_address+'&persistent=true'+ \
+ '&retry_sleep_duration=1'
+ elif endpoint_type == 'amqp':
+ endpoint_address = endpoint_type+'://'+host
+ endpoint_args = 'push-endpoint='+endpoint_address+'&amqp-exchange='+exchange+'&amqp-ack-level=broker&persistent=true'+ \
+ '&retry_sleep_duration=1'
+ elif endpoint_type == 'kafka':
+ endpoint_address = endpoint_type+'://'+host
+ endpoint_args = 'push-endpoint='+endpoint_address+'&kafka-ack-level=broker&persistent=true'+ \
+ '&retry_sleep_duration=1'
+
topic_conf = PSTopicS3(conn, topic_name, zonegroup, endpoint_args=endpoint_args)
topic_arn = topic_conf.set_config()
@@ -3087,19 +3116,26 @@ def persistent_topic_stats(conn, endpoint_type):
@attr('http_test')
-def persistent_topic_stats_http():
+def test_persistent_topic_stats_http():
""" test persistent topic stats, http endpoint """
conn = connection()
persistent_topic_stats(conn, 'http')
@attr('kafka_test')
-def persistent_topic_stats_kafka():
+def test_persistent_topic_stats_kafka():
""" test persistent topic stats, kafka endpoint """
conn = connection()
persistent_topic_stats(conn, 'kafka')
+@attr('amqp_test')
+def test_persistent_topic_stats_amqp():
+ """ test persistent topic stats, amqp endpoint """
+ conn = connection()
+ persistent_topic_stats(conn, 'amqp')
+
+
@attr('kafka_test')
def test_persistent_topic_dump():
""" test persistent topic dump """
@@ -4359,6 +4395,242 @@ def test_ps_s3_multiple_topics_notification():
http_server.close()
+@attr('data_path_v2_test')
+def test_ps_s3_list_topics_migration():
+ """ test list topics on migration"""
+ if get_config_cluster() == 'noname':
+ return SkipTest('realm is needed for migration test')
+
+ # Initialize connections and configurations
+ conn1 = connection()
+ tenant = 'kaboom1'
+ conn2 = connect_random_user(tenant)
+ bucket_name = gen_bucket_name()
+ topics = [f"{bucket_name}{TOPIC_SUFFIX}{i}" for i in range(1, 7)]
+ tenant_topics = [f"{tenant}_{topic}" for topic in topics]
+
+ # Define topic names with version
+ topic_versions = {
+ "topic1_v2": f"{topics[0]}_v2",
+ "topic2_v2": f"{topics[1]}_v2",
+ "topic3_v1": f"{topics[2]}_v1",
+ "topic4_v1": f"{topics[3]}_v1",
+ "topic5_v1": f"{topics[4]}_v1",
+ "topic6_v1": f"{topics[5]}_v1",
+ "tenant_topic1_v2": f"{tenant_topics[0]}_v2",
+ "tenant_topic2_v1": f"{tenant_topics[1]}_v1",
+ "tenant_topic3_v1": f"{tenant_topics[2]}_v1"
+ }
+
+ # Get necessary configurations
+ host = get_ip()
+ http_port = random.randint(10000, 20000)
+ endpoint_address = 'http://' + host + ':' + str(http_port)
+ endpoint_args = 'push-endpoint=' + endpoint_address + '&persistent=true'
+ zonegroup = get_config_zonegroup()
+ conf_cluster = get_config_cluster()
+
+ # Make sure there are no leftover topics on v2
+ zonegroup_modify_feature(enable=True, feature_name=zonegroup_feature_notification_v2)
+ delete_all_topics(conn1, '', conf_cluster)
+ delete_all_topics(conn2, tenant, conf_cluster)
+
+ # Start v1 notification
+ # Make sure there are no leftover topics on v1
+ zonegroup_modify_feature(enable=False, feature_name=zonegroup_feature_notification_v2)
+ delete_all_topics(conn1, '', conf_cluster)
+ delete_all_topics(conn2, tenant, conf_cluster)
+
+ # Create s3 - v1 topics
+ topic_conf = PSTopicS3(conn1, topic_versions['topic3_v1'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn3 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_versions['topic4_v1'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn4 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_versions['topic5_v1'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn5 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_versions['topic6_v1'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn6 = topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, topic_versions['tenant_topic2_v1'], zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn2 = tenant_topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, topic_versions['tenant_topic3_v1'], zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn3 = tenant_topic_conf.set_config()
+
+ # Start v2 notification
+ zonegroup_modify_feature(enable=True, feature_name=zonegroup_feature_notification_v2)
+
+ # Create s3 - v2 topics
+ topic_conf = PSTopicS3(conn1, topic_versions['topic1_v2'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn1 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_versions['topic2_v2'], zonegroup, endpoint_args=endpoint_args)
+ topic_arn2 = topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, topic_versions['tenant_topic1_v2'], zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn1 = tenant_topic_conf.set_config()
+
+ # Verify topics list
+ try:
+ # Verify no tenant topics
+ res, status = topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else []
+ assert_equal(len(member), 6)
+
+ # Verify tenant topics
+ res, status = tenant_topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else []
+ assert_equal(len(member), 3)
+ finally:
+ # Cleanup created topics
+ topic_conf.del_config(topic_arn1)
+ topic_conf.del_config(topic_arn2)
+ topic_conf.del_config(topic_arn3)
+ topic_conf.del_config(topic_arn4)
+ topic_conf.del_config(topic_arn5)
+ topic_conf.del_config(topic_arn6)
+ tenant_topic_conf.del_config(tenant_topic_arn1)
+ tenant_topic_conf.del_config(tenant_topic_arn2)
+ tenant_topic_conf.del_config(tenant_topic_arn3)
+
+
+@attr('basic_test')
+def test_ps_s3_list_topics():
+ """ test list topics"""
+
+ # Initialize connections, topic names and configurations
+ conn1 = connection()
+ tenant = 'kaboom1'
+ conn2 = connect_random_user(tenant)
+ bucket_name = gen_bucket_name()
+ topic_name1 = bucket_name + TOPIC_SUFFIX + '1'
+ topic_name2 = bucket_name + TOPIC_SUFFIX + '2'
+ topic_name3 = bucket_name + TOPIC_SUFFIX + '3'
+ tenant_topic_name1 = tenant + "_" + topic_name1
+ tenant_topic_name2 = tenant + "_" + topic_name2
+ host = get_ip()
+ http_port = random.randint(10000, 20000)
+ endpoint_address = 'http://' + host + ':' + str(http_port)
+ endpoint_args = 'push-endpoint=' + endpoint_address + '&persistent=true'
+ zonegroup = get_config_zonegroup()
+
+ # Make sure there are no leftover topics
+ delete_all_topics(conn1, '', get_config_cluster())
+ delete_all_topics(conn2, tenant, get_config_cluster())
+
+ # Create s3 - v2 topics
+ topic_conf = PSTopicS3(conn1, topic_name1, zonegroup, endpoint_args=endpoint_args)
+ topic_arn1 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_name2, zonegroup, endpoint_args=endpoint_args)
+ topic_arn2 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_name3, zonegroup, endpoint_args=endpoint_args)
+ topic_arn3 = topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, tenant_topic_name1, zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn1 = tenant_topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, tenant_topic_name2, zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn2 = tenant_topic_conf.set_config()
+
+ # Verify topics list
+ try:
+ # Verify no tenant topics
+ res, status = topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else [] # version 2
+ assert_equal(len(member), 3)
+
+ # Verify topics for tenant
+ res, status = tenant_topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else []
+ assert_equal(len(member), 2)
+ finally:
+ # Cleanup created topics
+ topic_conf.del_config(topic_arn1)
+ topic_conf.del_config(topic_arn2)
+ topic_conf.del_config(topic_arn3)
+ tenant_topic_conf.del_config(tenant_topic_arn1)
+ tenant_topic_conf.del_config(tenant_topic_arn2)
+
+@attr('data_path_v2_test')
+def test_ps_s3_list_topics_v1():
+ """ test list topics on v1"""
+ if get_config_cluster() == 'noname':
+ return SkipTest('realm is needed')
+
+ # Initialize connections and configurations
+ conn1 = connection()
+ tenant = 'kaboom1'
+ conn2 = connect_random_user(tenant)
+ bucket_name = gen_bucket_name()
+ topic_name1 = bucket_name + TOPIC_SUFFIX + '1'
+ topic_name2 = bucket_name + TOPIC_SUFFIX + '2'
+ topic_name3 = bucket_name + TOPIC_SUFFIX + '3'
+ tenant_topic_name1 = tenant + "_" + topic_name1
+ tenant_topic_name2 = tenant + "_" + topic_name2
+ host = get_ip()
+ http_port = random.randint(10000, 20000)
+ endpoint_address = 'http://' + host + ':' + str(http_port)
+ endpoint_args = 'push-endpoint=' + endpoint_address + '&persistent=true'
+ zonegroup = get_config_zonegroup()
+ conf_cluster = get_config_cluster()
+
+ # Make sure there are no leftover topics
+ delete_all_topics(conn1, '', conf_cluster)
+ delete_all_topics(conn2, tenant, conf_cluster)
+
+ # Make sure that we disable v2
+ zonegroup_modify_feature(enable=False, feature_name=zonegroup_feature_notification_v2)
+
+ # Create s3 - v1 topics
+ topic_conf = PSTopicS3(conn1, topic_name1, zonegroup, endpoint_args=endpoint_args)
+ topic_arn1 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_name2, zonegroup, endpoint_args=endpoint_args)
+ topic_arn2 = topic_conf.set_config()
+ topic_conf = PSTopicS3(conn1, topic_name3, zonegroup, endpoint_args=endpoint_args)
+ topic_arn3 = topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, tenant_topic_name1, zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn1 = tenant_topic_conf.set_config()
+ tenant_topic_conf = PSTopicS3(conn2, tenant_topic_name2, zonegroup, endpoint_args=endpoint_args)
+ tenant_topic_arn2 = tenant_topic_conf.set_config()
+
+ # Verify topics list
+ try:
+ # Verify no tenant topics
+ res, status = topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else []
+ assert_equal(len(member), 3)
+
+ # Verify tenant topics
+ res, status = tenant_topic_conf.get_list()
+ assert_equal(status // 100, 2)
+ listTopicsResponse = res.get('ListTopicsResponse', {})
+ listTopicsResult = listTopicsResponse.get('ListTopicsResult', {})
+ topics = listTopicsResult.get('Topics', {})
+ member = topics['member'] if topics else []
+ assert_equal(len(member), 2)
+ finally:
+ # Cleanup created topics
+ topic_conf.del_config(topic_arn1)
+ topic_conf.del_config(topic_arn2)
+ topic_conf.del_config(topic_arn3)
+ tenant_topic_conf.del_config(tenant_topic_arn1)
+ tenant_topic_conf.del_config(tenant_topic_arn2)
+
+
@attr('basic_test')
def test_ps_s3_topic_permissions():
""" test s3 topic set/get/delete permissions """
diff --git a/src/test/rgw/rgw_multi/tests.py b/src/test/rgw/rgw_multi/tests.py
index 2d49c7a0ce0..433cd034fe0 100644
--- a/src/test/rgw/rgw_multi/tests.py
+++ b/src/test/rgw/rgw_multi/tests.py
@@ -15,6 +15,7 @@ import boto
import boto.s3.connection
from boto.s3.website import WebsiteConfiguration
from boto.s3.cors import CORSConfiguration
+from botocore.exceptions import ClientError
from nose.tools import eq_ as eq
from nose.tools import assert_not_equal, assert_equal, assert_true, assert_false
@@ -573,6 +574,7 @@ def create_bucket_per_zone_in_realm():
b, z = create_bucket_per_zone(zg_conn)
buckets.extend(b)
zone_bucket.extend(z)
+ realm_meta_checkpoint(realm)
return buckets, zone_bucket
def test_bucket_create():
@@ -1212,6 +1214,9 @@ def test_datalog_autotrim():
# wait for metadata and data sync to catch up
zonegroup_meta_checkpoint(zonegroup)
zonegroup_data_checkpoint(zonegroup_conns)
+ zonegroup_bucket_checkpoint(zonegroup_conns, bucket.name)
+ time.sleep(config.checkpoint_delay)
+ zonegroup_data_checkpoint(zonegroup_conns)
# trim each datalog
for zone, _ in zone_bucket:
@@ -3634,4 +3639,23 @@ def test_copy_object_different_bucket():
CopySource = source_bucket.name + '/' + objname)
zonegroup_bucket_checkpoint(zonegroup_conns, dest_bucket.name)
-
+
+def test_bucket_create_location_constraint():
+ for zonegroup in realm.current_period.zonegroups:
+ zonegroup_conns = ZonegroupConns(zonegroup)
+ for zg in realm.current_period.zonegroups:
+ z = zonegroup_conns.rw_zones[0]
+ bucket_name = gen_bucket_name()
+ if zg.name == zonegroup.name:
+ # my zonegroup should pass
+ z.s3_client.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={'LocationConstraint': zg.name})
+ # check bucket location
+ response = z.s3_client.get_bucket_location(Bucket=bucket_name)
+ assert_equal(response['LocationConstraint'], zg.name)
+ else:
+ # other zonegroup should fail with 400
+ e = assert_raises(ClientError,
+ z.s3_client.create_bucket,
+ Bucket=bucket_name,
+ CreateBucketConfiguration={'LocationConstraint': zg.name})
+ assert e.response['ResponseMetadata']['HTTPStatusCode'] == 400
diff --git a/src/test/rgw/test-rgw-common.sh b/src/test/rgw/test-rgw-common.sh
index 9129092898e..6798a15ba31 100644
--- a/src/test/rgw/test-rgw-common.sh
+++ b/src/test/rgw/test-rgw-common.sh
@@ -103,7 +103,7 @@ function init_first_zone {
# create zonegroup, zone
x $(rgw_admin $cid) zonegroup create --rgw-zonegroup=$zg --master --default
- x $(rgw_admin $cid) zone create --rgw-zonegroup=$zg --rgw-zone=$zone --access-key=${access_key} --secret=${secret} --endpoints=$endpoints --default
+ x $(rgw_admin $cid) zone create --rgw-zonegroup=$zg --rgw-zone=$zone --access-key=${access_key} --secret=${secret} --endpoints=$endpoints --master --default
x $(rgw_admin $cid) user create --uid=zone.user --display-name=ZoneUser --access-key=${access_key} --secret=${secret} --system
x $(rgw_admin $cid) period update --commit
@@ -128,7 +128,7 @@ function init_zone_in_existing_zg {
x $(rgw_admin $cid) period update --commit
}
-function init_first_zone_in_slave_zg {
+function init_first_zone_in_peer_zg {
[ $# -ne 8 ] && echo "init_first_zone_in_slave_zg() needs 8 params" && exit 1
cid=$1
diff --git a/src/test/rgw/test-rgw-multisite.sh b/src/test/rgw/test-rgw-multisite.sh
index a005b19e3da..d3a1b265ca6 100755
--- a/src/test/rgw/test-rgw-multisite.sh
+++ b/src/test/rgw/test-rgw-multisite.sh
@@ -1,11 +1,12 @@
#!/usr/bin/env bash
-[ $# -lt 1 ] && echo "usage: $0 <num-clusters> [rgw parameters...]" && exit 1
+[ $# -lt 1 ] && echo "usage: $0 <num-zones> <num-zonegroups>[rgw parameters...]" && exit 1
-num_clusters=$1
+num_zones=$1
+num_zonegroups=$2
shift
-[ $num_clusters -lt 1 ] && echo "clusters num must be at least 1" && exit 1
+[ $num_zones -lt 1 ] && echo "clusters num must be at least 1" && exit 1
. "`dirname $0`/test-rgw-common.sh"
. "`dirname $0`/test-rgw-meta-sync.sh"
@@ -53,7 +54,7 @@ echo realm_status=$output
endpoints=""
i=2
-while [ $i -le $num_clusters ]; do
+while [ $i -le $num_zones ]; do
x $(start_ceph_cluster c$i) -n $(get_mstart_parameters $i)
j=1
endpoints=""
@@ -74,10 +75,53 @@ while [ $i -le $num_clusters ]; do
i=$((i+1))
done
-i=2
-while [ $i -le $num_clusters ]; do
- wait_for_meta_sync c1 c$i $realm_name
+endpoints=""
+k=2
+while [ $k -le $num_zonegroups ]; do
+ x $(start_ceph_cluster c$i) -n $(get_mstart_parameters $i)
+ j=1
+ endpoints=""
+ while [ $j -le $rgws ]; do
+ port=$((8000+i*100+j))
+ endpoints="$endpoints""$url:$port,"
+ j=$((j+1))
+ done
+ # create new zone, start rgw
+ init_first_zone_in_peer_zg c$i $realm_name zg${k} zg${k}-${i} 8101 $endpoints $system_access_key $system_secret
+ j=1
+ while [ $j -le $rgws ]; do
+ port=$((8000+i*100+j))
+ x $(rgw c$i "$port" "$@")
+ j="$((j+1))"
+ done
+# bring up next clusters in zonegroup k
i=$((i+1))
+
+ endpoints=""
+ l=2
+ while [ $l -le $num_zones ]; do
+ x $(start_ceph_cluster c$i) -n $(get_mstart_parameters $i)
+ j=1
+ endpoints=""
+ while [ $j -le $rgws ]; do
+ port=$((8000+i*100+j))
+ endpoints="$endpoints""$url:$port,"
+ j=$((j+1))
+ done
+
+ # create new zone, start rgw
+ init_zone_in_existing_zg c$i $realm_name zg${k} zg${k}-${i} 8101 $endpoints $zone_port $system_access_key $system_secret
+ j=1
+ while [ $j -le $rgws ]; do
+ port=$((8000+i*100+j))
+ x $(rgw c$i "$port" "$@")
+ j="$((j+1))"
+ done
+ l=$((l+1))
+ i=$((i+1))
+ done
+
+ k=$((k+1))
done
diff --git a/src/test/rgw/test_log_backing.cc b/src/test/rgw/test_log_backing.cc
index e4109d535d1..a6de690af0f 100644
--- a/src/test/rgw/test_log_backing.cc
+++ b/src/test/rgw/test_log_backing.cc
@@ -20,6 +20,7 @@
#include <fmt/format.h>
+#include "common/Clock.h" // for ceph_clock_now()
#include "include/types.h"
#include "include/rados/librados.hpp"
diff --git a/src/test/rgw/test_rgw_iam_policy.cc b/src/test/rgw/test_rgw_iam_policy.cc
index 7dadb7812ff..1d13c2aa013 100644
--- a/src/test/rgw/test_rgw_iam_policy.cc
+++ b/src/test/rgw/test_rgw_iam_policy.cc
@@ -75,6 +75,8 @@ using rgw::IAM::s3GetObjectTagging;
using rgw::IAM::s3GetObjectVersion;
using rgw::IAM::s3GetObjectVersionTagging;
using rgw::IAM::s3GetObjectVersionTorrent;
+using rgw::IAM::s3GetObjectAttributes;
+using rgw::IAM::s3GetObjectVersionAttributes;
using rgw::IAM::s3GetPublicAccessBlock;
using rgw::IAM::s3GetReplicationConfiguration;
using rgw::IAM::s3ListAllMyBuckets;
@@ -419,6 +421,8 @@ TEST_F(PolicyTest, Parse3) {
act2[s3GetObjectVersionAcl] = 1;
act2[s3GetObjectTorrent] = 1;
act2[s3GetObjectVersionTorrent] = 1;
+ act2[s3GetObjectAttributes] = 1;
+ act2[s3GetObjectVersionAttributes] = 1;
act2[s3GetAccelerateConfiguration] = 1;
act2[s3GetBucketAcl] = 1;
act2[s3GetBucketOwnershipControls] = 1;
@@ -487,6 +491,8 @@ TEST_F(PolicyTest, Eval3) {
s3allow[s3GetObjectVersion] = 1;
s3allow[s3GetObjectAcl] = 1;
s3allow[s3GetObjectVersionAcl] = 1;
+ s3allow[s3GetObjectAttributes] = 1;
+ s3allow[s3GetObjectVersionAttributes] = 1;
s3allow[s3GetObjectTorrent] = 1;
s3allow[s3GetObjectVersionTorrent] = 1;
s3allow[s3GetAccelerateConfiguration] = 1;
@@ -883,6 +889,8 @@ TEST_F(ManagedPolicyTest, AmazonS3ReadOnlyAccess)
act[s3GetObjectVersionAcl] = 1;
act[s3GetObjectTorrent] = 1;
act[s3GetObjectVersionTorrent] = 1;
+ act[s3GetObjectAttributes] = 1;
+ act[s3GetObjectVersionAttributes] = 1;
act[s3GetAccelerateConfiguration] = 1;
act[s3GetBucketAcl] = 1;
act[s3GetBucketOwnershipControls] = 1;
diff --git a/src/test/signals.cc b/src/test/signals.cc
index dc24900a8c4..513b176b780 100644
--- a/src/test/signals.cc
+++ b/src/test/signals.cc
@@ -3,6 +3,7 @@
#include "global/signal_handler.h"
#include "common/debug.h"
#include "include/coredumpctl.h"
+#include "log/Log.h"
#include "gtest/gtest.h"
diff --git a/src/test/test_addrs.cc b/src/test/test_addrs.cc
index 4062d0431c3..e70d234d743 100644
--- a/src/test/test_addrs.cc
+++ b/src/test/test_addrs.cc
@@ -17,6 +17,7 @@
#include "msg/msg_types.h"
#include "gtest/gtest.h"
+#include <iostream> // for std::cout
#include <sstream>
using namespace std;
diff --git a/src/test/test_denc.cc b/src/test/test_denc.cc
index 02dd1454ef8..db742b5e2cf 100644
--- a/src/test/test_denc.cc
+++ b/src/test/test_denc.cc
@@ -15,6 +15,8 @@
*/
#include <stdio.h>
+
+#include <iostream> // for std::cout
#include <numeric>
#include "global/global_init.h"
@@ -24,6 +26,10 @@
#include "include/denc.h"
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <boost/optional.hpp>
+
using namespace std;
// test helpers
diff --git a/src/test/test_features.cc b/src/test/test_features.cc
index 1ae758bfb34..bdd8838224b 100644
--- a/src/test/test_features.cc
+++ b/src/test/test_features.cc
@@ -2,6 +2,8 @@
// vim: ts=8 sw=2 smarttab
#include <stdio.h>
+#include <iostream> // for std::cout
+
#include "global/global_init.h"
#include "common/ceph_argparse.h"
#include "common/ceph_releases.h"
diff --git a/src/test/test_ipaddr.cc b/src/test/test_ipaddr.cc
index 49038815318..21df1d4056b 100644
--- a/src/test/test_ipaddr.cc
+++ b/src/test/test_ipaddr.cc
@@ -995,3 +995,158 @@ TEST(pick_address, ipv4_ipv6_enabled2)
ASSERT_EQ(-1, r);
}
}
+
+// Test for IPv4 address
+TEST(is_addr_in_subnet, ipv4)
+{
+ std::string public_network = "10.1.1.0/24";
+ entity_addr_t addr;
+ addr.parse("10.1.1.2", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "false");
+
+ bool r = is_addr_in_subnet(cct.get(), public_network, addr);
+ ASSERT_EQ(true, r);
+}
+
+// Test for IPv6 address
+TEST(is_addr_in_subnet, ipv6)
+{
+ std::string public_network = "2001:db8::/64";
+ entity_addr_t addr;
+ addr.parse("2001:db8::1", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv6", "true");
+ cct->_conf.set_val("ms_bind_ipv4", "false");
+
+ bool r = is_addr_in_subnet(cct.get(), public_network, addr);
+ ASSERT_EQ(true, r);
+}
+
+// Test for invalid address
+TEST(is_addr_in_subnet, invalid_address)
+{
+ std::string public_network = "10.1.1.0/24";
+ entity_addr_t addr;
+ addr.parse("192.168.1.1", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "false");
+
+ bool r = is_addr_in_subnet(cct.get(), public_network, addr);
+ ASSERT_EQ(false, r);
+}
+
+// Test for malformed address
+TEST(is_addr_in_subnet, malformed_address)
+{
+ std::string public_network = "10.1.1.0/24";
+ entity_addr_t addr;
+ addr.parse("invalid_address", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "false");
+
+ // Test with a malformed address
+ bool r = is_addr_in_subnet(cct.get(), public_network, addr);
+ ASSERT_EQ(false, r);
+}
+
+TEST(is_addr_in_subnet, boundary_ipv4)
+{
+ std::string public_network = "10.1.1.0/24";
+ entity_addr_t addr_low;
+ addr_low.parse("10.1.1.0", nullptr);
+ entity_addr_t addr_high;
+ addr_high.parse("10.1.1.255", nullptr);
+ entity_addr_t addr_out;
+ addr_out.parse("10.1.2.0", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "false");
+
+ ASSERT_TRUE(is_addr_in_subnet(cct.get(), public_network, addr_low));
+ ASSERT_TRUE(is_addr_in_subnet(cct.get(), public_network, addr_high));
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network, addr_out));
+}
+
+TEST(is_addr_in_subnet, boundary_ipv6)
+{
+ std::string public_network = "2001:db8::/64";
+ entity_addr_t addr_low;
+ addr_low.parse("2001:db8::", nullptr);
+ entity_addr_t addr_high;
+ addr_high.parse("2001:db8:0:0:ffff:ffff:ffff:ffff", nullptr);
+ entity_addr_t addr_out;
+ addr_out.parse("2001:db9::", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv6", "true");
+ cct->_conf.set_val("ms_bind_ipv4", "false");
+
+ ASSERT_TRUE(is_addr_in_subnet(cct.get(), public_network, addr_low));
+ ASSERT_TRUE(is_addr_in_subnet(cct.get(), public_network, addr_high));
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network, addr_out));
+}
+
+TEST(is_addr_in_subnet, overlapping_subnets)
+{
+ std::string public_network_1 = "10.1.1.0/24";
+ std::string public_network_2 = "10.1.2.0/24";
+ entity_addr_t addr;
+ addr.parse("10.1.1.5", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "false");
+
+ ASSERT_TRUE(is_addr_in_subnet(cct.get(), public_network_1, addr));
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network_2, addr));
+}
+
+TEST(is_addr_in_subnet, mismatched_family)
+{
+ std::string public_network_1 = "2001:db8::/64";
+ entity_addr_t addr_1;
+ addr_1.parse("10.1.1.5", nullptr);
+
+ std::string public_network_2 = "10.1.1.0/24";
+ entity_addr_t addr_2;
+ addr_2.parse("2001:db8::1", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+ cct->_conf.set_val("ms_bind_ipv4", "true");
+ cct->_conf.set_val("ms_bind_ipv6", "true");
+
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network_1, addr_1));
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network_2, addr_2));
+}
+
+TEST(is_addr_in_subnet, invalid_subnets)
+{
+ std::string public_network_1 = "10.1.1.0/33";
+ std::string public_network_2 = "25.0.0.99/10";
+ entity_addr_t addr;
+ addr.parse("10.1.1.2", nullptr);
+
+ boost::intrusive_ptr<CephContext> cct(new CephContext(CEPH_ENTITY_TYPE_OSD), false);
+ cct->_conf._clear_safe_to_start_threads();
+
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network_1, addr)); // Invalid prefix
+ ASSERT_FALSE(is_addr_in_subnet(cct.get(), public_network_2, addr)); // Invalid subnet string
+}
+
diff --git a/src/test/test_mempool.cc b/src/test/test_mempool.cc
index bb46b19aa4e..b806282d039 100644
--- a/src/test/test_mempool.cc
+++ b/src/test/test_mempool.cc
@@ -16,6 +16,8 @@
#include <stdio.h>
+#include <iostream> // for std::cout
+
#include "global/global_init.h"
#include "common/ceph_argparse.h"
#include "global/global_context.h"
diff --git a/src/test/test_perf_counters_cache.cc b/src/test/test_perf_counters_cache.cc
index 1fa147ee273..fa2d541b7f7 100644
--- a/src/test/test_perf_counters_cache.cc
+++ b/src/test/test_perf_counters_cache.cc
@@ -4,6 +4,7 @@
#include "global/global_context.h"
#include "global/global_init.h"
#include "include/msgr.h" // for CEPH_ENTITY_TYPE_CLIENT
+#include "include/utime.h"
#include "gtest/gtest.h"
using namespace ceph::perf_counters;
diff --git a/src/test/test_rewrite_latency.cc b/src/test/test_rewrite_latency.cc
index 348c8dde5c6..48a95cf183b 100644
--- a/src/test/test_rewrite_latency.cc
+++ b/src/test/test_rewrite_latency.cc
@@ -1,5 +1,6 @@
#include <unistd.h>
+#include <iostream> // for std::cout
#include <map>
#include <errno.h>
diff --git a/src/test/test_snap_mapper.cc b/src/test/test_snap_mapper.cc
index a47d2538c3a..7a9ac62defe 100644
--- a/src/test/test_snap_mapper.cc
+++ b/src/test/test_snap_mapper.cc
@@ -1,4 +1,5 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+#include <iostream> // for std::cout
#include <iterator>
#include <map>
#include <set>
diff --git a/src/test/test_striper.cc b/src/test/test_striper.cc
index ee70304ebc8..1e5f93a49be 100644
--- a/src/test/test_striper.cc
+++ b/src/test/test_striper.cc
@@ -3,6 +3,8 @@
#include "osdc/Striper.h"
+#include <iostream> // for std::cout
+
using namespace std;
TEST(Striper, Stripe1)
diff --git a/src/test/test_utime.cc b/src/test/test_utime.cc
index b1cee0e805c..de1d6f46878 100644
--- a/src/test/test_utime.cc
+++ b/src/test/test_utime.cc
@@ -1,4 +1,7 @@
#include "include/utime.h"
+
+#include <iostream> // for std::cout
+
#include "gtest/gtest.h"
#include "include/stringify.h"
#include "common/ceph_context.h"
diff --git a/src/test/test_workqueue.cc b/src/test/test_workqueue.cc
index 771b9d65952..5c2fc459da2 100644
--- a/src/test/test_workqueue.cc
+++ b/src/test/test_workqueue.cc
@@ -1,6 +1,9 @@
#include "gtest/gtest.h"
#include "common/WorkQueue.h"
+
+#include <iostream> // for std::cout
+
#include "common/ceph_argparse.h"
using namespace std;
diff --git a/src/test/testcrypto.cc b/src/test/testcrypto.cc
index 2efb9b219b9..8e3337babea 100644
--- a/src/test/testcrypto.cc
+++ b/src/test/testcrypto.cc
@@ -1,6 +1,8 @@
#include "auth/Crypto.h"
-#include "common/Clock.h"
+#include <iostream> // for std::cout
+
+#include "common/Clock.h"
#include "common/config.h"
#include "common/debug.h"
diff --git a/src/test/testkeys.cc b/src/test/testkeys.cc
index 85d0b56676f..dacddb08786 100644
--- a/src/test/testkeys.cc
+++ b/src/test/testkeys.cc
@@ -1,4 +1,7 @@
#include "auth/cephx/CephxKeyServer.h"
+
+#include <iostream> // for std::cout
+
#include "common/ceph_argparse.h"
#include "global/global_init.h"
#include "common/config.h"