We can write native files, build two-route indexes directly over their mappings, save the resulting roots and publish a later native merge. The native inputs stay immutable throughout. A secondary route uses the native file of its target; it needs no separate secondary index.
This complete program takes an existing empty directory as its argument. As in the streamed timeline example, the caller establishes that directory and its ancestors durably. Fresh catalogs let the example use a simple deterministic identity allocator. An application supplies its own allocator and retains its operation identities for retry.
#include <span>
#include <filesystem>
#include <algorithm>
#include <array>
#include <cstdio>
#include <initializer_list>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
import everett.sqlite;
std::string_view text) {
auto key = bit_string::from_bytes(text);
std::vector<bit_string> result;
while (!cursor.done()) {
cursor.step(1);
while (cursor.has_match()) result.push_back(cursor.take_match().value);
}
return result;
}
int main(
int argc,
char ** argv) {
if (argc != 2) return 64;
auto directory = std::filesystem::canonical(argv[1]);
{
unsigned next = 1;
auto fresh = [&] {
char text[33];
std::snprintf(text, sizeof text, "%032x", next++);
};
auto metadata = catalog::create_cola(directory, fresh());
auto reserve = [&](std::span<blob_identity const> inputs) {
std::array outputs{
metadata.reserve("reserve-" + r.ids.index.hex(), r.attempt,
"builder-" + r.ids.index.hex(), inputs, outputs);
return r;
};
metadata.record_sealed("native-" + r.ids.index.hex(), receipt);
auto native = std::make_shared<mapped_native<P>
const>(
std::shared_ptr<mapped_native<P> const>{};
while (!builder.done()) builder.step(16);
auto artifact = builder.finish();
main ? std::optional{main->identity()} : std::nullopt, side_id);
auto sealed = encoded.seal(directory, r.ids.index, r.attempt);
metadata.record_sealed("index-" + r.ids.index.hex(), sealed);
auto index = std::make_shared<mapped_cola_index<P> const>(
metadata.register_chain("register-" + r.ids.index.hex(), root);
return root;
};
auto write = [&](std::initializer_list<std::pair<std::string_view, std::string_view>> records) {
auto r = reserve({});
for (auto const & [name, contents] : records) {
auto key = bit_string::from_bytes(name);
auto value = bit_string::from_bytes(contents);
}
};
auto older = write({{"alpha", "before"}, {"beta", "retained"}});
auto first = metadata.create_timeline("create-main", "main", older.head()->identity());
metadata.save("save-before", "before", first.head);
auto newer = write({{"alpha", "after"}, {"gamma", "added"}});
std::array inputs{older.head()->identity(), newer.head()->identity()};
auto routing = reserve(inputs);
auto combined =
complete(routing,
empty.finish(), older.head(), newer.head());
metadata.save("save-combined", "combined", combined.head()->identity());
auto second = metadata.publish_timeline("publish-combined", first, combined.head()->identity());
if (!second.published) return 1;
auto output = reserve(inputs);
output.attempt, older.head()->native_object(), newer.head()->native_object());
while (!merge.done()) merge.step(1);
auto merged =
complete(output, merge.finish());
if (!metadata.publish_timeline("publish-merged", second.head,
merged.head()->identity()).published) return 2;
}
auto metadata = catalog::open(directory);
auto before_pin = metadata.acquire_save("read-before", "before", "reader-before");
auto combined_pin = metadata.acquire_save("read-combined", "combined", "reader-combined");
auto before = open_mapped_cola_query<P>(directory, before_pin.head);
auto combined = open_mapped_cola_query<P>(directory, combined_pin.head);
auto current = metadata.find_timeline("main");
if (!current) return 3;
auto merged = open_mapped_cola_query<P>(directory, current->head);
if (values(before, "alpha") != std::vector{bit_string::from_bytes("before")}) return 4;
auto both = values(combined, "alpha");
if (both.size() != 2 || std::count(both.begin(), both.end(), bit_string::from_bytes("before")) != 1 ||
std::count(both.begin(), both.end(), bit_string::from_bytes("after")) != 1) return 5;
if (values(merged, "alpha") != std::vector{bit_string::from_bytes("after")} ||
values(merged, "beta") != std::vector{bit_string::from_bytes("retained")} ||
values(merged, "gamma") != std::vector{bit_string::from_bytes("added")}) return 6;
}
void pair(bytes &out, blob_identity const &value)
Definition sqlite_catalog.h:121
bit_string value(arrow_t< S > const &value)
Definition typed_world.h:99
bit_string key(key_t< S > const &value)
Definition typed_world.h:89
Definition active_engine.h:18
encoded_cola_sections< P > encode_cola_sections(cola_index< P, Native, Main > const &source, object_id const &native_id, std::optional< blob_identity > main_id={}, std::optional< object_id > secondary_id={})
Definition cola_sections.h:256
bit_view view() const &
Definition profile.h:178
Definition sqlite_catalog.h:45
Definition cola_index.h:496
Definition cola_query.h:40
cola_query_cursor< P, Blob > cursor(bit_view query) const
Definition cola_query.h:64
Definition mapped_cola.h:33
std::shared_ptr< mapped_cola_blob const > pair_type
Definition mapped_cola.h:39
Definition cola_sections.h:266
Definition sections.h:442
Definition native_file_merge.h:38
Definition native_file_writer.h:29
Definition object_writer.h:39
Definition object_path.h:38
Definition object_writer.h:88
Definition sqlite_catalog.h:351
The program drives each step explicitly. It demonstrates durable completed objects and root publication; the scheduler model supplies the separate main/secondary/shadow work and visibility rules. Restoring an interrupted private merge is covered by the continuation design.