Document dynamic table creation, and use dynamic-friendly Txs everywhere (#1674)

This commit is contained in:
Eddy Ashton 2020-09-30 16:33:48 +01:00 коммит произвёл GitHub
Родитель 96b7dcf2f1
Коммит 0cd5c4c5b1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 463 добавлений и 280 удалений

Просмотреть файл

@ -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<kv::Map<string, string>>("map1");
// Two Views created at the same time, over different public and private maps
auto [view_map2, view_map3] =
tx.get_view<kv::Map<string, string>, kv::Map<uint64_t, string>>("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);

Просмотреть файл

@ -73,7 +73,7 @@ static std::vector<uint8_t> kv_serialized_data(std::vector<uint8_t>& data)
auto& map0 = kv_store.create<aft::RequestsMap>("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, {}});

Просмотреть файл

@ -178,7 +178,7 @@ namespace ccfapp
LOG_TRACE_FMT("Looking for table '{}'", property_name);
auto tx_ptr = static_cast<kv::Tx*>(JS_GetOpaque(this_val, tables_class_id));
auto view = tx_ptr->get_view2<Table>(property_name);
auto view = tx_ptr->get_view<Table>(property_name);
auto view_val = JS_NewObjectClass(ctx, view_class_id);
JS_SetOpaque(view_val, view);

Просмотреть файл

@ -340,8 +340,8 @@ namespace loggingapp
const auto in = params.get<LoggingGetHistorical::In>();
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())

Просмотреть файл

@ -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<kv::NullTxEncryptor>();
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<kv::NullTxEncryptor>();
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<kv::NullTxEncryptor>();
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({});

Просмотреть файл

@ -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)

Просмотреть файл

@ -50,6 +50,7 @@ namespace aft
kv::Tx* tx = nullptr,
ccf::PrimarySignature* sig = nullptr) = 0;
virtual std::shared_ptr<ccf::ProgressTracker> get_progress_tracker() = 0;
virtual kv::Tx create_tx() = 0;
};
template <typename T, typename S>
@ -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<uint8_t>& data,
bool public_only = false,

Просмотреть файл

@ -217,6 +217,11 @@ namespace aft
{
return nullptr;
}
kv::Tx create_tx()
{
return kv::Tx();
}
};
class LoggingStubStoreSig : public LoggingStubStore

Просмотреть файл

