Skip to content

Commit 5b73b8d

Browse files
authored
CXX-1998 'CommitQuorum' support for 'createIndexes’ cmd (#691)
1 parent 5e0b6e7 commit 5b73b8d

File tree

8 files changed

+155
-10
lines changed

8 files changed

+155
-10
lines changed

src/mongocxx/collection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,7 @@ class change_stream collection::_watch(const client_session* session,
12821282
}
12831283

12841284
class index_view collection::indexes() {
1285-
return index_view{_get_impl().collection_t};
1285+
return index_view{_get_impl().collection_t, _get_impl().client_impl->client_t};
12861286
}
12871287

12881288
class bulk_write collection::_init_insert_many(const options::insert& options,

src/mongocxx/index_view.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@
2626
namespace mongocxx {
2727
MONGOCXX_INLINE_NAMESPACE_BEGIN
2828

29-
index_view::index_view(void* coll)
30-
: _impl{stdx::make_unique<impl>(static_cast<mongoc_collection_t*>(coll))} {}
29+
index_view::index_view(void* coll, void* client)
30+
: _impl{stdx::make_unique<impl>(static_cast<mongoc_collection_t*>(coll),
31+
static_cast<mongoc_client_t*>(client))} {}
3132

3233
index_view::index_view(index_view&&) noexcept = default;
3334
index_view& index_view::operator=(index_view&&) noexcept = default;

src/mongocxx/index_view.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ class MONGOCXX_API index_view {
421421
friend class collection;
422422
class MONGOCXX_PRIVATE impl;
423423

424-
MONGOCXX_PRIVATE index_view(void* coll);
424+
MONGOCXX_PRIVATE index_view(void* coll, void* client);
425425

426426
MONGOCXX_PRIVATE impl& _get_impl();
427427

src/mongocxx/options/index_view.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <bsoncxx/builder/basic/document.hpp>
16+
#include <bsoncxx/builder/basic/kvp.hpp>
17+
#include <bsoncxx/types.hpp>
18+
#include <mongocxx/config/private/prelude.hh>
1519
#include <mongocxx/options/index_view.hpp>
1620

17-
#include <mongocxx/config/private/prelude.hh>
21+
using bsoncxx::builder::basic::kvp;
22+
using bsoncxx::builder::basic::make_document;
1823

1924
namespace mongocxx {
2025
MONGOCXX_INLINE_NAMESPACE_BEGIN
@@ -30,6 +35,10 @@ const bsoncxx::stdx::optional<std::chrono::milliseconds>& index_view::max_time()
3035
return _max_time;
3136
}
3237

38+
const stdx::optional<bsoncxx::document::value> index_view::commit_quorum() const {
39+
return _commit_quorum;
40+
}
41+
3342
index_view& index_view::max_time(std::chrono::milliseconds max_time) {
3443
_max_time = max_time;
3544
return *this;
@@ -40,6 +49,18 @@ index_view& index_view::write_concern(mongocxx::write_concern write_concern) {
4049
return *this;
4150
}
4251

52+
index_view& index_view::commit_quorum(int commit_quorum) {
53+
_commit_quorum = stdx::make_optional<bsoncxx::document::value>(
54+
make_document(kvp("commitQuorum", bsoncxx::types::b_int32{commit_quorum})));
55+
return *this;
56+
}
57+
58+
index_view& index_view::commit_quorum(std::string commit_quorum) {
59+
_commit_quorum = stdx::make_optional<bsoncxx::document::value>(
60+
make_document(kvp("commitQuorum", commit_quorum)));
61+
return *this;
62+
}
4363
} // namespace options
64+
4465
MONGOCXX_INLINE_NAMESPACE_END
4566
} // namespace mongocxx

src/mongocxx/options/index_view.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,61 @@ class MONGOCXX_API index_view {
8484
///
8585
const bsoncxx::stdx::optional<mongocxx::write_concern>& write_concern() const;
8686

87+
///
88+
/// Sets the commit quorum for this operation.
89+
///
90+
/// This option may only be used with MongoDB version 4.4 or later.
91+
///
92+
/// @param commit_quorum
93+
/// Integer representing the minimum number of data-bearing voting replica set members (i.e.
94+
/// commit quorum), including the primary, that must report a successful index build before
95+
/// the primary marks the indexes as ready. A value of @c 0 disables quorum-voting behavior.
96+
///
97+
/// @return
98+
/// A reference to the object on which this member function is being called. This facilitates
99+
/// method chaining.
100+
///
101+
/// @see
102+
/// https://docs.mongodb.com/master/reference/command/createIndexes
103+
///
104+
index_view& commit_quorum(std::int32_t commit_quorum);
105+
106+
///
107+
/// Sets the commit quorum for this operation.
108+
///
109+
/// This option may only be used with MongoDB version 4.4 or later.
110+
///
111+
/// @param commit_quorum
112+
/// String representing the minimum number of data-bearing voting replica set members (i.e.
113+
/// commit quorum), including the primary, that must report a successful index build before
114+
/// the primary marks the indexes as ready.
115+
///
116+
/// @return
117+
/// A reference to the object on which this member function is being called. This facilitates
118+
/// method chaining.
119+
///
120+
/// @see
121+
/// https://docs.mongodb.com/master/reference/command/createIndexes
122+
///
123+
index_view& commit_quorum(std::string commit_quorum);
124+
125+
///
126+
/// Gets the current commitQuorum setting.
127+
///
128+
/// This option may only be used with MongoDB version 4.4 or later.
129+
///
130+
/// @return
131+
/// The current commitQuorum setting.
132+
///
133+
/// @see
134+
/// https://docs.mongodb.com/master/reference/command/createIndexes
135+
///
136+
const stdx::optional<bsoncxx::document::value> commit_quorum() const;
137+
87138
private:
88139
bsoncxx::stdx::optional<std::chrono::milliseconds> _max_time;
89140
bsoncxx::stdx::optional<mongocxx::write_concern> _write_concern;
141+
bsoncxx::stdx::optional<bsoncxx::document::value> _commit_quorum;
90142
};
91143

92144
} // namespace options

src/mongocxx/private/index_view.hh

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,21 @@
1414

1515
#pragma once
1616

17-
#include <vector>
18-
1917
#include <bsoncxx/builder/basic/array.hpp>
2018
#include <bsoncxx/builder/basic/document.hpp>
2119
#include <bsoncxx/document/view_or_value.hpp>
2220
#include <bsoncxx/string/to_string.hpp>
2321
#include <bsoncxx/types/bson_value/view.hpp>
22+
#include <mongocxx/config/private/prelude.hh>
2423
#include <mongocxx/exception/error_code.hpp>
2524
#include <mongocxx/exception/logic_error.hpp>
2625
#include <mongocxx/exception/operation_exception.hpp>
26+
#include <mongocxx/exception/write_exception.hpp>
2727
#include <mongocxx/options/index_view.hpp>
2828
#include <mongocxx/private/client_session.hh>
2929
#include <mongocxx/private/libbson.hh>
3030
#include <mongocxx/private/libmongoc.hh>
31-
32-
#include <mongocxx/config/private/prelude.hh>
31+
#include <vector>
3332

3433
namespace mongocxx {
3534
MONGOCXX_INLINE_NAMESPACE_BEGIN
@@ -39,7 +38,8 @@ using bsoncxx::builder::basic::kvp;
3938

4039
class index_view::impl {
4140
public:
42-
impl(mongoc_collection_t* collection) : _coll{collection} {}
41+
impl(mongoc_collection_t* collection, mongoc_client_t* client)
42+
: _coll{collection}, _client{client} {}
4343

4444
impl(const impl& i) = default;
4545

@@ -134,6 +134,26 @@ class index_view::impl {
134134
opts_doc.append(bsoncxx::builder::concatenate_doc{session->_get_impl().to_document()});
135135
}
136136

137+
if (options.commit_quorum()) {
138+
auto server_description = scoped_server_description(libmongoc::client_select_server(
139+
_client, true /* for_writes */, nullptr /* read_prefs */, &error));
140+
if (!server_description.sd)
141+
throw_exception<write_exception>(error);
142+
143+
auto is_master = libmongoc::server_description_ismaster(server_description.sd);
144+
145+
bson_iter_t iter;
146+
if (!bson_iter_init_find(&iter, is_master, "maxWireVersion") ||
147+
bson_iter_int32(&iter) < 9) {
148+
throw write_exception{
149+
error_code::k_invalid_parameter,
150+
"option 'commitQuorum' not available on the current server version"};
151+
}
152+
153+
command =
154+
make_document(concatenate(command), concatenate(options.commit_quorum()->view()));
155+
}
156+
137157
libbson::scoped_bson_t command_bson{command};
138158
libbson::scoped_bson_t opts_bson{opts_doc.view()};
139159

@@ -219,6 +239,16 @@ class index_view::impl {
219239
}
220240

221241
mongoc_collection_t* _coll;
242+
mongoc_client_t* _client;
243+
244+
class scoped_server_description {
245+
public:
246+
explicit scoped_server_description(mongoc_server_description_t* sd) : sd(sd) {}
247+
~scoped_server_description() {
248+
mongoc_server_description_destroy(sd);
249+
}
250+
mongoc_server_description_t* sd;
251+
};
222252
};
223253
MONGOCXX_INLINE_NAMESPACE_END
224254
} // namespace mongocxx

src/mongocxx/private/libmongoc_symbols.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ MONGOCXX_LIBMONGOC_SYMBOL(client_pool_push)
154154
MONGOCXX_LIBMONGOC_SYMBOL(client_pool_set_apm_callbacks)
155155
MONGOCXX_LIBMONGOC_SYMBOL(client_pool_try_pop)
156156
MONGOCXX_LIBMONGOC_SYMBOL(client_reset)
157+
MONGOCXX_LIBMONGOC_SYMBOL(client_select_server)
157158
MONGOCXX_LIBMONGOC_SYMBOL(client_session_abort_transaction)
158159
MONGOCXX_LIBMONGOC_SYMBOL(client_session_advance_cluster_time)
159160
MONGOCXX_LIBMONGOC_SYMBOL(client_session_advance_operation_time)

src/mongocxx/test/index_view.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,46 @@ TEST_CASE("create_one", "[index_view]") {
172172
REQUIRE_NOTHROW(indexes.create_one(keys1.view(), options.view()));
173173
REQUIRE_THROWS_AS(indexes.create_one(keys2.view(), options.view()), operation_exception);
174174
}
175+
176+
SECTION("commitQuorum option") {
177+
if (test_util::get_topology(mongodb_client) == "single") {
178+
WARN("skip: commitQuorum option requires a replica set");
179+
return;
180+
}
181+
182+
collection coll = db["index_view_create_one_commit_quorum"];
183+
coll.drop();
184+
coll.insert_one({}); // Ensure that the collection exists.
185+
index_view indexes = coll.indexes();
186+
187+
auto key = make_document(kvp("a", 1));
188+
index_model model(key.view());
189+
options::index_view options;
190+
191+
auto commit_quorum_regex =
192+
Catch::Matches("(.*)commit( )?quorum(.*)", Catch::CaseSensitive::No);
193+
194+
bool is_supported = test_util::get_max_wire_version(mongodb_client) >= 9;
195+
CAPTURE(is_supported);
196+
197+
SECTION("works with int") {
198+
options.commit_quorum(1);
199+
if (is_supported) {
200+
REQUIRE_NOTHROW(indexes.create_one(model, options));
201+
} else {
202+
REQUIRE_THROWS_WITH(indexes.create_one(model, options), commit_quorum_regex);
203+
}
204+
}
205+
206+
SECTION("works with string") {
207+
options.commit_quorum("majority");
208+
if (is_supported) {
209+
REQUIRE_NOTHROW(indexes.create_one(model, options));
210+
} else {
211+
REQUIRE_THROWS_WITH(indexes.create_one(model, options), commit_quorum_regex);
212+
}
213+
}
214+
}
175215
}
176216

177217
TEST_CASE("create_many", "[index_view]") {

0 commit comments

Comments
 (0)