From 0cd5c4c5b1fae29a8cf35dcf84a3269d2555b066 Mon Sep 17 00:00:00 2001 From: Eddy Ashton Date: Wed, 30 Sep 2020 16:33:48 +0100 Subject: [PATCH] Document dynamic table creation, and use dynamic-friendly Txs everywhere (#1674) --- doc/developers/kv/kv_how_to.rst | 18 ++- .../tests/small_bank_serdes_bench.cpp | 2 +- src/apps/js_generic/js_generic.cpp | 2 +- src/apps/logging/logging.cpp | 4 +- .../lua_generic/test/lua_generic_test.cpp | 8 +- src/consensus/aft/raft.h | 2 +- src/consensus/aft/raft_types.h | 11 ++ src/consensus/aft/test/logging_stub.h | 5 + src/kv/store.h | 27 +++- src/kv/test/kv_bench.cpp | 10 +- src/kv/test/kv_contention.cpp | 2 +- src/kv/test/kv_dynamic_tables.cpp | 142 ++++++++++++------ src/kv/test/kv_serialisation.cpp | 50 +++--- src/kv/test/kv_snapshot.cpp | 22 +-- src/kv/test/kv_test.cpp | 133 ++++++++-------- src/kv/tx.h | 112 +++++++++++--- src/lua_interp/test/lua_kv.cpp | 12 +- src/node/historical_queries.h | 4 +- src/node/history.h | 8 +- src/node/node_state.h | 13 +- src/node/progress_tracker.h | 2 +- src/node/rpc/frontend.h | 2 +- src/node/rpc/test/frontend_test.cpp | 20 +-- src/node/rpc/test/member_voting_test.cpp | 78 +++++----- src/node/rpc/test/node_frontend_test.cpp | 8 +- src/node/snapshotter.h | 2 +- src/node/test/historical_queries.cpp | 6 +- src/node/test/history.cpp | 30 ++-- src/node/test/snapshot.cpp | 6 +- src/node/test/snapshotter.cpp | 2 +- 30 files changed, 463 insertions(+), 280 deletions(-) diff --git a/doc/developers/kv/kv_how_to.rst b/doc/developers/kv/kv_how_to.rst index 45ec1bb48..d6cc514e3 100644 --- a/doc/developers/kv/kv_how_to.rst +++ b/doc/developers/kv/kv_how_to.rst @@ -48,6 +48,23 @@ For each ``Map`` that a Transaction wants to write to or read from, a :cpp:class // Two Views created at the same time on map_pub and map_priv_int, respectively auto [view_map2, view_map3] = tx.get_view(map_pub, map_priv_int); +A :cpp:class:`kv::Map::TxView` can also be retrieved purely by name, without reference to an existing ``Map``. + +.. code-block:: cpp + + // View on map1 + auto view_map1 = tx.get_view>("map1"); + + // Two Views created at the same time, over different public and private maps + auto [view_map2, view_map3] = + tx.get_view, kv::Map>("public:map2", "map3"); + +This supports dynamic creation of maps - if the requested map did not exist previously, it will be created by this transaction. Any writes to a newly created ``Map`` will be persisted when the transaction commits, and future transactions will be able to access this ``Map`` by name. + +.. note:: + + When accessing a ``Map`` by name, the confidentiality is encoded in the map's name with a "public:" prefix. For example "public:foo" refers to a public ``Map`` while "foo" is a private ``Map``. The latter is encrypted before writing to the ledger and all access to the table must happen through application code. The former is written unencrypted so can be read by external tools with access to the ledger. These maps are distinct; writes to "public:foo" have no impact on "foo" and vice versa. + Modifying a ``View`` -------------------- @@ -183,4 +200,3 @@ By default CCF decides which transactions are successful (so should be applied t // Apply this, even though it has an error response args.rpc_ctx->set_apply_writes(true); - diff --git a/samples/apps/smallbank/tests/small_bank_serdes_bench.cpp b/samples/apps/smallbank/tests/small_bank_serdes_bench.cpp index 3da7d920f..f70c0e84c 100644 --- a/samples/apps/smallbank/tests/small_bank_serdes_bench.cpp +++ b/samples/apps/smallbank/tests/small_bank_serdes_bench.cpp @@ -73,7 +73,7 @@ static std::vector kv_serialized_data(std::vector& data) auto& map0 = kv_store.create("map0"); - kv::Tx tx(kv_store.next_version()); + auto tx = kv_store.create_reserved_tx(kv_store.next_version()); auto tx0 = tx.get_view(map0); tx0->put(0, {0, {}, data, {}}); diff --git a/src/apps/js_generic/js_generic.cpp b/src/apps/js_generic/js_generic.cpp index 9dc8e1749..902256713 100644 --- a/src/apps/js_generic/js_generic.cpp +++ b/src/apps/js_generic/js_generic.cpp @@ -178,7 +178,7 @@ namespace ccfapp LOG_TRACE_FMT("Looking for table '{}'", property_name); auto tx_ptr = static_cast(JS_GetOpaque(this_val, tables_class_id)); - auto view = tx_ptr->get_view2(property_name); + auto view = tx_ptr->get_view
(property_name); auto view_val = JS_NewObjectClass(ctx, view_class_id); JS_SetOpaque(view_val, view); diff --git a/src/apps/logging/logging.cpp b/src/apps/logging/logging.cpp index a11a0f819..08abc60e7 100644 --- a/src/apps/logging/logging.cpp +++ b/src/apps/logging/logging.cpp @@ -340,8 +340,8 @@ namespace loggingapp const auto in = params.get(); - kv::Tx historical_tx; - auto view = historical_tx.get_view(*historical_map); + auto historical_tx = historical_store->create_read_only_tx(); + auto view = historical_tx.get_read_only_view(*historical_map); const auto v = view->get(in.id); if (v.has_value()) diff --git a/src/apps/lua_generic/test/lua_generic_test.cpp b/src/apps/lua_generic/test/lua_generic_test.cpp index 10714f03b..11c8849d8 100644 --- a/src/apps/lua_generic/test/lua_generic_test.cpp +++ b/src/apps/lua_generic/test/lua_generic_test.cpp @@ -154,7 +154,7 @@ auto init_frontend( void set_handler(NetworkTables& network, const string& method, const Script& h) { - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.app_scripts)->put(method, h); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } @@ -192,7 +192,7 @@ TEST_CASE("simple lua apps") NetworkTables network; auto encryptor = std::make_shared(); network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -333,7 +333,7 @@ TEST_CASE("simple bank") NetworkTables network; auto encryptor = std::make_shared(); network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -450,7 +450,7 @@ TEST_CASE("pre-populated environment") NetworkTables network; auto encryptor = std::make_shared(); network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); diff --git a/src/consensus/aft/raft.h b/src/consensus/aft/raft.h index 31f8d0191..7b438c230 100644 --- a/src/consensus/aft/raft.h +++ b/src/consensus/aft/raft.h @@ -766,7 +766,7 @@ namespace aft state->last_idx = i; Term sig_term = 0; - kv::Tx tx; + auto tx = store->create_tx(); kv::DeserialiseSuccess deserialise_success; ccf::PrimarySignature sig; if (consensus_type == ConsensusType::BFT) diff --git a/src/consensus/aft/raft_types.h b/src/consensus/aft/raft_types.h index 85edb0b33..f8f15b94b 100644 --- a/src/consensus/aft/raft_types.h +++ b/src/consensus/aft/raft_types.h @@ -50,6 +50,7 @@ namespace aft kv::Tx* tx = nullptr, ccf::PrimarySignature* sig = nullptr) = 0; virtual std::shared_ptr get_progress_tracker() = 0; + virtual kv::Tx create_tx() = 0; }; template @@ -111,6 +112,16 @@ namespace aft return nullptr; } + kv::Tx create_tx() override + { + auto p = x.lock(); + if (p) + { + return p->create_tx(); + } + throw std::logic_error("Can't create a tx without a store"); + } + S deserialise_views( const std::vector& data, bool public_only = false, diff --git a/src/consensus/aft/test/logging_stub.h b/src/consensus/aft/test/logging_stub.h index 15dfd3f62..9395d28a9 100644 --- a/src/consensus/aft/test/logging_stub.h +++ b/src/consensus/aft/test/logging_stub.h @@ -217,6 +217,11 @@ namespace aft { return nullptr; } + + kv::Tx create_tx() + { + return kv::Tx(); + } }; class LoggingStubStoreSig : public LoggingStubStore diff --git a/src/kv/store.h b/src/kv/store.h index bbc1f59ee..13e9e1019 100644 --- a/src/kv/store.h +++ b/src/kv/store.h @@ -240,8 +240,19 @@ namespace kv return *result; } - // EXPERIMENTAL - DO NOT USE - // This API is for internal testing only, and may change or be removed + /** Get a map by name, iff it exists at the given version. + * + * This means a prior transaction must have created the map, and + * successfully committed at a version <= v. If this has not happened (the + * map has never been created, or never been committed, or committed at a + * later version) this will return nullptr. + * + * @param v Version at which the map must exist + * @param map_name Name of requested map + * + * @return Abstract shared-owning pointer to requested map, or nullptr if no + * such map exists + */ std::shared_ptr get_map( kv::Version v, const std::string& map_name) override { @@ -258,8 +269,16 @@ namespace kv return nullptr; } - // EXPERIMENTAL - DO NOT USE - // This API is for internal testing only, and may change or be removed + /** Transfer ownership of a dynamically created map to this Store. + * + * Should be called as part of the commit process, once a transaction is + * known to be conflict-free and has been assigned a unique Version. This + * publishes dynamically created Maps so they can be retrieved via get_map + * in future transactions. + * + * @param v Version at which map is being committed/created + * @param map Map to add + */ void add_dynamic_map( kv::Version v, const std::shared_ptr& map) override { diff --git a/src/kv/test/kv_bench.cpp b/src/kv/test/kv_bench.cpp index d621d8155..af85138b6 100644 --- a/src/kv/test/kv_bench.cpp +++ b/src/kv/test/kv_bench.cpp @@ -62,7 +62,7 @@ static void serialise(picobench::state& s) auto& map0 = kv_store.create("map0", SD); auto& map1 = kv_store.create("map1", SD); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [tx0, tx1] = tx.get_view(map0, map1); for (int i = 0; i < s.iterations(); i++) @@ -99,7 +99,7 @@ static void deserialise(picobench::state& s) auto& map1 = kv_store.create("map1", SD); kv_store2.clone_schema(kv_store); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [tx0, tx1] = tx.get_view(map0, map1); for (int i = 0; i < s.iterations(); i++) @@ -135,7 +135,7 @@ static void commit_latency(picobench::state& s) for (int i = 0; i < s.iterations(); i++) { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [tx0, tx1] = tx.get_view(map0, map1); for (int iTx = 0; iTx < S; iTx++) { @@ -174,7 +174,7 @@ static void ser_snap(picobench::state& s) fmt::format("map{}", i), kv::SecurityDomain::PRIVATE); } - kv::Tx tx; + auto tx = kv_store.create_tx(); for (int i = 0; i < s.iterations(); i++) { auto view = tx.get_view(*kv_store.get(fmt::format("map{}", i))); @@ -218,7 +218,7 @@ static void des_snap(picobench::state& s) kv_store2.clone_schema(kv_store); - kv::Tx tx; + auto tx = kv_store.create_tx(); for (int i = 0; i < s.iterations(); i++) { auto view = tx.get_view(*kv_store.get(fmt::format("map{}", i))); diff --git a/src/kv/test/kv_contention.cpp b/src/kv/test/kv_contention.cpp index b62b4ee35..071e0a29d 100644 --- a/src/kv/test/kv_contention.cpp +++ b/src/kv/test/kv_contention.cpp @@ -80,7 +80,7 @@ DOCTEST_TEST_CASE("Concurrent kv access" * doctest::test_suite("concurrency")) try { // Start a transaction over selected maps - kv::Tx tx; + auto tx = args->kv_store->create_tx(); std::vector views; for (const auto map : args->maps) diff --git a/src/kv/test/kv_dynamic_tables.cpp b/src/kv/test/kv_dynamic_tables.cpp index ce848f57f..8201605e4 100644 --- a/src/kv/test/kv_dynamic_tables.cpp +++ b/src/kv/test/kv_dynamic_tables.cpp @@ -33,7 +33,7 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic")) { auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); view->put("foo", "bar"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -54,7 +54,7 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic")) INFO("New style access"); auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); const auto it = view->get("foo"); REQUIRE(it.has_value()); REQUIRE(it.value() == "bar"); @@ -66,7 +66,7 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic")) auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); const auto it = view->get("foo"); REQUIRE(it.has_value()); REQUIRE(it.value() == "bar"); @@ -82,24 +82,24 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic")) INFO("Multiple dynamic tables can be created in a single tx"); auto tx = kv_store.create_tx(); - auto [v1, v2] = tx.get_view2( + auto [v1, v2] = tx.get_view( new_map1, new_map2); - auto [v2a, v3] = tx.get_view2( - new_map2, new_map3); + auto [v2a, v3] = + tx.get_view(new_map2, new_map3); REQUIRE(v2 == v2a); v1->put("foo", "bar"); v3->put(42, "hello"); - auto va = tx.get_view2(map_name); + auto va = tx.get_view(map_name); va->put("foo", "baz"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); { auto check_tx = kv_store.create_tx(); - auto check_va = check_tx.get_view2(map_name); + auto check_va = check_tx.get_view(map_name); const auto v = check_va->get("foo"); REQUIRE(v.has_value()); REQUIRE(v.value() == "baz"); @@ -126,7 +126,7 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic")) { INFO("Retained dynamic maps have their state rolled back"); auto check_tx = kv_store.create_tx(); - auto check_va = check_tx.get_view2(map_name); + auto check_va = check_tx.get_view(map_name); const auto v = check_va->get("foo"); REQUIRE(v.has_value()); REQUIRE(v.value() == "bar"); @@ -146,11 +146,11 @@ TEST_CASE("Dynamic table opacity" * doctest::test_suite("dynamic")) auto tx1 = kv_store.create_tx(); auto tx2 = kv_store.create_tx(); - auto view1 = tx1.get_view2(map_name); + auto view1 = tx1.get_view(map_name); view1->put("foo", "bar"); REQUIRE(view1->get("foo").value() == "bar"); - auto view2 = tx2.get_view2(map_name); + auto view2 = tx2.get_view(map_name); view2->put("foo", "baz"); REQUIRE(view2->get("foo").value() == "baz"); @@ -167,7 +167,7 @@ TEST_CASE("Dynamic table opacity" * doctest::test_suite("dynamic")) { INFO("Committed transaction results are persisted"); auto txx = kv_store.create_tx(); - auto view = txx.get_view2(map_name); + auto view = txx.get_view(map_name); const auto v = view->get("foo"); REQUIRE(v.has_value()); REQUIRE(v.value() == "bar"); @@ -181,7 +181,7 @@ TEST_CASE("Dynamic table opacity" * doctest::test_suite("dynamic")) { INFO("Conflicting transaction can be rerun, on existing map"); auto tx3 = kv_store.create_tx(); - auto view3 = tx3.get_view2(map_name); + auto view3 = tx3.get_view(map_name); const auto v = view3->get("foo"); REQUIRE(v.has_value()); view3->put("foo", "baz"); @@ -197,7 +197,7 @@ TEST_CASE("Dynamic table opacity" * doctest::test_suite("dynamic")) { INFO("Subsequent transactions over dynamic map are persisted"); auto tx4 = kv_store.create_tx(); - auto view4 = tx4.get_view2(map_name); + auto view4 = tx4.get_view(map_name); const auto v = view4->get("foo"); REQUIRE(v.has_value()); REQUIRE(v.value() == "baz"); @@ -221,11 +221,11 @@ TEST_CASE( auto tx3 = kv_store.create_tx(); auto tx4 = kv_store.create_tx(); - auto view1 = tx1.get_view2(map_name); + auto view1 = tx1.get_view(map_name); view1->put("foo", "bar"); // Map created in tx1 is not visible - auto view2 = tx2.get_view2(map_name); + auto view2 = tx2.get_view(map_name); REQUIRE(!view2->get("foo").has_value()); // tx3 takes a read dependency at an early version, before the map is visible @@ -235,15 +235,74 @@ TEST_CASE( // Even after commit, the new map is not visible to tx3 because it is reading // from an earlier version - auto view3 = tx3.get_view2(map_name); + auto view3 = tx3.get_view(map_name); REQUIRE(!view3->get("foo").has_value()); // Map created in tx1 is visible, because tx4 first _reads_ (creates a // view) after tx1 has committed - auto view4 = tx4.get_view2(map_name); + auto view4 = tx4.get_view(map_name); REQUIRE(view4->get("foo").has_value()); } +TEST_CASE("Read only views" * doctest::test_suite("dynamic")) +{ + kv::Store kv_store; + + auto encryptor = std::make_shared(); + kv_store.set_encryptor(encryptor); + + constexpr auto dynamic_map_a = "dynamic_map_a"; + constexpr auto dynamic_map_b = "dynamic_map_b"; + + { + auto tx = kv_store.create_read_only_tx(); + auto va = tx.get_read_only_view(dynamic_map_a); + auto [vaa, vb, vbb] = tx.get_read_only_view< + MapTypes::StringString, + MapTypes::StringString, + MapTypes::StringString>(dynamic_map_a, dynamic_map_b, dynamic_map_b); + + REQUIRE(va != nullptr); + REQUIRE(vaa != nullptr); + REQUIRE(vb != nullptr); + REQUIRE(vbb != nullptr); + + REQUIRE(va == vaa); + REQUIRE(vb == vbb); + + REQUIRE(!va->get("foo").has_value()); + REQUIRE(!vb->get("foo").has_value()); + + REQUIRE(tx.commit() == kv::CommitSuccess::OK); + } + + { + auto tx = kv_store.create_tx(); + auto [va, vb] = tx.get_view( + dynamic_map_a, dynamic_map_b); + + va->put("foo", "bar"); + vb->put("foo", "baz"); + + REQUIRE(tx.commit() == kv::CommitSuccess::OK); + } + + { + auto tx = kv_store.create_read_only_tx(); + auto [va, vb] = + tx.get_read_only_view( + dynamic_map_a, dynamic_map_b); + + const auto foo_a = va->get("foo"); + REQUIRE(foo_a.has_value()); + REQUIRE(*foo_a == "bar"); + + const auto foo_b = vb->get("foo"); + REQUIRE(foo_b.has_value()); + REQUIRE(*foo_b == "baz"); + } +} + TEST_CASE("Mixed map dependencies" * doctest::test_suite("dynamic")) { kv::Store kv_store; @@ -261,8 +320,8 @@ TEST_CASE("Mixed map dependencies" * doctest::test_suite("dynamic")) auto tx1 = kv_store.create_tx(); auto tx2 = kv_store.create_tx(); - auto view1 = tx1.get_view2(dynamic_map_a); - auto view2 = tx2.get_view2(dynamic_map_b); + auto view1 = tx1.get_view(dynamic_map_a); + auto view2 = tx2.get_view(dynamic_map_b); view1->put(42, "hello"); view2->put("hello", 42); @@ -279,7 +338,7 @@ TEST_CASE("Mixed map dependencies" * doctest::test_suite("dynamic")) auto view1 = tx1.get_view(static_map); const auto v = view1->get(key); // Introduce read-dependency view1->put(key, "bar"); - auto dynamic_view = tx1.get_view2(dynamic_map_a); + auto dynamic_view = tx1.get_view(dynamic_map_a); dynamic_view->put(42, "hello world"); } @@ -288,7 +347,7 @@ TEST_CASE("Mixed map dependencies" * doctest::test_suite("dynamic")) auto view2 = tx2.get_view(static_map); const auto v = view2->get(key); // Introduce read-dependency view2->put(key, "bar"); - auto dynamic_view = tx2.get_view2(dynamic_map_b); + auto dynamic_view = tx2.get_view(dynamic_map_b); dynamic_view->put("hello world", 42); } @@ -299,7 +358,7 @@ TEST_CASE("Mixed map dependencies" * doctest::test_suite("dynamic")) auto tx3 = kv_store.create_tx(); auto [view1, view2] = - tx3.get_view2( + tx3.get_view( dynamic_map_a, dynamic_map_b); const auto v1 = view1->get(42); @@ -333,7 +392,7 @@ TEST_CASE("Dynamic map serialisation" * doctest::test_suite("dynamic")) { INFO("Commit a map creation in source store"); auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); view->put(key, value); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } @@ -348,7 +407,7 @@ TEST_CASE("Dynamic map serialisation" * doctest::test_suite("dynamic")) kv::DeserialiseSuccess::PASS); auto tx_target = kv_store_target.create_tx(); - auto view_target = tx_target.get_view2(map_name); + auto view_target = tx_target.get_view(map_name); const auto v = view_target->get(key); REQUIRE(v.has_value()); REQUIRE(v.value() == value); @@ -367,12 +426,12 @@ TEST_CASE("Dynamic map snapshot serialisation" * doctest::test_suite("dynamic")) INFO("Create maps in original store"); { auto tx1 = store.create_tx(); - auto view_1 = tx1.get_view2(map_name); + auto view_1 = tx1.get_view(map_name); view_1->put("foo", "foo"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); auto tx2 = store.create_tx(); - auto view_2 = tx2.get_view2(map_name); + auto view_2 = tx2.get_view(map_name); view_2->put("bar", "bar"); REQUIRE(tx2.commit() == kv::CommitSuccess::OK); @@ -390,7 +449,7 @@ TEST_CASE("Dynamic map snapshot serialisation" * doctest::test_suite("dynamic")) new_store.deserialise_snapshot(serialised_snapshot); auto tx = new_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); const auto foo_v = view->get("foo"); REQUIRE(foo_v.has_value()); @@ -416,7 +475,7 @@ TEST_CASE("Mid rollback safety" * doctest::test_suite("dynamic")) { auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); view->put("foo", "bar"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -424,7 +483,7 @@ TEST_CASE("Mid rollback safety" * doctest::test_suite("dynamic")) { auto tx = kv_store.create_tx(); - auto view = tx.get_view2(map_name); + auto view = tx.get_view(map_name); const auto v_0 = view->get("foo"); REQUIRE(v_0.has_value()); REQUIRE(v_0.value() == "bar"); @@ -437,7 +496,7 @@ TEST_CASE("Mid rollback safety" * doctest::test_suite("dynamic")) REQUIRE(v_0.has_value()); REQUIRE(v_0.value() == "bar"); - auto view_after = tx.get_view2(map_name); + auto view_after = tx.get_view(map_name); REQUIRE(view_after == view); view->put("foo", "baz"); @@ -457,7 +516,7 @@ TEST_CASE( { auto tx = kv_store.create_tx(); - auto view = tx.get_view2("public:foo"); + auto view = tx.get_view("public:foo"); view->put("foo", "bar"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -465,7 +524,7 @@ TEST_CASE( { auto tx = kv_store.create_tx(); - auto view = tx.get_view2("foo"); + auto view = tx.get_view("foo"); view->put("hello", "world"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -484,7 +543,7 @@ TEST_CASE( { auto tx = kv_store.create_tx(); auto [public_view, private_view] = - tx.get_view2( + tx.get_view( "public:foo", "foo"); // These are _different views_ over _different maps_ @@ -510,7 +569,7 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) { auto tx = s1.create_tx(); auto [v0, v1] = - tx.get_view2("foo", "bar"); + tx.get_view("foo", "bar"); v0->put("hello", "world"); v1->put(42, "everything"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -519,7 +578,7 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) { auto tx = s1.create_tx(); auto [v0, v1] = - tx.get_view2("foo", "baz"); + tx.get_view("foo", "baz"); v0->put("hello", "goodbye"); v1->put("saluton", 100); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -528,7 +587,7 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) { // Create _public_ state in source store auto tx = s1.create_tx(); - auto v0 = tx.get_view2("public:source_state"); + auto v0 = tx.get_view("public:source_state"); v0->put("store", "source"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } @@ -541,7 +600,7 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) { // Create public state in target store, to confirm it is unaffected auto tx = s2.create_tx(); - auto v0 = tx.get_view2("public:target_state"); + auto v0 = tx.get_view("public:target_state"); v0->put("store", "target"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } @@ -554,7 +613,7 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) INFO("Private state is transferred"); auto tx = s2.create_tx(); - auto [v0, v1, v2] = tx.get_view2< + auto [v0, v1, v2] = tx.get_view< MapTypes::StringString, MapTypes::NumString, MapTypes::StringNum>("foo", "bar", "baz"); @@ -576,9 +635,8 @@ TEST_CASE("Swapping dynamic maps" * doctest::test_suite("dynamic")) INFO("Public state is untouched"); auto tx = s2.create_tx(); - auto [v0, v1] = - tx.get_view2( - "public:source_state", "public:target_state"); + auto [v0, v1] = tx.get_view( + "public:source_state", "public:target_state"); const auto val0 = v0->get("store"); REQUIRE_FALSE(val0.has_value()); diff --git a/src/kv/test/kv_serialisation.cpp b/src/kv/test/kv_serialisation.cpp index 3c869eec0..cf9e1cd21 100644 --- a/src/kv/test/kv_serialisation.cpp +++ b/src/kv/test/kv_serialisation.cpp @@ -41,7 +41,7 @@ TEST_CASE( INFO("Commit to public map in source store"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view0 = tx.get_view(pub_map); view0->put("pubk1", "pubv1"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -56,7 +56,7 @@ TEST_CASE( kv_store_target.deserialise(latest_data.value()) == kv::DeserialiseSuccess::PASS); - kv::Tx tx_target; + auto tx_target = kv_store_target.create_tx(); auto view_target = tx_target.get_view(*target_map); REQUIRE(view_target->get("pubk1") == "pubv1"); } @@ -81,7 +81,7 @@ TEST_CASE( SUBCASE( "Commit a private transaction without an encryptor throws an exception") { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view0 = tx.get_view(priv_map); view0->put("privk1", "privv1"); REQUIRE_THROWS_AS(tx.commit(), kv::KvSerialiserException); @@ -92,7 +92,7 @@ TEST_CASE( kv_store.set_encryptor(encryptor); INFO("Commit to private map in source store"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view0 = tx.get_view(priv_map); view0->put("privk1", "privv1"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -106,7 +106,7 @@ TEST_CASE( kv_store_target.deserialise(latest_data.value()) == kv::DeserialiseSuccess::PASS); - kv::Tx tx_target; + auto tx_target = kv_store_target.create_tx(); auto view_target = tx_target.get_view(*target_map); REQUIRE(view_target->get("privk1") == "privv1"); } @@ -129,14 +129,15 @@ TEST_CASE( kv::Store kv_store_target; kv_store_target.set_encryptor(encryptor); kv_store_target.clone_schema(kv_store); - auto* target_priv_map = kv_store.get("priv_map"); - auto* target_pub_map = kv_store.get("pub_map"); + auto* target_priv_map = + kv_store_target.get("priv_map"); + auto* target_pub_map = kv_store_target.get("pub_map"); REQUIRE(target_priv_map != nullptr); REQUIRE(target_pub_map != nullptr); INFO("Commit to public and private map in source store"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [view_priv, view_pub] = tx.get_view(priv_map, pub_map); view_priv->put("privk1", "privv1"); @@ -153,8 +154,9 @@ TEST_CASE( kv_store_target.deserialise(latest_data.value()) != kv::DeserialiseSuccess::FAILED); - kv::Tx tx; - auto [view_priv, view_pub] = tx.get_view(*target_priv_map, *target_pub_map); + auto tx_target = kv_store_target.create_tx(); + auto [view_priv, view_pub] = + tx_target.get_view(*target_priv_map, *target_pub_map); REQUIRE(view_priv->get("privk1") == "privv1"); REQUIRE(view_pub->get("pubk1") == "pubv1"); @@ -179,7 +181,7 @@ TEST_CASE( INFO("Commit a new key in source store and deserialise in target store"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view_priv = tx.get_view(priv_map); view_priv->put("privk1", "privv1"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -190,20 +192,20 @@ TEST_CASE( kv_store_target.deserialise(latest_data.value()) != kv::DeserialiseSuccess::FAILED); - kv::Tx tx_target; + auto tx_target = kv_store_target.create_tx(); auto view_priv_target = tx_target.get_view(*target_priv_map); REQUIRE(view_priv_target->get("privk1") == "privv1"); } INFO("Commit key removal in source store and deserialise in target store"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view_priv = tx.get_view(priv_map); view_priv->remove("privk1"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); // Make sure it has been marked as deleted in source store - kv::Tx tx2; + auto tx2 = kv_store.create_tx(); auto view_priv2 = tx2.get_view(priv_map); REQUIRE(view_priv2->get("privk1").has_value() == false); @@ -213,7 +215,7 @@ TEST_CASE( kv_store_target.deserialise(latest_data.value()) != kv::DeserialiseSuccess::FAILED); - kv::Tx tx_target; + auto tx_target = kv_store_target.create_tx(); auto view_priv_target = tx_target.get_view(*target_priv_map); REQUIRE(view_priv_target->get("privk1").has_value() == false); } @@ -379,7 +381,7 @@ TEST_CASE_TEMPLATE( kv::Store kv_store2; auto& map2 = kv_store2.create("map", kv::SecurityDomain::PUBLIC); - kv::Tx tx(kv_store.next_version()); + auto tx = kv_store.create_reserved_tx(kv_store.next_version()); auto view = tx.get_view(map); view->put(k1, v1); view->put(k2, v2); @@ -389,7 +391,7 @@ TEST_CASE_TEMPLATE( kv_store.compact(kv_store.current_version()); REQUIRE(kv_store2.deserialise(data) == kv::DeserialiseSuccess::PASS); - kv::Tx tx2; + auto tx2 = kv_store2.create_tx(); auto view2 = tx2.get_view(map2); // operator== does not need to be defined for custom types. In this case it @@ -461,7 +463,7 @@ TEST_CASE("Integrity" * doctest::test_suite("serialisation")) kv_store_target.clone_schema(kv_store); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [public_view, private_view] = tx.get_view(public_map, private_map); std::string pub_value = "pubv1"; public_view->put("pubk1", pub_value); @@ -496,7 +498,7 @@ TEST_CASE("nlohmann (de)serialisation" * doctest::test_suite("serialisation")) auto& t = s0.create
("t", kv::SecurityDomain::PUBLIC); s1.create
("t"); - kv::Tx tx; + auto tx = s0.create_tx(); tx.get_view(t)->put(k1, v1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -514,7 +516,7 @@ TEST_CASE("nlohmann (de)serialisation" * doctest::test_suite("serialisation")) auto& t = s0.create
("t", kv::SecurityDomain::PUBLIC); s1.create
("t"); - kv::Tx tx; + auto tx = s0.create_tx(); tx.get_view(t)->put(k0, v0); tx.get_view(t)->put(k1, v1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -561,7 +563,7 @@ TEST_CASE( REQUIRE(second_data_derived_private != nullptr); { - kv::Tx tx(store.next_version()); + auto tx = store.create_reserved_tx(store.next_version()); auto [data_view_r, data_view_r_p, data_view_d, data_view_d_p] = tx.get_view( data_replicated, @@ -581,7 +583,7 @@ TEST_CASE( { REQUIRE( kv_store_target.deserialise(data) == kv::DeserialiseSuccess::PASS); - kv::Tx tx; + auto tx = kv_store_target.create_tx(); auto [data_view_r, data_view_r_p, data_view_d, data_view_d_p] = tx.get_view( *second_data_replicated, @@ -642,13 +644,13 @@ TEST_CASE("Exceptional serdes" * doctest::test_suite("serialisation")) NonSerialiser>>("bad_map_v"); { - kv::Tx tx; + auto tx = store.create_tx(); auto bad_view = tx.get_view(bad_map_k); REQUIRE_THROWS(bad_view->put({}, 0)); } { - kv::Tx tx; + auto tx = store.create_tx(); auto bad_view = tx.get_view(bad_map_v); REQUIRE_THROWS(bad_view->put(0, {})); } diff --git a/src/kv/test/kv_snapshot.cpp b/src/kv/test/kv_snapshot.cpp index e181431f9..332d93f52 100644 --- a/src/kv/test/kv_snapshot.cpp +++ b/src/kv/test/kv_snapshot.cpp @@ -27,19 +27,19 @@ TEST_CASE("Simple snapshot" * doctest::test_suite("snapshot")) INFO("Apply transactions to original store"); { - kv::Tx tx1; + auto tx1 = store.create_tx(); auto view_1 = tx1.get_view(string_map); view_1->put("foo", "bar"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); first_snapshot_version = tx1.commit_version(); - kv::Tx tx2; + auto tx2 = store.create_tx(); auto view_2 = tx2.get_view(num_map); view_2->put(42, 123); REQUIRE(tx2.commit() == kv::CommitSuccess::OK); second_snapshot_version = tx2.commit_version(); - kv::Tx tx3; + auto tx3 = store.create_tx(); auto view_3 = tx1.get_view(string_map); view_3->put("key", "not committed"); // Do not commit tx3 @@ -62,7 +62,7 @@ TEST_CASE("Simple snapshot" * doctest::test_suite("snapshot")) auto new_string_map = new_store.get("string_map"); auto new_num_map = new_store.get("num_map"); - kv::Tx tx1; + auto tx1 = new_store.create_tx(); auto view = tx1.get_view(*new_string_map); auto v = view->get("foo"); REQUIRE(v.has_value()); @@ -92,7 +92,7 @@ TEST_CASE("Simple snapshot" * doctest::test_suite("snapshot")) new_store.deserialise_snapshot(second_serialised_snapshot); REQUIRE_EQ(new_store.current_version(), 2); - kv::Tx tx1; + auto tx1 = new_store.create_tx(); auto view = tx1.get_view(*new_string_map); auto v = view->get("foo"); @@ -121,12 +121,12 @@ TEST_CASE( kv::Version snapshot_version = kv::NoVersion; INFO("Apply transactions to original store"); { - kv::Tx tx1; + auto tx1 = store.create_tx(); auto view_1 = tx1.get_view(string_map); view_1->put("foo", "foo"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); // Committed at 1 - kv::Tx tx2; + auto tx2 = store.create_tx(); auto view_2 = tx2.get_view(string_map); view_2->put("bar", "bar"); REQUIRE(tx2.commit() == kv::CommitSuccess::OK); // Committed at 2 @@ -142,7 +142,7 @@ TEST_CASE( new_store.clone_schema(store); auto new_string_map = new_store.get("string_map"); - kv::Tx tx; + auto tx = new_store.create_tx(); auto view = tx.get_view(*new_string_map); view->put("in", "flight"); // tx is not committed until the snapshot is deserialised @@ -168,14 +168,14 @@ TEST_CASE("Commit hooks with snapshot" * doctest::test_suite("snapshot")) kv::Version snapshot_version = kv::NoVersion; INFO("Apply transactions to original store"); { - kv::Tx tx1; + auto tx1 = store.create_tx(); auto view_1 = tx1.get_view(string_map); view_1->put("foo", "foo"); view_1->put("bar", "bar"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); // Committed at 1 // New transaction, deleting content from the previous transaction - kv::Tx tx2; + auto tx2 = store.create_tx(); auto view_2 = tx2.get_view(string_map); view_2->put("baz", "baz"); view_2->remove("bar"); @@ -213,7 +213,7 @@ TEST_CASE("Commit hooks with snapshot" * doctest::test_suite("snapshot")) INFO("Verify content of snapshot"); { - kv::Tx tx; + auto tx = new_store.create_tx(); auto view = tx.get_view(*new_string_map); REQUIRE(view->get("foo").has_value()); REQUIRE(!view->get("bar").has_value()); diff --git a/src/kv/test/kv_test.cpp b/src/kv/test/kv_test.cpp index 155b0791c..1163eba4e 100644 --- a/src/kv/test/kv_test.cpp +++ b/src/kv/test/kv_test.cpp @@ -77,14 +77,14 @@ TEST_CASE("Reads/writes and deletions") INFO("Start empty transaction"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); REQUIRE(tx.commit() == kv::CommitSuccess::OK); REQUIRE_THROWS_AS(tx.commit(), std::logic_error); } INFO("Read own writes"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); auto v = view->get(k); REQUIRE(!v.has_value()); @@ -97,7 +97,7 @@ TEST_CASE("Reads/writes and deletions") INFO("Read previous writes"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); auto v = view->get(k); REQUIRE(v.has_value()); @@ -107,8 +107,8 @@ TEST_CASE("Reads/writes and deletions") INFO("Remove keys"); { - kv::Tx tx; - kv::Tx tx2; + auto tx = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); auto view = tx.get_view(map); view->put(k, v1); @@ -125,9 +125,9 @@ TEST_CASE("Reads/writes and deletions") INFO("Remove key that was deleted from state"); { - kv::Tx tx; - kv::Tx tx2; - kv::Tx tx3; + auto tx = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); + auto tx3 = kv_store.create_tx(); auto view = tx.get_view(map); view->put(k, v1); auto va = view->get_globally_committed(k); @@ -161,7 +161,7 @@ TEST_CASE("foreach") SUBCASE("Empty map") { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->foreach(store_iterated); REQUIRE(iterated_entries.empty()); @@ -169,7 +169,7 @@ TEST_CASE("foreach") SUBCASE("Reading own writes") { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); @@ -181,7 +181,7 @@ TEST_CASE("foreach") iterated_entries.clear(); INFO("Uncommitted writes from other txs are not visible"); - kv::Tx tx2; + auto tx2 = kv_store.create_tx(); auto view2 = tx2.get_view(map); view2->foreach(store_iterated); REQUIRE(iterated_entries.empty()); @@ -189,13 +189,13 @@ TEST_CASE("foreach") SUBCASE("Reading committed writes") { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); - kv::Tx tx2; + auto tx2 = kv_store.create_tx(); auto view2 = tx2.get_view(map); view2->foreach(store_iterated); REQUIRE(iterated_entries.size() == 2); @@ -205,13 +205,13 @@ TEST_CASE("foreach") SUBCASE("Mix of committed and own writes") { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); - kv::Tx tx2; + auto tx2 = kv_store.create_tx(); auto view2 = tx2.get_view(map); view2->put("key2", "replaced2"); view2->put("key3", "value3"); @@ -225,7 +225,7 @@ TEST_CASE("foreach") SUBCASE("Deletions") { { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); @@ -234,14 +234,14 @@ TEST_CASE("foreach") } { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->remove("key1"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->foreach(store_iterated); REQUIRE(iterated_entries.size() == 2); @@ -270,7 +270,7 @@ TEST_CASE("foreach") SUBCASE("Early termination") { { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); @@ -286,7 +286,7 @@ TEST_CASE("foreach") } { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key4", "value4"); view->put("key5", "value5"); @@ -333,7 +333,7 @@ TEST_CASE("Read-only tx") INFO("Write some keys"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); auto v = view->get(k); REQUIRE(!v.has_value()); @@ -346,7 +346,7 @@ TEST_CASE("Read-only tx") INFO("Do only reads with an overpowered Tx"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_read_only_view(map); const auto v = view->get(k); REQUIRE(v.has_value()); @@ -362,7 +362,7 @@ TEST_CASE("Read-only tx") INFO("Read with read-only tx"); { - kv::ReadOnlyTx tx; + auto tx = kv_store.create_read_only_tx(); auto view = tx.get_read_only_view(map); const auto v = view->get(k); REQUIRE(v.has_value()); @@ -388,8 +388,8 @@ TEST_CASE("Rollback and compact") INFO("Do not read transactions that have been rolled back"); { - kv::Tx tx; - kv::Tx tx2; + auto tx = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); auto view = tx.get_view(map); view->put(k, v1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -403,8 +403,8 @@ TEST_CASE("Rollback and compact") INFO("Read committed key"); { - kv::Tx tx; - kv::Tx tx2; + auto tx = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); auto view = tx.get_view(map); view->put(k, v1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -418,8 +418,8 @@ TEST_CASE("Rollback and compact") INFO("Read deleted committed key"); { - kv::Tx tx; - kv::Tx tx2; + auto tx = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); auto view = tx.get_view(map); REQUIRE(view->remove(k)); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -452,7 +452,7 @@ TEST_CASE("Local commit hooks") INFO("Write with hooks"); { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key1", "value1"); view->put("key2", "value2"); @@ -476,7 +476,7 @@ TEST_CASE("Local commit hooks") map.unset_local_hook(); map.unset_global_hook(); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->put("key2", "value2"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -490,7 +490,7 @@ TEST_CASE("Local commit hooks") map.set_local_hook(local_hook); map.set_global_hook(global_hook); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); view->remove("key2"); view->put("key3", "value3"); @@ -547,7 +547,7 @@ TEST_CASE("Global commit hooks") SUBCASE("Compact one transaction") { - kv::Tx tx1; + auto tx1 = kv_store.create_tx(); auto view_hook = tx1.get_view(map_with_hook); view_hook->put("key1", "value1"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); @@ -565,7 +565,9 @@ TEST_CASE("Global commit hooks") SUBCASE("Compact beyond the last map version") { - kv::Tx tx1, tx2, tx3; + auto tx1 = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); + auto tx3 = kv_store.create_tx(); auto view_hook = tx1.get_view(map_with_hook); view_hook->put("key1", "value1"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); @@ -600,7 +602,9 @@ TEST_CASE("Global commit hooks") SUBCASE("Compact in between two map versions") { - kv::Tx tx1, tx2, tx3; + auto tx1 = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); + auto tx3 = kv_store.create_tx(); auto view_hook = tx1.get_view(map_with_hook); view_hook->put("key1", "value1"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); @@ -631,7 +635,8 @@ TEST_CASE("Global commit hooks") SUBCASE("Compact twice") { - kv::Tx tx1, tx2; + auto tx1 = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); auto view_hook = tx1.get_view(map_with_hook); view_hook->put("key1", "value1"); REQUIRE(tx1.commit() == kv::CommitSuccess::OK); @@ -664,7 +669,7 @@ TEST_CASE("Clone schema") auto& public_map = store.create("public", kv::SecurityDomain::PUBLIC); auto& private_map = store.create("private"); - kv::Tx tx1(store.next_version()); + auto tx1 = store.create_reserved_tx(store.next_version()); auto [view1, view2] = tx1.get_view(public_map, private_map); view1->put(42, "aardvark"); view2->put(14, "alligator"); @@ -696,7 +701,7 @@ TEST_CASE("Deserialise return status") store.set_history(history); { - kv::Tx tx(store.next_version()); + auto tx = store.create_reserved_tx(store.next_version()); auto data_view = tx.get_view(data); data_view->put(42, 42); auto [success, reqid, data] = tx.commit_reserved(); @@ -706,7 +711,7 @@ TEST_CASE("Deserialise return status") } { - kv::Tx tx(store.next_version()); + auto tx = store.create_reserved_tx(store.next_version()); auto sig_view = tx.get_view(signatures); ccf::PrimarySignature sigv(0, 2, {0}); sig_view->put(0, sigv); @@ -718,7 +723,7 @@ TEST_CASE("Deserialise return status") INFO("Signature transactions with additional contents should fail"); { - kv::Tx tx(store.next_version()); + auto tx = store.create_reserved_tx(store.next_version()); auto [sig_view, data_view] = tx.get_view(signatures, data); ccf::PrimarySignature sigv(0, 2, {0}); sig_view->put(0, sigv); @@ -747,14 +752,14 @@ TEST_CASE("Map swap between stores") s2.create("public_data", kv::SecurityDomain::PUBLIC); { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(d1); v->put(42, 42); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pd1); v->put(14, 14); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -763,7 +768,7 @@ TEST_CASE("Map swap between stores") const auto target_version = s1.current_version(); while (s2.current_version() < target_version) { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(d2); v->put(41, 41); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -772,7 +777,7 @@ TEST_CASE("Map swap between stores") s2.swap_private_maps(s1); { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(d1); auto val = v->get(41); REQUIRE_FALSE(v->get(42).has_value()); @@ -781,7 +786,7 @@ TEST_CASE("Map swap between stores") } { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pd1); auto val = v->get(14); REQUIRE(val.has_value()); @@ -789,7 +794,7 @@ TEST_CASE("Map swap between stores") } { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(d2); auto val = v->get(42); REQUIRE_FALSE(v->get(41).has_value()); @@ -798,7 +803,7 @@ TEST_CASE("Map swap between stores") } { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(pd2); REQUIRE_FALSE(v->get(14).has_value()); } @@ -823,27 +828,27 @@ TEST_CASE("Private recovery map swap") // We compact twice, deliberately. A public KV during recovery // would have compacted some number of times. { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pub1); v->put(42, "42"); tx.commit(); } { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pub1); v->put(42, "43"); tx.commit(); } s1.compact(s1.current_version()); { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pub1); v->put(44, "44"); tx.commit(); } s1.compact(s1.current_version()); { - kv::Tx tx; + auto tx = s1.create_tx(); auto v = tx.get_view(pub1); v->put(45, "45"); tx.commit(); @@ -854,26 +859,26 @@ TEST_CASE("Private recovery map swap") // KV, which is what we expect during recovery of the private KV. We do expect // that the _entire_ private state is compacted { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(priv2); v->put(12, 12); tx.commit(); } { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(priv2); v->put(13, 13); tx.commit(); } s2.compact(s2.current_version()); { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(priv2); v->put(14, 14); tx.commit(); } { - kv::Tx tx; + auto tx = s2.create_tx(); auto v = tx.get_view(priv2); v->put(15, 15); tx.commit(); @@ -885,7 +890,7 @@ TEST_CASE("Private recovery map swap") INFO("Check state looks as expected in s1"); { - kv::Tx tx; + auto tx = s1.create_tx(); auto [priv, pub] = tx.get_view(priv1, pub1); { auto val = pub->get(42); @@ -914,7 +919,7 @@ TEST_CASE("Private recovery map swap") INFO("Check committed state looks as expected in s1"); { - kv::Tx tx; + auto tx = s1.create_tx(); auto [priv, pub] = tx.get_view(priv1, pub1); { auto val = pub->get_globally_committed(42); @@ -965,7 +970,7 @@ TEST_CASE("Conflict resolution") auto confirm_state = [&]( const std::vector& present, const std::vector& missing) { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view = tx.get_view(map); for (const auto& s : present) @@ -983,8 +988,8 @@ TEST_CASE("Conflict resolution") }; // Simulate parallel execution by interleaving tx steps - kv::Tx tx1; - kv::Tx tx2; + auto tx1 = kv_store.create_tx(); + auto tx2 = kv_store.create_tx(); // First transaction tries to write a value, depending on initial version try_write(tx1, "bar"); @@ -1028,7 +1033,7 @@ TEST_CASE("Mid-tx compaction") constexpr auto key_b = "b"; auto increment_vals = [&]() { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto [view_a, view_b] = tx.get_view(map_a, map_b); auto a_opt = view_a->get(key_a); @@ -1049,7 +1054,7 @@ TEST_CASE("Mid-tx compaction") { INFO("Compaction before get_views"); - kv::Tx tx; + auto tx = kv_store.create_tx(); increment_vals(); kv_store.compact(kv_store.current_version()); @@ -1068,7 +1073,7 @@ TEST_CASE("Mid-tx compaction") { INFO("Compaction after get_views"); - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view_a = tx.get_view(map_a); increment_vals(); @@ -1090,7 +1095,7 @@ TEST_CASE("Mid-tx compaction") try { - kv::Tx tx; + auto tx = kv_store.create_tx(); auto view_a = tx.get_view(map_a); // This transaction does something slow. Meanwhile... diff --git a/src/kv/tx.h b/src/kv/tx.h index 8f0fb1fcb..eca1f533d 100644 --- a/src/kv/tx.h +++ b/src/kv/tx.h @@ -66,7 +66,7 @@ namespace kv } template - std::tuple get_tuple(M& m) + std::tuple get_tuple_old(M& m) { using MapView = typename M::TxView; @@ -110,11 +110,13 @@ namespace kv } template - std::tuple get_tuple2(const std::string& map_name) + std::tuple get_view_tuple_by_name( + const std::string& map_name) { if (store == nullptr) { - throw std::logic_error("New form called on old-style Tx"); + CCF_ASSERT( + false, "Cannot retrieve view: New form called on old-style Tx"); } using MapView = typename M::TxView; @@ -199,18 +201,35 @@ namespace kv } template - std::tuple get_tuple( - M& m, Ms&... ms) + std::tuple + get_view_tuple_by_types(M& m, Ms&... ms) { - return std::tuple_cat(get_tuple(m), get_tuple(ms...)); + if constexpr (sizeof...(Ms) == 0) + { + return get_view_tuple_by_name(m.get_name()); + } + else + { + return std::tuple_cat( + get_view_tuple_by_name(m.get_name()), + get_view_tuple_by_types(ms...)); + } } template - std::tuple get_tuple2( - const std::string& map_names, const Ts&... names) + std::tuple + get_view_tuple_by_names(const std::string& map_name, const Ts&... names) { - return std::tuple_cat( - get_tuple2(map_names), get_tuple2(names...)); + if constexpr (sizeof...(Ts) == 0) + { + return get_view_tuple_by_name(map_name); + } + else + { + return std::tuple_cat( + get_view_tuple_by_name(map_name), + get_view_tuple_by_names(names...)); + } } public: @@ -476,7 +495,20 @@ namespace kv template typename M::ReadOnlyTxView* get_read_only_view(M& m) { - return std::get<0>(get_tuple(m)); + return std::get<0>(get_view_tuple_by_name(m.get_name())); + } + + /** Get a read-only transaction view on a map by name. + * + * This adds the map to the transaction set if it is not yet present, and + * creates the map if it does not yet exist. + * + * @param map_name Name of map + */ + template + typename M::ReadOnlyTxView* get_read_only_view(const std::string& map_name) + { + return std::get<0>(get_view_tuple_by_name(map_name)); } /** Get read-only transaction views over multiple maps. @@ -488,7 +520,24 @@ namespace kv std::tuple get_read_only_view(M& m, Ms&... ms) { - return std::tuple_cat(get_tuple(m), get_tuple(ms...)); + return std::tuple_cat( + get_view_tuple_by_name(m.get_name()), + get_view_tuple_by_types(ms...)); + } + + /** Get read-only transaction views over multiple maps by name. This will + * create the maps if they do not exist. + * + * @param map_name Name of first map to retrieve + * @param names Names of additional maps + */ + template + std::tuple get_read_only_view( + const std::string& map_name, const Ts&... names) + { + return std::tuple_cat( + get_view_tuple_by_name(map_name), + get_view_tuple_by_names(names...)); } }; @@ -497,6 +546,13 @@ namespace kv public: using ReadOnlyTx::ReadOnlyTx; + // TEMPORARY - DO NOT USE + template + typename M::TxView* get_view_old(M& m) + { + return std::get<0>(get_tuple_old(m)); + } + /** Get a transaction view on a map. * * This adds the map to the transaction set if it is not yet present. @@ -506,15 +562,20 @@ namespace kv template typename M::TxView* get_view(M& m) { - return std::get<0>(get_tuple(m)); + return std::get<0>(get_view_tuple_by_name(m.get_name())); } - // EXPERIMENTAL - DO NOT USE - // This API is for internal testing only, and may change or be removed + /** Get a transaction view on a map by name + * + * This adds the map to the transaction set if it is not yet present, and + * creates the map if it does not yet exist. + * + * @param map_name Name of map + */ template - typename M::TxView* get_view2(const std::string& map_name) + typename M::TxView* get_view(const std::string& map_name) { - return std::get<0>(get_tuple2(map_name)); + return std::get<0>(get_view_tuple_by_name(map_name)); } /** Get transaction views over multiple maps. @@ -526,17 +587,24 @@ namespace kv std::tuple get_view( M& m, Ms&... ms) { - return std::tuple_cat(get_tuple(m), get_tuple(ms...)); + return std::tuple_cat( + get_view_tuple_by_name(m.get_name()), + get_view_tuple_by_types(ms...)); } - // EXPERIMENTAL - DO NOT USE - // This API is for internal testing only, and may change or be removed + /** Get transaction views over multiple maps by name. This will create the + * maps if they do not exist. + * + * @param map_name Name of first map to retrieve + * @param names Names of additional maps + */ template - std::tuple get_view2( + std::tuple get_view( const std::string& map_name, const Ts&... names) { return std::tuple_cat( - get_tuple2(map_name), get_tuple2(names...)); + get_view_tuple_by_name(map_name), + get_view_tuple_by_names(names...)); } }; diff --git a/src/lua_interp/test/lua_kv.cpp b/src/lua_interp/test/lua_kv.cpp index b0a7288a1..4f23f8cad 100644 --- a/src/lua_interp/test/lua_kv.cpp +++ b/src/lua_interp/test/lua_kv.cpp @@ -34,7 +34,7 @@ namespace ccf kv::Store tables; auto& table = tables.create("test", kv::SecurityDomain::PUBLIC); - kv::Tx txs; + auto txs = tables.create_tx(); const auto a = "Alice"; const auto b = "Bob"; @@ -129,7 +129,7 @@ namespace ccf { tables.compact(tables.current_version()); - kv::Tx next_txs; + auto next_txs = tables.create_tx(); auto next_tx = next_txs.get_view(table); REQUIRE(next_tx->put(k, s1)); @@ -166,7 +166,7 @@ namespace ccf auto& is = tables.create("test_is", kv::SecurityDomain::PUBLIC); auto& sb = tables.create("test_sb", kv::SecurityDomain::PUBLIC); - kv::Tx txs; + auto txs = tables.create_tx(); auto tx = txs.get_view(ii, is, sb); auto tx_ii = get<0>(tx); auto tx_is = get<1>(tx); @@ -233,7 +233,7 @@ namespace ccf kv::Store tables; auto& table = tables.create("v"); - kv::Tx txs; + auto txs = tables.create_tx(); auto tx = txs.get_view(table); tx->put(vector(100, 1), 123); @@ -337,7 +337,7 @@ namespace ccf kv::Store tables; auto& table = tables.create("t", kv::SecurityDomain::PUBLIC); - kv::Tx txs; + auto txs = tables.create_tx(); auto tx = txs.get_view(table); auto create = [tx](int dst, int amt) { @@ -397,7 +397,7 @@ namespace ccf kv::Store tables; auto& table = tables.create("t", kv::SecurityDomain::PUBLIC); - kv::Tx txs; + auto txs = tables.create_tx(); auto tx = txs.get_view(table); Interpreter li; diff --git a/src/node/historical_queries.h b/src/node/historical_queries.h index e2fabc67e..f91cba8d0 100644 --- a/src/node/historical_queries.h +++ b/src/node/historical_queries.h @@ -94,7 +94,7 @@ namespace ccf::historical std::optional get_signature( const StorePtr& sig_store) { - kv::Tx tx; + auto tx = sig_store->create_tx(); auto sig_table = sig_store->get(ccf::Tables::SIGNATURES); if (sig_table == nullptr) { @@ -112,7 +112,7 @@ namespace ccf::historical // This only works while entries are never deleted from this table, and // makes no check that the signing node was active at the point it // produced this signature - kv::Tx tx; + auto tx = source_store.create_tx(); auto nodes_table = source_store.get(ccf::Tables::NODES); if (nodes_table == nullptr) diff --git a/src/node/history.h b/src/node/history.h index 4e944b8da..938ef1d70 100644 --- a/src/node/history.h +++ b/src/node/history.h @@ -140,7 +140,7 @@ namespace ccf store.commit( txid, [txid, this]() { - kv::Tx sig(txid.version); + auto sig = store.create_reserved_tx(txid.version); auto sig_view = sig.get_view(signatures); PrimarySignature sig_value(id, txid.version, {0}); sig_view->put(0, sig_value); @@ -537,7 +537,7 @@ namespace ccf // The history can be initialised after a snapshot has been applied by // deserialising the tree in the signatures table and then applying the // hash of the transaction at which the snapshot was taken - kv::ReadOnlyTx tx; + auto tx = store.create_read_only_tx(); auto sig_tv = tx.get_read_only_view(signatures); auto sig = sig_tv->get(0); if (!sig.has_value()) @@ -605,7 +605,7 @@ namespace ccf bool verify( kv::Term* term = nullptr, PrimarySignature* signature = nullptr) override { - kv::Tx tx; + auto tx = store.create_tx(); auto [sig_tv, ni_tv] = tx.get_view(signatures, nodes); auto sig = sig_tv->get(0); if (!sig.has_value()) @@ -697,7 +697,7 @@ namespace ccf store.commit( txid, [txid, commit_txid, this]() { - kv::Tx sig(txid.version); + auto sig = store.create_reserved_tx(txid.version); auto sig_view = sig.get_view(signatures); crypto::Sha256Hash root = replicated_state_tree.get_root(); diff --git a/src/node/node_state.h b/src/node/node_state.h index a7db92862..0158ad4fe 100644 --- a/src/node/node_state.h +++ b/src/node/node_state.h @@ -469,7 +469,7 @@ namespace ccf fmt::format("Failed to apply snapshot on join: {}", rc)); } - kv::ReadOnlyTx tx; + auto tx = network.tables->create_read_only_tx(); auto sig_view = tx.get_read_only_view(network.signatures); auto sig = sig_view->get(0); if (!sig.has_value()) @@ -634,7 +634,7 @@ namespace ccf if (result == kv::DeserialiseSuccess::PASS_SIGNATURE) { network.tables->compact(ledger_idx); - kv::Tx tx; + auto tx = network.tables->create_tx(); GenesisGenerator g(network, tx); auto last_sig = g.get_last_signature(); if (last_sig.has_value()) @@ -688,7 +688,7 @@ namespace ccf LOG_INFO_FMT("Setting term on public recovery KV to {}", new_term); network.tables->set_term(new_term); - kv::Tx tx; + auto tx = network.tables->create_tx(); GenesisGenerator g(network, tx); g.create_service(network.identity->cert); g.retire_active_nodes(); @@ -722,10 +722,9 @@ namespace ccf h->set_node_id(self); } - auto p = dynamic_cast(progress_tracker.get()); - if (p) + if (progress_tracker != nullptr) { - p->set_node_id(self); + progress_tracker->set_node_id(self); } setup_raft(true); @@ -833,7 +832,7 @@ namespace ccf // Open the service if (consensus->is_primary()) { - kv::Tx tx; + auto tx = network.tables->create_tx(); // Shares for the new ledger secret can only be issued now, once the // previous ledger secrets have been recovered diff --git a/src/node/progress_tracker.h b/src/node/progress_tracker.h index 42cbc3cc4..9ff82f7d0 100644 --- a/src/node/progress_tracker.h +++ b/src/node/progress_tracker.h @@ -363,7 +363,7 @@ namespace ccf uint8_t* sig) { kv::Tx tx; - auto ni_tv = tx.get_view(nodes); + auto ni_tv = tx.get_view_old(nodes); auto ni = ni_tv->get(node_id); if (!ni.has_value()) diff --git a/src/node/rpc/frontend.h b/src/node/rpc/frontend.h index b4284e0b1..8c6dccd76 100644 --- a/src/node/rpc/frontend.h +++ b/src/node/rpc/frontend.h @@ -144,7 +144,7 @@ namespace ccf if ((nodes != nullptr) && (consensus != nullptr)) { NodeId primary_id = consensus->primary(); - kv::Tx tx; + auto tx = tables.create_tx(); auto nodes_view = tx.get_view(*nodes); auto info = nodes_view->get(primary_id); diff --git a/src/node/rpc/test/frontend_test.cpp b/src/node/rpc/test/frontend_test.cpp index 7d61693be..54ad0c743 100644 --- a/src/node/rpc/test/frontend_test.cpp +++ b/src/node/rpc/test/frontend_test.cpp @@ -405,7 +405,7 @@ nlohmann::json parse_response_body( std::optional get_signed_req( NetworkState& network, CallerId caller_id) { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto client_sig_view = tx.get_view(network.user_client_signatures); return client_sig_view->get(caller_id); } @@ -457,7 +457,7 @@ void prepare_callers(NetworkState& network) auto backup_consensus = std::make_shared(); network.tables->set_consensus(backup_consensus); - kv::Tx tx; + auto tx = network.tables->create_tx(); network.tables->set_encryptor(encryptor); GenesisGenerator g(network, tx); @@ -472,7 +472,7 @@ void prepare_callers(NetworkState& network) void add_callers_pbft_store() { - kv::Tx gen_tx; + auto gen_tx = pbft_network.tables->create_tx(); pbft_network.tables->set_encryptor(encryptor); pbft_network.tables->set_history(history); auto backup_consensus = @@ -508,7 +508,7 @@ TEST_CASE("process_pbft") ctx->execute_on_node = true; frontend.process_pbft(ctx); - kv::Tx tx; + auto tx = pbft_network.tables->create_tx(); auto pbft_requests_map = tx.get_view(pbft_network.pbft_requests_map); auto request_value = pbft_requests_map->get(0); REQUIRE(request_value.has_value()); @@ -988,7 +988,7 @@ TEST_CASE("Explicit commitability") size_t next_value = 0; auto get_value = [&]() { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto view = tx.get_view(frontend.values); auto actual_v = view->get(0).value(); return actual_v; @@ -996,7 +996,7 @@ TEST_CASE("Explicit commitability") // Set initial value { - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(frontend.values)->put(0, next_value); REQUIRE(tx.commit() == kv::CommitSuccess::OK); } @@ -1370,7 +1370,7 @@ TEST_CASE("Forwarding" * doctest::test_suite("forwarding")) user_frontend_primary.process_forwarded(fwd_ctx); - kv::Tx tx; + auto tx = network_primary.tables->create_tx(); auto client_sig_view = tx.get_view(network_primary.user_client_signatures); auto client_sig = client_sig_view->get(user_id); REQUIRE(client_sig.has_value()); @@ -1549,7 +1549,7 @@ public: { // Warning: Never do this in a real application! // Create another transaction that conflicts with the frontend one - kv::Tx tx; + auto tx = this->tables.create_tx(); auto view = tx.get_view(values); view->put(0, 42); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -1575,7 +1575,7 @@ TEST_CASE("Signature is stored even after conflicts") INFO("Check that no client signatures have been recorded"); { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto client_signatures_view = tx.get_view(network.user_client_signatures); REQUIRE_FALSE(client_signatures_view->get(0).has_value()); } @@ -1593,7 +1593,7 @@ TEST_CASE("Signature is stored even after conflicts") INFO("Check that a client signatures have been recorded"); { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto client_signatures_view = tx.get_view(network.user_client_signatures); REQUIRE(client_signatures_view->get(0).has_value()); } diff --git a/src/node/rpc/test/member_voting_test.cpp b/src/node/rpc/test/member_voting_test.cpp index e4f2f9799..3b4c2124c 100644 --- a/src/node/rpc/test/member_voting_test.cpp +++ b/src/node/rpc/test/member_voting_test.cpp @@ -242,7 +242,7 @@ DOCTEST_TEST_CASE("Member query/read") { // initialize the network state NetworkState network; - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -259,7 +259,7 @@ DOCTEST_TEST_CASE("Member query/read") // put value to read constexpr auto key = 123; constexpr auto value = 456; - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.values)->put(key, value); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -271,7 +271,7 @@ DOCTEST_TEST_CASE("Member query/read") DOCTEST_SUBCASE("Query: bytecode/script allowed access") { // set member ACL so that the VALUES table is accessible - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.whitelists) ->put(WlIds::MEMBER_CAN_READ, {Tables::VALUES}); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -290,7 +290,7 @@ DOCTEST_TEST_CASE("Member query/read") DOCTEST_SUBCASE("Query: table not in ACL") { // set member ACL so that no table is accessible - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.whitelists)->put(WlIds::MEMBER_CAN_READ, {}); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -302,7 +302,7 @@ DOCTEST_TEST_CASE("Member query/read") DOCTEST_SUBCASE("Read: allowed access, key exists") { - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.whitelists) ->put(WlIds::MEMBER_CAN_READ, {Tables::VALUES}); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -317,7 +317,7 @@ DOCTEST_TEST_CASE("Member query/read") DOCTEST_SUBCASE("Read: allowed access, key doesn't exist") { constexpr auto wrong_key = 321; - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.whitelists) ->put(WlIds::MEMBER_CAN_READ, {Tables::VALUES}); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -331,7 +331,7 @@ DOCTEST_TEST_CASE("Member query/read") DOCTEST_SUBCASE("Read: access not allowed") { - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.whitelists)->put(WlIds::MEMBER_CAN_READ, {}); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); @@ -347,7 +347,7 @@ DOCTEST_TEST_CASE("Proposer ballot") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -467,7 +467,7 @@ DOCTEST_TEST_CASE("Add new members until there are 7 then reject") network.encryption_key = std::make_unique( tls::create_entropy()->random(crypto::BoxKey::KEY_SIZE)); network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -617,7 +617,7 @@ DOCTEST_TEST_CASE("Add new members until there are 7 then reject") { // make sure that there is a signature in the signatures table since // ack's depend on that - kv::Tx tx; + auto tx = network.tables->create_tx(); auto sig_view = tx.get_view(network.signatures); PrimarySignature sig_value; sig_view->put(0, sig_value); @@ -670,7 +670,7 @@ DOCTEST_TEST_CASE("Accept node") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -838,7 +838,7 @@ ProposalInfo test_raw_writes( // check values before { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto next_member_id_r = tx.get_view(network.values)->get(ValueIds::NEXT_MEMBER_ID); DOCTEST_CHECK(next_member_id_r); @@ -907,7 +907,7 @@ DOCTEST_TEST_CASE("Propose raw writes") const bool should_succeed = pro_votes > n_members / 2; NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -915,7 +915,7 @@ DOCTEST_TEST_CASE("Propose raw writes") StubNodeState node(share_manager); nlohmann::json recovery_threshold = 4; - kv::Tx tx_before; + auto tx_before = network.tables->create_tx(); auto configuration = tx_before.get_view(network.config)->get(0); DOCTEST_REQUIRE_FALSE(configuration.has_value()); @@ -940,7 +940,7 @@ DOCTEST_TEST_CASE("Propose raw writes") continue; // check results - kv::Tx tx_after; + auto tx_after = network.tables->create_tx(); configuration = tx_after.get_view(network.config)->get(0); DOCTEST_CHECK(configuration.has_value()); DOCTEST_CHECK(configuration->recovery_threshold == recovery_threshold); @@ -962,7 +962,7 @@ DOCTEST_TEST_CASE("Propose raw writes") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1000,7 +1000,7 @@ DOCTEST_TEST_CASE("Remove proposal") NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1023,7 +1023,7 @@ DOCTEST_TEST_CASE("Remove proposal") // check that the proposal doesn't exist { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto proposal = tx.get_view(network.proposals)->get(proposal_id); DOCTEST_CHECK(!proposal); } @@ -1040,7 +1040,7 @@ DOCTEST_TEST_CASE("Remove proposal") // check that the proposal is there { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto proposal = tx.get_view(network.proposals)->get(proposal_id); DOCTEST_CHECK(proposal); DOCTEST_CHECK(proposal->state == ProposalState::OPEN); @@ -1078,7 +1078,7 @@ DOCTEST_TEST_CASE("Remove proposal") // check that the proposal is now withdrawn { - kv::Tx tx; + auto tx = network.tables->create_tx(); auto proposal = tx.get_view(network.proposals)->get(proposal_id); DOCTEST_CHECK(proposal.has_value()); DOCTEST_CHECK(proposal->state == ProposalState::WITHDRAWN); @@ -1090,7 +1090,7 @@ DOCTEST_TEST_CASE("Complete proposal after initial rejection") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1109,7 +1109,7 @@ DOCTEST_TEST_CASE("Complete proposal after initial rejection") const auto propose = create_signed_request(Propose::In{proposal}, "proposals", kp); - kv::Tx tx; + auto tx = network.tables->create_tx(); const auto r = parse_response_body( frontend_process(frontend, propose, member_certs[0])); DOCTEST_CHECK(r.state == ProposalState::OPEN); @@ -1142,7 +1142,7 @@ DOCTEST_TEST_CASE("Complete proposal after initial rejection") { DOCTEST_INFO("Put value that makes vote agree"); - kv::Tx tx; + auto tx = network.tables->create_tx(); tx.get_view(network.values)->put(123, 123); DOCTEST_CHECK(tx.commit() == kv::CommitSuccess::OK); } @@ -1162,7 +1162,7 @@ DOCTEST_TEST_CASE("Vetoed proposal gets rejected") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1216,7 +1216,7 @@ DOCTEST_TEST_CASE("Add and remove user via proposed calls") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1249,7 +1249,7 @@ DOCTEST_TEST_CASE("Add and remove user via proposed calls") DOCTEST_CHECK(r.state == ProposalState::ACCEPTED); DOCTEST_CHECK(r.proposal_id == 0); - kv::Tx tx1; + auto tx1 = network.tables->create_tx(); const auto uid = tx1.get_view(network.values)->get(ValueIds::NEXT_USER_ID); DOCTEST_CHECK(uid); DOCTEST_CHECK(*uid == 1); @@ -1275,7 +1275,7 @@ DOCTEST_TEST_CASE("Add and remove user via proposed calls") DOCTEST_CHECK(r.state == ProposalState::ACCEPTED); DOCTEST_CHECK(r.proposal_id == 1); - kv::Tx tx1; + auto tx1 = network.tables->create_tx(); auto user = tx1.get_view(network.users)->get(0); DOCTEST_CHECK(!user.has_value()); auto user_cert = tx1.get_view(network.user_certs)->get(user_der); @@ -1297,7 +1297,7 @@ DOCTEST_TEST_CASE( // Operator votes, but is _not_ taken into consideration NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1408,7 +1408,7 @@ DOCTEST_TEST_CASE("Passing operator vote" * doctest::test_suite("operator")) // and gets it through without member votes NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1592,7 +1592,7 @@ DOCTEST_TEST_CASE( // A majority of members pass the vote NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1708,7 +1708,7 @@ DOCTEST_TEST_CASE("User data") { NetworkState network; network.tables->set_encryptor(encryptor); - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1833,7 +1833,7 @@ DOCTEST_TEST_CASE("Submit recovery shares") DOCTEST_INFO("Setup state"); { - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -1891,7 +1891,7 @@ DOCTEST_TEST_CASE("Submit recovery shares") DOCTEST_INFO("Change service state to waiting for recovery shares"); { - kv::Tx tx; + auto tx = network.tables->create_tx(); GenesisGenerator g(network, tx); DOCTEST_REQUIRE(g.service_wait_for_shares()); g.finalize(); @@ -1900,7 +1900,7 @@ DOCTEST_TEST_CASE("Submit recovery shares") DOCTEST_INFO( "Threshold cannot be changed while service is waiting for shares"); { - kv::Tx tx; + auto tx = network.tables->create_tx(); GenesisGenerator g(network, tx); DOCTEST_REQUIRE_FALSE(g.set_recovery_threshold(recovery_threshold)); } @@ -1974,7 +1974,7 @@ DOCTEST_TEST_CASE("Maximum number of active members") std::map members; - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -2031,7 +2031,7 @@ DOCTEST_TEST_CASE("Open network sequence") DOCTEST_INFO("Setup state"); { - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); gen.create_service({}); @@ -2054,7 +2054,7 @@ DOCTEST_TEST_CASE("Open network sequence") DOCTEST_INFO("Open fails as recovery threshold is too high"); { - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); DOCTEST_REQUIRE_FALSE(gen.open_service()); @@ -2062,7 +2062,7 @@ DOCTEST_TEST_CASE("Open network sequence") DOCTEST_INFO("Activate all members - open still fails"); { - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); for (auto const& m : members) { @@ -2074,7 +2074,7 @@ DOCTEST_TEST_CASE("Open network sequence") DOCTEST_INFO("Reduce recovery threshold"); { - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.set_recovery_threshold(members_count); diff --git a/src/node/rpc/test/node_frontend_test.cpp b/src/node/rpc/test/node_frontend_test.cpp index 1114af32b..7861d28cc 100644 --- a/src/node/rpc/test/node_frontend_test.cpp +++ b/src/node/rpc/test/node_frontend_test.cpp @@ -79,7 +79,7 @@ T parse_response_body(const TResponse& r) TEST_CASE("Add a node to an opening service") { NetworkState network; - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); @@ -150,7 +150,7 @@ TEST_CASE("Add a node to an opening service") CHECK(response.node_status == NodeStatus::TRUSTED); CHECK(response.network_info.public_only == false); - kv::Tx tx; + auto tx = network.tables->create_tx(); const NodeId node_id = response.node_id; auto nodes_view = tx.get_view(network.nodes); auto node_info = nodes_view->get(node_id); @@ -200,7 +200,7 @@ TEST_CASE("Add a node to an opening service") TEST_CASE("Add a node to an open service") { NetworkState network; - kv::Tx gen_tx; + auto gen_tx = network.tables->create_tx(); GenesisGenerator gen(network, gen_tx); gen.init_values(); @@ -227,7 +227,7 @@ TEST_CASE("Add a node to an open service") const auto caller = kp->self_sign(fmt::format("CN=nodes")); std::optional node_info; - kv::Tx tx; + auto tx = network.tables->create_tx(); JoinNetworkNodeToNode::In join_input; diff --git a/src/node/snapshotter.h b/src/node/snapshotter.h index df01c51d1..fd1d31622 100644 --- a/src/node/snapshotter.h +++ b/src/node/snapshotter.h @@ -91,7 +91,7 @@ namespace ccf auto serialised_snapshot = network.tables->serialise_snapshot(std::move(snapshot)); - kv::Tx tx; + auto tx = network.tables->create_tx(); auto view = tx.get_view(network.snapshot_evidence); auto snapshot_hash = crypto::Sha256Hash(serialised_snapshot); view->put(0, {snapshot_hash, snapshot_v}); diff --git a/src/node/test/historical_queries.cpp b/src/node/test/historical_queries.cpp index f0ddfd0a4..3e57635e0 100644 --- a/src/node/test/historical_queries.cpp +++ b/src/node/test/historical_queries.cpp @@ -98,7 +98,7 @@ TEST_CASE("StateCache") { INFO("Store the signing node's key"); - kv::Tx tx; + auto tx = store.create_tx(); auto view = tx.get_view(nodes); ccf::NodeInfo ni; ni.cert = kp->self_sign("CN=Test node"); @@ -124,7 +124,7 @@ TEST_CASE("StateCache") } else { - kv::Tx tx; + auto tx = store.create_tx(); auto [public_view, private_view] = tx.get_view(public_table, private_table); const auto s = std::to_string(i); @@ -259,7 +259,7 @@ TEST_CASE("StateCache") auto& public_table = *store_at_index->get("public"); auto& private_table = *store_at_index->get("private"); - kv::Tx tx; + auto tx = store_at_index->create_tx(); auto [public_view, private_view] = tx.get_view(public_table, private_table); diff --git a/src/node/test/history.cpp b/src/node/test/history.cpp index e3e8c584e..39496627d 100644 --- a/src/node/test/history.cpp +++ b/src/node/test/history.cpp @@ -96,7 +96,7 @@ TEST_CASE("Check signature verification") INFO("Write certificate"); { - kv::Tx txs; + auto txs = primary_store.create_tx(); auto tx = txs.get_view(primary_nodes); ccf::NodeInfo ni; ni.cert = kp->self_sign("CN=name"); @@ -112,7 +112,7 @@ TEST_CASE("Check signature verification") INFO("Issue a bogus signature, rejected by verification on the backup"); { - kv::Tx txs; + auto txs = primary_store.create_tx(); auto tx = txs.get_view(primary_signatures); ccf::PrimarySignature bogus(0, 0, {0}); bogus.sig = std::vector(MBEDTLS_ECDSA_MAX_LEN, 1); @@ -159,7 +159,7 @@ TEST_CASE("Check signing works across rollback") INFO("Write certificate"); { - kv::Tx txs; + auto txs = primary_store.create_tx(); auto tx = txs.get_view(primary_nodes); ccf::NodeInfo ni; ni.cert = kp->self_sign("CN=name"); @@ -169,7 +169,7 @@ TEST_CASE("Check signing works across rollback") INFO("Transaction that we will roll back"); { - kv::Tx txs; + auto txs = primary_store.create_tx(); auto tx = txs.get_view(primary_nodes); ccf::NodeInfo ni; tx->put(1, ni); @@ -267,7 +267,7 @@ TEST_CASE( INFO("Write first tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -278,7 +278,7 @@ TEST_CASE( { auto rv = store.next_txid(); - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 2); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -286,8 +286,8 @@ TEST_CASE( store.commit( rv, - [rv, &other_table]() { - kv::Tx txr(rv.version); + [&store, rv, &other_table]() { + auto txr = store.create_reserved_tx(rv.version); auto txrv = txr.get_view(other_table); txrv->put(0, 1); return txr.commit_reserved(); @@ -298,7 +298,7 @@ TEST_CASE( INFO("Single tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 3); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -376,7 +376,7 @@ TEST_CASE( INFO("Write first tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -385,7 +385,7 @@ TEST_CASE( INFO("Write second tx, causing a rollback"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 2); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -394,7 +394,7 @@ TEST_CASE( INFO("Single tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 3); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -415,7 +415,7 @@ TEST_CASE( INFO("Write first tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 1); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -424,7 +424,7 @@ TEST_CASE( INFO("Write second tx, causing a rollback"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 2); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -433,7 +433,7 @@ TEST_CASE( INFO("Single tx"); { - kv::Tx tx; + auto tx = store.create_tx(); auto txv = tx.get_view(table); txv->put(0, 3); REQUIRE(tx.commit() == kv::CommitSuccess::OK); diff --git a/src/node/test/snapshot.cpp b/src/node/test/snapshot.cpp index fc60091cb..f4ca17f14 100644 --- a/src/node/test/snapshot.cpp +++ b/src/node/test/snapshot.cpp @@ -39,7 +39,7 @@ TEST_CASE("Snapshot with merkle tree" * doctest::test_suite("snapshot")) { for (size_t i = 0; i < transactions_count; i++) { - kv::Tx tx; + auto tx = source_store.create_tx(); auto view = tx.get_view(string_map); view->put(fmt::format("key#{}", i), "value"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); @@ -60,7 +60,7 @@ TEST_CASE("Snapshot with merkle tree" * doctest::test_suite("snapshot")) { // No snapshot here, only verify that a fresh tree can be started from the // mini-tree in a signature and the hash of the signature - kv::ReadOnlyTx tx; + auto tx = source_store.create_read_only_tx(); auto view = tx.get_read_only_view(signatures); auto sig = view->get(0).value(); @@ -130,7 +130,7 @@ TEST_CASE("Snapshot with merkle tree" * doctest::test_suite("snapshot")) INFO("Deserialise additional transaction after restart"); { - kv::Tx tx; + auto tx = source_store.create_tx(); auto view = tx.get_view(string_map); view->put("key", "value"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); diff --git a/src/node/test/snapshotter.cpp b/src/node/test/snapshotter.cpp index e00c9718c..8b3fb0b05 100644 --- a/src/node/test/snapshotter.cpp +++ b/src/node/test/snapshotter.cpp @@ -47,7 +47,7 @@ void issue_transactions(ccf::NetworkState& network, size_t tx_count) for (size_t i = 0; i < tx_count; i++) { auto tx = network.tables->create_tx(); - auto view = tx.get_view2("map"); + auto view = tx.get_view("map"); view->put("foo", "bar"); REQUIRE(tx.commit() == kv::CommitSuccess::OK); }