@ -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<AbstractMap> 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<AbstractMap>& map) override
{

Просмотреть файл

@ -62,7 +62,7 @@ static void serialise(picobench::state& s)
auto& map0 = kv_store.create<MapType>("map0", SD);
auto& map1 = kv_store.create<MapType>("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<MapType>("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<MapType>(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<MapType>(fmt::format("map{}", i)));

Просмотреть файл

@ -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<MapType::TxView*> views;
for (const auto map : args->maps)

Просмотреть файл

@ -33,7 +33,7 @@ TEST_CASE("Basic dynamic table" * doctest::test_suite("dynamic"))
{
auto tx = kv_store.create_tx();
auto view = tx.get_view2<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString, MapTypes::StringNum>(
auto [v1, v2] = tx.get_view<MapTypes::StringString, MapTypes::StringNum>(
new_map1, new_map2);
auto [v2a, v3] = tx.get_view2<MapTypes::StringNum, MapTypes::NumString>(
new_map2, new_map3);
auto [v2a, v3] =
tx.get_view<MapTypes::StringNum, MapTypes::NumString>(new_map2, new_map3);
REQUIRE(v2 == v2a);
v1->put("foo", "bar");
v3->put(42, "hello");
auto va = tx.get_view2<MapTypes::StringString>(map_name);
auto va = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto check_va = check_tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto check_va = check_tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view1 = tx1.get_view<MapTypes::StringString>(map_name);
view1->put("foo", "bar");
REQUIRE(view1->get("foo").value() == "bar");
auto view2 = tx2.get_view2<MapTypes::StringString>(map_name);
auto view2 = tx2.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = txx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view3 = tx3.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view4 = tx4.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view1 = tx1.get_view<MapTypes::StringString>(map_name);
view1->put("foo", "bar");
// Map created in tx1 is not visible
auto view2 = tx2.get_view2<MapTypes::StringString>(map_name);
auto view2 = tx2.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view3 = tx3.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view4 = tx4.get_view<MapTypes::StringString>(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::NullTxEncryptor>();
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<MapTypes::StringString>(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<MapTypes::StringString, MapTypes::StringString>(
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<MapTypes::StringString, MapTypes::StringString>(
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<MapTypes::NumString>(dynamic_map_a);
auto view2 = tx2.get_view2<MapTypes::StringNum>(dynamic_map_b);
auto view1 = tx1.get_view<MapTypes::NumString>(dynamic_map_a);
auto view2 = tx2.get_view<MapTypes::StringNum>(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<MapTypes::NumString>(dynamic_map_a);
auto dynamic_view = tx1.get_view<MapTypes::NumString>(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<MapTypes::StringNum>(dynamic_map_b);
auto dynamic_view = tx2.get_view<MapTypes::StringNum>(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<MapTypes::NumString, MapTypes::StringNum>(
tx3.get_view<MapTypes::NumString, MapTypes::StringNum>(
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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view_target = tx_target.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view_1 = tx1.get_view<MapTypes::StringString>(map_name);
view_1->put("foo", "foo");
REQUIRE(tx1.commit() == kv::CommitSuccess::OK);
auto tx2 = store.create_tx();
auto view_2 = tx2.get_view2<MapTypes::StringString>(map_name);
auto view_2 = tx2.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>(map_name);
auto view_after = tx.get_view<MapTypes::StringString>(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<MapTypes::StringString>("public:foo");
auto view = tx.get_view<MapTypes::StringString>("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<MapTypes::StringString>("foo");
auto view = tx.get_view<MapTypes::StringString>("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<MapTypes::StringString, MapTypes::StringString>(
tx.get_view<MapTypes::StringString, MapTypes::StringString>(
"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<MapTypes::StringString, MapTypes::NumString>("foo", "bar");
tx.get_view<MapTypes::StringString, MapTypes::NumString>("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<MapTypes::StringString, MapTypes::StringNum>("foo", "baz");
tx.get_view<MapTypes::StringString, MapTypes::StringNum>("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<MapTypes::StringString>("public:source_state");
auto v0 = tx.get_view<MapTypes::StringString>("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<MapTypes::StringString>("public:target_state");
auto v0 = tx.get_view<MapTypes::StringString>("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<MapTypes::StringString, MapTypes::StringString>(
"public:source_state", "public:target_state");
auto [v0, v1] = tx.get_view<MapTypes::StringString, MapTypes::StringString>(
"public:source_state", "public:target_state");
const auto val0 = v0->get("store");
REQUIRE_FALSE(val0.has_value());

Просмотреть файл

@ -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<MapTypes::StringString>("priv_map");
auto* target_pub_map = kv_store.get<MapTypes::StringString>("pub_map");
auto* target_priv_map =
kv_store_target.get<MapTypes::StringString>("priv_map");
auto* target_pub_map = kv_store_target.get<MapTypes::StringString>("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<MapType>("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<Table>("t", kv::SecurityDomain::PUBLIC);
s1.create<Table>("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<Table>("t", kv::SecurityDomain::PUBLIC);
s1.create<Table>("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, {}));
}

Просмотреть файл

@ -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<MapTypes::StringString>("string_map");
auto new_num_map = new_store.get<MapTypes::NumNum>("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<MapTypes::StringString>("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());

Просмотреть файл

@ -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<MapTypes::NumString>("public", kv::SecurityDomain::PUBLIC);
auto& private_map = store.create<MapTypes::NumString>("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<MapTypes::NumNum>("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<std::string>& present,
const std::vector<std::string>& 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...

Просмотреть файл

@ -66,7 +66,7 @@ namespace kv
}
template <class M>
std::tuple<typename M::TxView*> get_tuple(M& m)
std::tuple<typename M::TxView*> get_tuple_old(M& m)
{
using MapView = typename M::TxView;
@ -110,11 +110,13 @@ namespace kv
}
template <class M>
std::tuple<typename M::TxView*> get_tuple2(const std::string& map_name)
std::tuple<typename M::TxView*> 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 <class M, class... Ms>
std::tuple<typename M::TxView*, typename Ms::TxView*...> get_tuple(
M& m, Ms&... ms)
std::tuple<typename M::TxView*, typename Ms::TxView*...>
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>(m.get_name());
}
else
{
return std::tuple_cat(
get_view_tuple_by_name<M>(m.get_name()),
get_view_tuple_by_types(ms...));
}
}
template <class M, class... Ms, class... Ts>
std::tuple<typename M::TxView*, typename Ms::TxView*...> get_tuple2(
const std::string& map_names, const Ts&... names)
std::tuple<typename M::TxView*, typename Ms::TxView*...>
get_view_tuple_by_names(const std::string& map_name, const Ts&... names)
{
return std::tuple_cat(
get_tuple2<M>(map_names), get_tuple2<Ms...>(names...));
if constexpr (sizeof...(Ts) == 0)
{
return get_view_tuple_by_name<M>(map_name);
}
else
{
return std::tuple_cat(
get_view_tuple_by_name<M>(map_name),
get_view_tuple_by_names<Ms...>(names...));
}
}
public:
@ -476,7 +495,20 @@ namespace kv
template <class M>
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>(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 <class M>
typename M::ReadOnlyTxView* get_read_only_view(const std::string& map_name)
{
return std::get<0>(get_view_tuple_by_name<M>(map_name));
}
/** Get read-only transaction views over multiple maps.
@ -488,7 +520,24 @@ namespace kv
std::tuple<typename M::ReadOnlyTxView*, typename Ms::ReadOnlyTxView*...>
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>(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 <class M, class... Ms, class... Ts>
std::tuple<typename M::TxView*, typename Ms::TxView*...> get_read_only_view(
const std::string& map_name, const Ts&... names)
{
return std::tuple_cat(
get_view_tuple_by_name<M>(map_name),
get_view_tuple_by_names<Ms...>(names...));
}
};
@ -497,6 +546,13 @@ namespace kv
public:
using ReadOnlyTx::ReadOnlyTx;
// TEMPORARY - DO NOT USE
template <class M>
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 <class M>
typename M::TxView* get_view(M& m)
{
return std::get<0>(get_tuple(m));
return std::get<0>(get_view_tuple_by_name<M>(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 <class M>
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<M>(map_name));
return std::get<0>(get_view_tuple_by_name<M>(map_name));
}
/** Get transaction views over multiple maps.
@ -526,17 +587,24 @@ namespace kv
std::tuple<typename M::TxView*, typename Ms::TxView*...> 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>(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 <class M, class... Ms, class... Ts>
std::tuple<typename M::TxView*, typename Ms::TxView*...> get_view2(
std::tuple<typename M::TxView*, typename Ms::TxView*...> get_view(
const std::string& map_name, const Ts&... names)
{
return std::tuple_cat(
get_tuple2<M>(map_name), get_tuple2<Ms...>(names...));
get_view_tuple_by_name<M>(map_name),
get_view_tuple_by_names<Ms...>(names...));
}
};

Просмотреть файл

@ -34,7 +34,7 @@ namespace ccf
kv::Store tables;
auto& table = tables.create<TableIS>("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<TableIS>("test_is", kv::SecurityDomain::PUBLIC);
auto& sb = tables.create<TableSB>("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<TableVI>("v");
kv::Tx txs;
auto txs = tables.create_tx();
auto tx = txs.get_view(table);
tx->put(vector<uint8_t>(100, 1), 123);
@ -337,7 +337,7 @@ namespace ccf
kv::Store tables;
auto& table = tables.create<TableII>("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<TableII>("t", kv::SecurityDomain::PUBLIC);
kv::Tx txs;
auto txs = tables.create_tx();
auto tx = txs.get_view(table);
Interpreter li;

Просмотреть файл

@ -94,7 +94,7 @@ namespace ccf::historical
std::optional<ccf::PrimarySignature> get_signature(
const StorePtr& sig_store)
{
kv::Tx tx;
auto tx = sig_store->create_tx();
auto sig_table = sig_store->get<ccf::Signatures>(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::Nodes>(ccf::Tables::NODES);
if (nodes_table == nullptr)

Просмотреть файл

@ -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();

Просмотреть файл

@ -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<ccf::ProgressTracker*>(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

Просмотреть файл

@ -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())

Просмотреть файл

@ -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);

Просмотреть файл

@ -405,7 +405,7 @@ nlohmann::json parse_response_body(
std::optional<SignedReq> 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<kv::PrimaryStubConsensus>();
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());
}

Просмотреть файл

@ -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<NetworkEncryptionKey>(
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<Propose::Out>(
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<size_t, tls::Pem> 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);

Просмотреть файл

@ -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<NodeInfo> node_info;
kv::Tx tx;
auto tx = network.tables->create_tx();
JoinNetworkNodeToNode::In join_input;

Просмотреть файл

@ -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});

Просмотреть файл

@ -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<NumToString>("public");
auto& private_table = *store_at_index->get<NumToString>("private");
kv::Tx tx;
auto tx = store_at_index->create_tx();
auto [public_view, private_view] =
tx.get_view(public_table, private_table);

Просмотреть файл

@ -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<uint8_t>(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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<StringString>("map");
auto view = tx.get_view<StringString>("map");
view->put("foo", "bar");
REQUIRE(tx.commit() == kv::CommitSuccess::OK);
}