Everett
Loading...
Searching...
No Matches
redundant_runtime.h
Go to the documentation of this file.
1
12#pragma once
13
15#include <array>
16#include <unordered_map>
17
18namespace everett {
19 // A storage family changes native framing without changing the scheduler.
20 // Borrowed streams and query navigation follow native_type::stream_family.
21 template <class P> struct profile_runtime_storage {
25 static auto encode_native(profile_array<P> const & value) { return encode_native_sections(value); }
27 template <class Compose> static auto make_merge(std::shared_ptr<native_type const> older,
28 std::shared_ptr<native_type const> newer, Compose compose) {
29 return std::make_unique<merge_type<Compose>>(std::move(older), std::move(newer), std::move(compose));
30 }
31 template <class Merge> static auto finish_merge(Merge & merge) { return native_type::from_owned(merge.finish()); }
33 template <class Node> static auto make_index(std::shared_ptr<native_type const> native,
34 typename Node::pair_type main = {}, std::shared_ptr<native_type const> secondary = {}) {
35 return std::make_unique<index_type<Node>>(std::move(native), std::move(main), std::move(secondary));
36 }
37 template <class Node> static auto finish_index(index_type<Node> & index) { return Node::from_built(index.finish()); }
39 static auto singleton(profile_record const & record) {
40 profile_native_writer<P> writer; writer.append(record); return native_type::from_owned(writer.finish());
41 }
42 static auto sorted_native(std::span<profile_record const> records) {
44 for (auto const & record : records) writer.append(record);
45 return native_type::from_owned(writer.finish());
46 }
47 };
48
49 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_node {
50 using policy_type = P;
51 using storage_type = Storage;
52 using native_type = typename Storage::native_type;
53 using native_pointer = std::shared_ptr<native_type const>;
54 using pair_type = std::shared_ptr<redundant_node const>;
57 return pair_type(new redundant_node(std::make_shared<built_type const>(std::move(value))));
58 }
59 static pair_type from_built(std::shared_ptr<built_type const> value) {
60 if (!value) throw std::invalid_argument("null redundant built head");
61 return pair_type(new redundant_node(std::move(value)));
62 }
63 static pair_type from_mapped(std::shared_ptr<typename Storage::mapped_pair_type const> head) {
64 if (!head) error_detail::raise<std::invalid_argument>("null redundant mapped head");
65 std::vector<std::shared_ptr<typename Storage::mapped_pair_type const>> chain;
66 std::unordered_set<typename Storage::mapped_pair_type const *> seen;
67 for (auto p = head; p; p = p->main_target()) {
68 if (!seen.insert(p.get()).second) error_detail::raise<std::invalid_argument>("cyclic redundant main chain");
69 chain.push_back(p);
70 }
71 pair_type result;
72 for (auto i = chain.rbegin(); i != chain.rend(); ++i) result = pair_type(new redundant_node(*i, std::move(result)));
73 return result;
74 }
75 // The loader interns mapped identities and passes the corresponding
76 // facades, preserving exact target/native sharing across hidden roots.
77 static pair_type from_mapped_parts(std::shared_ptr<typename Storage::mapped_pair_type const> value,
79 if (!value || !native || native->mapped() != value->native_object() ||
80 bool(main) != bool(value->main_target()) || (main && main->mapped() != value->main_target()) ||
81 bool(secondary) != bool(value->secondary_target()) || (secondary && secondary->mapped() != value->secondary_target()))
82 error_detail::raise<std::invalid_argument>("inexact mapped redundant parts");
83 return pair_type(new redundant_node(std::move(value), std::move(native), std::move(main), std::move(secondary)));
84 }
85 typename built_type::view_type view() const { return built_ ? built_->view() : mapped_->view(); }
86 native_pointer native_owner() const noexcept { return native_; }
87 native_pointer secondary_target() const noexcept { return secondary_; }
88 pair_type main_target() const noexcept { return main_; }
89 std::uint64_t virtual_size() const { return view().virtual_size(); }
90 std::uint64_t group_count() const { return view().group_count(); }
91 std::uint64_t depth() const noexcept { return depth_; }
92 std::shared_ptr<built_type const> built() const noexcept { return built_; }
93 std::shared_ptr<typename Storage::mapped_pair_type const> mapped() const noexcept { return mapped_; }
94 bool canonical_mapped() const noexcept { return canonical_mapped_; }
95 private:
96 template <class, class, class, class> friend struct runtime_store;
97 template <class, class, class, class> friend struct runtime_store_detail::graph_sealer;
98 template <class, class, class, class, class> friend struct sort_runtime_context;
99 // Only the execution context constructs an index from acknowledged exact
100 // owner bindings. Original facades may still own small native arrays; the
101 // physical pair owns their canonical mapped counterparts without a tail walk.
103 std::filesystem::path const & root, native_pointer native, pair_type main, native_pointer secondary) {
104 if (!binding || !binding->mapped || !native || binding->mapped->identity() != binding->identity ||
105 native->size() != binding->mapped->native_object()->size() ||
106 bool(main) != bool(binding->mapped->main_target()) || bool(secondary) != bool(binding->mapped->secondary_target()))
107 throw std::invalid_argument("inexact sealed redundant parts");
108 auto result = std::shared_ptr<redundant_node>(new redundant_node(binding->mapped,
109 std::move(native), std::move(main), std::move(secondary)));
110 result->bindings_.get_or_create(binding->catalog, root, [&] { return binding; });
111 return result;
112 }
117 std::shared_ptr<built_type const> built_;
118 std::shared_ptr<typename Storage::mapped_pair_type const> mapped_;
119 std::uint64_t depth_;
120 bool canonical_mapped_ = false;
121 explicit redundant_node(std::shared_ptr<built_type const> value)
122 : native_(value->native_owner()), secondary_(value->secondary_target()), main_(value->main_target()), built_(std::move(value)),
123 depth_(profile_detail::add(main_ ? main_->depth() : 0, 1)) {}
124 redundant_node(std::shared_ptr<typename Storage::mapped_pair_type const> value, native_pointer native, pair_type main, native_pointer secondary)
125 : native_(std::move(native)), secondary_(std::move(secondary)), main_(std::move(main)), mapped_(std::move(value)),
126 depth_(profile_detail::add(main_ ? main_->depth() : 0, 1)),
128 redundant_node(std::shared_ptr<typename Storage::mapped_pair_type const> value, pair_type main)
129 : native_(native_type::from_mapped(value->native_object())),
131 main_(std::move(main)), mapped_(std::move(value)),
132 depth_(profile_detail::add(main_ ? main_->depth() : 0, 1)), canonical_mapped_(!main_ || main_->canonical_mapped()) {}
133 };
134
135 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_object;
136 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_routes {
137 std::shared_ptr<redundant_object<P, Storage> const> main, secondary;
138 };
139 template <class P, class Storage> struct redundant_object {
142 std::uint64_t identity = 0, first = 0, last = 0;
143 unsigned level = 0;
145 pair_type pair; // Absent only for a terminal secondary.
147 bool secondary() const noexcept { return !pair; }
148 std::uint64_t mass() const noexcept { return last - first; }
149 std::uint64_t augmented() const { return pair ? pair->virtual_size() : native->size(); }
150 };
153 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_slot {
155 std::shared_ptr<redundant_object<P, Storage> const> object;
158 bool ever_visible = false;
159 };
160 // A restart recipe owns completed artifacts and exact targets, never a
161 // partially written stream or mutable cursor. Replaying partial work costs
162 // new service and puts the restored executor behind a recovery barrier.
163 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_job_recipe {
164 std::array<unsigned, 2> inputs{};
165 unsigned destination = 0, carrier_slot = 0;
166 bool new_main = false;
168 std::shared_ptr<redundant_object<P, Storage> const> existing_main, output;
172 };
173 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_level {
174 std::array<redundant_slot<P, Storage>, 3> slots{};
175 std::optional<redundant_job_recipe<P, Storage>> job;
176 std::uint64_t last_destination = 0;
178 };
179 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_frontier {
180 std::uint64_t admissions = 0, next_identity = 1, service_due = 0;
182 std::vector<redundant_level<P, Storage>> levels;
183 };
185 std::uint64_t granted = 0, charged = 0;
186 std::uint64_t native_work = 0, index_work = 0, carrier_work = 0;
187 std::uint64_t metadata_work = 0, root_work = 0;
189 std::uint64_t admissions = 0, merges = 0, indexes = 0, carriers = 0, checkpoints = 0;
190 std::uint64_t max_job_charge_per_mass = 0;
191 };
192 template <class P, class Compose, class Storage> struct redundant_runtime;
193 template <class P, class Storage = profile_runtime_storage<P>> struct redundant_snapshot {
194 using policy_type = P;
195 using storage_type = Storage;
197 using object_pointer = std::shared_ptr<redundant_object<P, Storage> const>;
198 std::uint64_t admissions() const noexcept { return state_->frontier.admissions; }
199 redundant_frontier<P, Storage> const & frontier() const & noexcept { return state_->frontier; }
200 redundant_frontier<P, Storage> const & frontier() const && = delete;
201 std::span<object_pointer const> runs() const & noexcept { return state_->runs; }
202 std::span<object_pointer const> runs() const && = delete;
203 query_type const & query_root() const & noexcept { return state_->query; }
204 query_type const & query_root() const && = delete;
205 auto cursor(bit_view key) const { return state_->query.cursor(key); }
206 auto cursor_owned(bit_string key) const { return state_->query.cursor_owned(std::move(key)); }
207 bool same_layout(redundant_snapshot const & other) const noexcept { return state_ == other.state_; }
208 // Metadata admission only. The native/index payloads must separately be
209 // admitted or trusted. Exact pointer relationships are deliberate: a
210 // persistent loader interns each immutable identity before calling this.
212 auto reject = [](bool value, char const * why) { if (!value) error_detail::raise<std::invalid_argument>(why); };
213 auto height = frontier.levels.size();
214 reject(height && height <= 64 && frontier.next_identity, "invalid redundant frontier header");
215 std::unordered_map<std::uint64_t, object_pointer> objects;
216 auto target = [&](redundant_routes<P, Storage> const & route, unsigned level) {
217 reject(!route.secondary || bool(route.main), "secondary without main");
218 if (route.main) reject(route.main->level == level && bool(route.main->pair) && bool(route.main->native), "invalid main level/role");
219 if (route.secondary) reject(route.secondary->level == level && route.secondary->secondary() && bool(route.secondary->native), "invalid secondary level/role");
220 };
221 auto pair_targets = [&](auto const & pair, redundant_routes<P, Storage> const & route) {
222 reject(bool(pair), "missing redundant pair");
223 reject(pair->main_target() == (route.main ? route.main->pair : typename redundant_node<P, Storage>::pair_type{}) &&
224 pair->secondary_target() == (route.secondary ? route.secondary->native : typename redundant_node<P, Storage>::native_pointer{}), "inexact redundant pair targets");
225 auto view = pair->view();
226 auto count = route.secondary ? route.secondary->native->size() : 0;
227 reject(view.borrowed(0).size() == (route.main ? route.main->pair->group_count() : 0) &&
228 view.borrowed(1).size() == count / P::group_size + (count % P::group_size != 0), "redundant target cardinality");
229 };
230 std::uint64_t unsafe = 0;
231 for (unsigned i = 0; i != height; ++i) {
232 auto const & level = frontier.levels[i]; unsigned active = 0, carriers = 0, staging = 0;
233 reject(level.last_destination < frontier.next_identity, "future redundant destination identity");
234 for (unsigned position = 0; position != 3; ++position) {
235 auto const & slot = level.slots[position];
237 reject(level.job && level.job->carrier_slot == position, "orphan building carrier");
238 if (slot.state == redundant_slot_state::reserved)
239 reject(i && frontier.levels[i - 1].job && frontier.levels[i - 1].job->destination == position, "orphan destination reservation");
240 active += slot.state == redundant_slot_state::active;
241 carriers += slot.state == redundant_slot_state::carrier_ready || slot.state == redundant_slot_state::root_carrier;
242 staging += slot.state == redundant_slot_state::reserved || slot.state == redundant_slot_state::carrier_building;
243 target(slot.route, i + 1);
244 if (slot.object) {
245 auto const & object = slot.object;
246 reject(object->identity && object->identity < frontier.next_identity && object->level == i && bool(object->native) &&
247 objects.emplace(object->identity, object).second, "invalid/repeated redundant object");
248 reject(object->last >= object->first && object->last <= frontier.admissions, "invalid redundant interval");
249 if (slot.state == redundant_slot_state::root_carrier)
250 reject(!i && object->first == 0 && object->last == 0 && !object->native->size() && bool(object->pair), "invalid root carrier");
251 else reject(object->mass() == (std::uint64_t{1} << i) && object->native->size() <= object->mass(), "invalid redundant object mass");
252 target(object->next, i + 1);
253 if (object->pair) { reject(object->pair->native_owner() == object->native, "inexact redundant native owner"); pair_targets(object->pair, object->next); }
254 else reject(!object->next.main && !object->next.secondary, "recursive redundant secondary");
255 }
256 switch (slot.state) {
258 reject(!slot.object && !slot.route.main && !slot.route.secondary && !slot.carrier && !slot.ever_visible, "nonempty vacant slot"); break;
260 reject(bool(slot.object) && !slot.route.main && !slot.route.secondary && !slot.carrier, "invalid occupied slot"); break;
262 reject(!slot.object && !slot.route.main && !slot.route.secondary && !slot.carrier, "invalid building carrier"); break;
264 reject(!slot.object && bool(slot.route.main), "invalid ready carrier");
265 pair_targets(slot.carrier, slot.route); reject(!slot.carrier->native_owner()->size(), "carrier has natives"); break;
267 reject(bool(slot.object) && !slot.carrier, "invalid root carrier slot");
268 pair_targets(slot.object->pair, slot.route); break;
270 default: reject(false, "unknown redundant slot state");
271 }
272 }
273 reject(active <= 2 && carriers <= 1 && staging <= 1, "invalid redundant slot populations");
274 if (active == 2 || level.job) unsafe |= std::uint64_t{1} << i;
275 if (level.job) {
276 auto const & job = *level.job;
277 reject(i + 1 < height && job.inputs[0] < 3 && job.inputs[1] < 3 && job.inputs[0] != job.inputs[1] &&
278 job.destination < 3 && job.carrier_slot < 3, "invalid redundant job slots");
279 auto const & a = level.slots[job.inputs[0]], & b = level.slots[job.inputs[1]];
280 reject(a.state == redundant_slot_state::active && b.state == redundant_slot_state::active && a.object->last == b.object->first &&
281 level.slots[job.carrier_slot].state == redundant_slot_state::carrier_building &&
282 frontier.levels[i + 1].slots[job.destination].state == redundant_slot_state::reserved, "invalid redundant job reservation");
283 target(job.destination_route, i + 2);
284 reject(job.new_main ? !job.existing_main : (job.existing_main && job.existing_main->level == i + 1 && bool(job.existing_main->pair)), "invalid destination main");
285 auto const & destination = frontier.levels[i + 1].slots[job.destination];
286 reject(destination.route.main == job.destination_route.main && destination.route.secondary == job.destination_route.secondary,
287 "inexact destination reservation route");
289 reject(!destination.object, "premature reserved output");
290 if (job.stage != redundant_stage::native_merge)
291 reject(job.merged && job.merged->size() <= b.object->last - a.object->first, "invalid merged native");
293 reject(!job.output && !job.carrier && (job.stage != redundant_stage::destination_index || job.new_main), "premature job artifact");
294 else {
295 reject(job.output && job.output == frontier.levels[i + 1].slots[job.destination].object &&
296 job.output->native == job.merged && job.output->first == a.object->first && job.output->last == b.object->last &&
297 job.output->secondary() != job.new_main, "invalid destination artifact");
298 if (job.stage == redundant_stage::commit) {
299 auto route = job.new_main ? redundant_routes<P, Storage>{job.output, {}} : redundant_routes<P, Storage>{job.existing_main, job.output};
300 pair_targets(job.carrier, route); reject(!job.carrier->native_owner()->size(), "nonempty lookahead carrier");
301 } else reject(job.stage == redundant_stage::carrier_index && !job.carrier, "invalid job phase");
302 }
303 }
304 }
305 reject(!(unsafe & (unsafe << 1)), "adjacent unsafe checkpoint levels");
306 auto bound = profile_detail::add(profile_detail::multiply(profile_detail::add(P::group_size, 6), 32), 2048);
307 auto allowance = profile_detail::multiply(profile_detail::multiply(bound, 8),
308 std::bit_width(frontier.admissions) + 2);
309 reject(frontier.service_due <= allowance && (unsafe || !frontier.service_due), "invalid checkpoint service obligation");
310 auto owned = [&](object_pointer const & value) { if (value) reject(objects.contains(value->identity) && objects.at(value->identity) == value, "dependency escaped redundant slots"); };
311 for (auto const & [id, value] : objects) { (void)id; owned(value->next.main); owned(value->next.secondary); }
312 for (auto const & level : frontier.levels) {
313 for (auto const & slot : level.slots) { owned(slot.route.main); owned(slot.route.secondary); }
314 if (level.job) { auto const & job = *level.job; owned(job.existing_main); owned(job.output); owned(job.destination_route.main); owned(job.destination_route.secondary); }
315 }
316 target(frontier.root, 0); owned(frontier.root.main); owned(frontier.root.secondary);
317 auto query = query_type::adopt_prepared(head);
318 if (!frontier.root.main) reject(!frontier.admissions && !head->virtual_size() && !head->main_target() && !head->secondary_target(), "nonempty unrooted checkpoint");
319 else {
320 auto p = head;
321 if (!frontier.root.secondary) {
322 while (p != frontier.root.main->pair) { reject(p && !p->native_owner()->size() && !p->secondary_target(), "checkpoint root differs from frontier"); p = p->main_target(); }
323 } else {
324 while (p && !(p->main_target() == frontier.root.main->pair && p->secondary_target() == frontier.root.secondary->native)) {
325 reject(!p->native_owner()->size() && !p->secondary_target(), "checkpoint root differs from frontier"); p = p->main_target();
326 }
327 reject(p && !p->native_owner()->size(), "missing two-root entry carrier");
328 }
329 }
330 std::vector<object_pointer> runs; std::unordered_set<std::uint64_t> visible;
331 auto walk = [&](auto && self, object_pointer const & value) -> void {
332 if (!value) return;
333 reject(visible.insert(value->identity).second, "repeated visible checkpoint object");
334 self(self, value->next.main); self(self, value->next.secondary);
335 if (value->mass()) runs.push_back(value);
336 };
337 walk(walk, frontier.root.main); walk(walk, frontier.root.secondary);
338 std::uint64_t next = 0;
339 for (auto const & run : runs) { reject(run->first == next, "checkpoint chronology gap"); next = run->last; }
340 reject(next == frontier.admissions, "checkpoint chronology extent");
341 for (auto const & level : frontier.levels) for (auto const & slot : level.slots)
342 if (slot.object && visible.contains(slot.object->identity)) reject(slot.ever_visible, "visible object lacks visibility history");
343 return redundant_snapshot(std::make_shared<state const>(state{std::move(frontier), std::move(query), std::move(runs)}));
344 }
345 private:
346 template <class, class, class> friend struct redundant_runtime;
347 struct state {
350 std::vector<object_pointer> runs;
351 };
352 std::shared_ptr<state const> state_;
353 explicit redundant_snapshot(std::shared_ptr<state const> value) : state_(std::move(value)) {}
354 };
355
356 // The scheduler uses admission mass, not surviving key count. At most three
357 // logical slots occupy each level; historical snapshots retain their own
358 // exact graphs. Only main routes recurse. All composition is oldest first.
359 // Service charges record/directory/metadata operations, not key bytes or
360 // elapsed time. Existing EF finalizers remain atomic after their allowance
361 // has been funded. This is not a hard per-call latency or I/O bound.
362 template <class P, class Compose = replace_native_value, class Storage = profile_runtime_storage<P>> struct redundant_runtime {
363 using policy_type = P;
364 using storage_type = Storage;
372 using object_pointer = std::shared_ptr<object_type const>;
375 static constexpr unsigned maximum_levels = 64;
376 static_assert(P::group_size <= (std::numeric_limits<std::uint64_t>::max() - 2240) / 32, "redundant policy charge is not representable");
377 static constexpr std::uint64_t local_charge_bound = 32 * (P::group_size + 6) + 2048;
378 static std::uint64_t service_budget(std::uint64_t admissions) {
380 std::bit_width(admissions) + 2);
381 }
382 explicit redundant_runtime(Compose compose = {}) : redundant_runtime(Storage{}, std::move(compose)) {}
383 redundant_runtime(Storage storage, Compose compose = {}) : e_(std::make_unique<execution>(std::move(storage), std::move(compose))) {}
384 static redundant_runtime from_snapshot(snapshot_type source, Compose compose = {}) {
385 return from_snapshot(std::move(source), Storage{}, std::move(compose));
386 }
387 static redundant_runtime from_snapshot(snapshot_type source, Storage storage, Compose compose = {}) {
388 return redundant_runtime(std::make_unique<execution>(std::move(source), std::move(storage), std::move(compose)));
389 }
390 Storage const & storage() const & { return active().storage; }
391 Storage const & storage() const && = delete;
393 redundant_runtime & operator=(redundant_runtime const &) = delete;
394 redundant_runtime(redundant_runtime &&) noexcept = default;
395 redundant_runtime & operator=(redundant_runtime &&) noexcept = default;
397 redundant_work work() const { return active().work; }
398 std::uint64_t service_due() const { return active().service_due; }
399 // Explicit metadata-only capture; unlike snapshot(), this charges and
400 // allocates a new full frontier, without finalizing or scanning a payload.
402 auto & e = writable();
403 try { e.direct(e.checkpoint_price(), category::metadata); e.checkpoint(); }
404 catch (...) { e.poison(); throw; }
405 return e.published;
406 }
407 bool pending() const noexcept { return e_ && (e_->unsafe || e_->checkpoint_pending); }
408 bool failed() const noexcept { return e_ && e_->failed; }
409 void poison() noexcept { if (e_) e_->poison(); }
410 bool admission_ready() const noexcept { return e_ && e_->ready(); }
411 bool recovering() const noexcept { return e_ && e_->recovery; }
412 std::uint64_t credit() const { return active().credit; }
413 std::uint64_t next_service_cost() const { return active().price(); }
414 std::uint64_t admission_cost() const { auto const & e = active(); e.require_ready(); return e.admission_price(); }
415 // Initial construction only: a sorted power-of-two batch seeds the same
416 // consecutive-level topology as ordinary admission, then services its
417 // carry chain. Ineligible calls leave both the input and executor alone.
418 // The allowance charges structural events, not bytes or elapsed time.
419 bool try_initialize_sorted(std::span<profile_record const> records, std::uint64_t allowance,
420 std::uint64_t depth_limit)
421 requires requires (Storage & storage) { storage.sorted_native(records); } {
422 auto & e = writable();
423 auto count = static_cast<std::uint64_t>(records.size());
424 if (!e.initializable() || count < 2 || !std::has_single_bit(count)) return false;
425 auto height = static_cast<unsigned>(std::bit_width(count) - 1);
426 if (height + 1 > depth_limit || execution::initialization_price(count) > allowance) return false;
427 for (std::size_t i = 0; i != records.size(); ++i) {
428 validate(records[i]);
429 if (i && compare_bits<typename P::architecture>(records[i - 1].key.view(), records[i].key.view()) >= 0)
430 error_detail::raise<std::invalid_argument>("initial records must be strictly sorted");
431 }
432 auto prior = e.published;
433 try { e.initialize_sorted(records, allowance, depth_limit); }
434 catch (...) { e.published = std::move(prior); e.poison(); throw; }
435 return true;
436 }
437 snapshot_type advance(std::uint64_t budget) {
438 auto & e = writable();
439 if (!budget || !pending()) return e.published;
440 try { e.grant(budget); e.service_due -= std::min(e.service_due, budget); e.serve(); }
441 catch (...) { e.poison(); throw; }
442 return e.published;
443 }
444 std::optional<snapshot_type> try_contribute(profile_record const & record, std::uint64_t budget = 0) {
445 auto & e = writable();
446 if (!e.ready()) return std::nullopt;
447 validate(record); (void)add(e.admissions, 1);
448 auto prior = e.published;
449 try { e.admit(record); if (budget) { e.grant(budget); e.service_due -= std::min(e.service_due, budget); e.serve(); } }
450 catch (...) { e.published = std::move(prior); e.poison(); throw; }
451 return e.published;
452 }
454 auto & e = writable(); validate(record);
455 auto allowance = service_budget(add(e.admissions, 1));
456 if (!e.ready()) advance(allowance);
457 if (!e.ready()) error_detail::raise<std::logic_error>("redundant admission needs additional recovery service");
458 return *try_contribute(record, allowance);
459 }
460 private:
461 static std::uint64_t add(std::uint64_t a, std::uint64_t b) { return profile_detail::add(a, b); }
462 static std::uint64_t ceil(std::uint64_t n, std::uint64_t d) { return n / d + (n % d != 0); }
463 static void require(bool value, char const * message) { if (!value) error_detail::raise<std::logic_error>(message); }
464 static void validate(profile_record const & record) {
465 auto key = record.key.view(), value = record.value.view();
466 if ((key.size() & (P::bits_per_unit - 1)) || (value.size() & (P::bits_per_unit - 1)) ||
467 (P::value_width && value.size() / P::bits_per_unit != *P::value_width))
468 error_detail::raise<std::invalid_argument>("invalid encoded redundant contribution");
469 }
470 using merge_compose = std::conditional_t<std::is_same_v<Compose, replace_native_value>, Compose, std::reference_wrapper<Compose>>;
471 using merge_type = typename Storage::template merge_type<merge_compose>;
472 using index_type = typename Storage::template index_type<node_type>;
475 struct worker {
477 std::unique_ptr<merge_type> merge;
478 std::unique_ptr<index_type> index;
479 std::uint64_t charged = 0;
480 };
481 struct execution {
482 Storage storage; // Outlives workers whose file outputs borrow its concrete context.
483 Compose compose;
486 std::array<level_type, maximum_levels> levels{};
487 std::array<std::unique_ptr<worker>, maximum_levels> workers{};
488 unsigned height = 1;
489 std::uint64_t admissions = 0, next_identity = 1, unsafe = 0, credit = 0, service_due = 0;
494 bool failed = false, recovery = false, checkpoint_pending = false, changed = false;
495 void poison() noexcept {
496 failed = true;
497 if constexpr (requires { { storage.poison() } noexcept; }) storage.poison();
498 }
499 native_pointer make_empty() { return storage.empty(); }
503 return snapshot_type(std::make_shared<typename snapshot_type::state const>(typename snapshot_type::state{
504 std::move(f), query_type::adopt_prepared(std::move(pair)), {}}));
505 }
506 execution(Storage context, Compose value) : storage(std::move(context)), compose(std::move(value)), empty(make_empty()), empty_pair(make_empty_pair(empty)),
508 execution(snapshot_type source, Storage context, Compose value) : storage(std::move(context)), compose(std::move(value)), empty(make_empty()), empty_pair(make_empty_pair(empty)),
509 query(source.query_root()), published(std::move(source)) {
510 auto const & f = published.frontier();
511 require(!f.levels.empty() && f.levels.size() <= maximum_levels, "invalid redundant checkpoint height");
512 height = static_cast<unsigned>(f.levels.size()); admissions = f.admissions; next_identity = f.next_identity; root = f.root; service_due = f.service_due;
513 for (unsigned i = 0; i != height; ++i) {
514 levels[i] = f.levels[i];
515 if (levels[i].job) {
516 workers[i] = std::make_unique<worker>();
517 auto stage = levels[i].job->stage;
520 }
521 refresh(i);
522 }
523 recovery = unsafe != 0;
525 }
526 struct active_slots { std::array<unsigned, 2> positions{}; unsigned count = 0; };
527 active_slots active(unsigned i) const {
528 active_slots out;
529 for (unsigned s = 0; s != 3; ++s) if (levels[i].slots[s].state == redundant_slot_state::active) {
530 require(out.count < 2, "too many active redundant slots"); out.positions[out.count++] = s;
531 }
532 if (out.count == 2 && levels[i].slots[out.positions[0]].object->first > levels[i].slots[out.positions[1]].object->first)
533 std::swap(out.positions[0], out.positions[1]);
534 return out;
535 }
536 std::optional<unsigned> find(unsigned i, redundant_slot_state state) const {
537 for (unsigned s = 0; s != 3; ++s) if (levels[i].slots[s].state == state) return s;
538 return {};
539 }
540 unsigned vacant(unsigned i) const { auto found = find(i, redundant_slot_state::empty); require(bool(found), "no redundant shadow slot"); return *found; }
541 bool ready() const noexcept {
542 if (failed || recovery || checkpoint_pending || service_due || levels[0].job) return false;
543 unsigned count = 0;
544 for (auto const & slot : levels[0].slots) count += slot.state == redundant_slot_state::active;
545 return count < 2;
546 }
547 void require_ready() const { require(ready(), "redundant admission is not ready"); }
548 bool initializable() const noexcept {
550 unsafe || credit || service_due || height != 1 || root.main || root.secondary ||
551 work.admissions || levels[0].job || levels[0].last_destination || levels[0].last_destination_visible)
552 return false;
553 for (auto const & slot : levels[0].slots)
554 if (slot.state != redundant_slot_state::empty || slot.object || slot.route.main ||
555 slot.route.secondary || slot.carrier || slot.ever_visible) return false;
556 return true;
557 }
558 void refresh(unsigned i) {
559 auto flag = std::uint64_t{1} << i;
560 if (levels[i].job || active(i).count == 2) unsafe |= flag; else unsafe &= ~flag;
561 }
562 merge_compose merger() { if constexpr (std::is_same_v<Compose, replace_native_value>) return compose; else return std::ref(compose); }
563 static std::uint64_t augmented(object_pointer const & object) { return object ? object->augmented() : 0; }
564 static std::uint64_t index_price(std::uint64_t native, std::uint64_t main, std::uint64_t secondary) {
565 auto a = ceil(main, P::group_size), b = ceil(secondary, P::group_size);
566 auto n = add(add(native, a), b);
567 return add(add(10, profile_detail::multiply(n, P::group_size + 6)),
568 add(ceil(a, P::codec_block_size), ceil(b, P::codec_block_size)));
569 }
570 static std::uint64_t root_price(std::uint64_t main, std::uint64_t secondary) {
571 if (!secondary && main <= P::group_size) return 0;
572 std::uint64_t result = 0;
573 do {
574 result = add(result, index_price(0, main, secondary));
575 main = add(ceil(main, P::group_size), ceil(secondary, P::group_size)); secondary = 0;
576 } while (main > P::group_size);
577 return result;
578 }
579 static std::uint64_t initial_native_price(std::uint64_t count) {
580 return add(profile_detail::multiply(count, 3), add(ceil(count, P::codec_block_size), 4));
581 }
582 static std::uint64_t initialization_price(std::uint64_t count) {
583 auto h = static_cast<unsigned>(std::bit_width(count) - 1);
584 std::uint64_t result = 0, main = 0;
585 for (unsigned i = static_cast<unsigned>(h); i--;) {
586 auto size = std::uint64_t{1} << i;
587 result = add(result, add(initial_native_price(size), index_price(size, main, 0)));
588 main = add(size, ceil(main, P::group_size));
589 }
590 result = add(result, initial_native_price(1));
591 result = add(result, add(root_price(main, 1), 6 * h + 8));
592 // Initial checkpoint and its independent shape/chronology validation.
593 result = add(result, add(8 * h + 16, 64 * (h + 1) + 64));
594 // Exactly one ordinary carry at each source level, with masses
595 // 1,2,...,N/2. Checkpoints are outside the checked local job ceiling.
596 result = add(result, profile_detail::multiply(local_charge_bound, count - 1));
597 return add(result, 2 * (8 * (h + 1) + 16));
598 }
599 std::uint64_t checkpoint_price() const { return 8 * height + 16; }
600 std::uint64_t visibility_price() const { return 6 * height + 8; }
601 void tally(std::uint64_t amount, category kind) {
602 auto next = work; next.charged = add(next.charged, amount);
605 next.*field = add(next.*field, amount); work = next;
606 }
607 void direct(std::uint64_t amount, category kind) { auto total = add(work.granted, amount); tally(amount, kind); work.granted = total; }
608 void grant(std::uint64_t amount) { auto next = add(credit, amount), total = add(work.granted, amount); credit = next; work.granted = total; }
609 void initialize_sorted(std::span<profile_record const> records, std::uint64_t allowance,
610 std::uint64_t depth_limit) {
611 require(initializable(), "redundant initial construction requires an empty runtime");
612 auto count = static_cast<std::uint64_t>(records.size());
613 height = static_cast<unsigned>(std::bit_width(count) - 1);
614 grant(allowance);
615 auto spend = [&](std::uint64_t amount, category kind) {
616 require(credit >= amount, "initial construction exhausted its allowance");
617 tally(amount, kind); credit -= amount;
618 };
619 spend(64 * (std::uint64_t(height) + 1) + 64, category::metadata);
620 std::uint64_t first = 0;
621 routes next;
622 auto build_native = [&](std::uint64_t size) {
624 auto native = storage.sorted_native(records.subspan(static_cast<std::size_t>(first), static_cast<std::size_t>(size)));
625 require(native && native->size() == size, "initial native cardinality mismatch");
627 return native;
628 };
629 for (unsigned i = height; i--;) {
630 auto size = std::uint64_t{1} << i;
631 auto native = build_native(size);
632 spend(index_price(size, augmented(next.main), 0), category::index);
633 auto pair = build_index(native, next);
634 auto last = add(first, size);
635 auto value = object(std::move(native), std::move(pair), next, i, first, last);
636 levels[i].slots[0] = {redundant_slot_state::active, value, {}, {}, false};
637 first = last; next = {std::move(value), {}};
638 }
639 auto secondary = object(build_native(1), {}, {}, 0, first, count);
640 levels[0].slots[1] = {redundant_slot_state::active, secondary, {}, {}, false};
641 root = {next.main, std::move(secondary)};
642 admissions = count; work.admissions = add(work.admissions, count);
643 for (unsigned i = 0; i != height; ++i) refresh(i);
644 require(unsafe == 1, "initial frontier has more than one unsafe level");
645 service_due = service_budget(count); recovery = true;
647 visibility();
648 require(query.head()->depth() <= depth_limit, "initial root exceeds depth limit");
652 service_due -= std::min(service_due, credit);
653 serve();
655 "initial carry chain exhausted its allowance");
656 require(query.head()->depth() <= depth_limit, "initialized root exceeds depth limit");
657 }
658 object_pointer object(native_pointer native, pair_type pair, routes next, unsigned level, std::uint64_t first, std::uint64_t last) {
660 return std::make_shared<object_type const>(object_type{id, first, last, level, std::move(native), std::move(pair), std::move(next)});
661 }
663 auto builder = storage.template make_index<node_type>(std::move(native),
664 target.main ? target.main->pair : pair_type{}, target.secondary ? target.secondary->native : native_pointer{});
665 while (!builder->done()) { auto n = builder->step(1); work.index_occurrences = add(work.index_occurrences, n); }
666 auto pair = storage.template finish_index<node_type>(*builder); work.indexes = add(work.indexes, 1); return pair;
667 }
669 if (!main) return empty_pair;
670 if (!secondary && main->virtual_size() <= P::group_size) return main;
671 do {
672 auto builder = storage.template make_index<node_type>(empty, main, secondary);
673 while (!builder->done()) { auto n = builder->step(1); work.index_occurrences = add(work.index_occurrences, n); }
674 main = storage.template finish_index<node_type>(*builder); secondary.reset();
676 } while (main->virtual_size() > P::group_size);
677 return main;
678 }
679 template <class F> static void visit(object_pointer const & value, F & fn) {
680 if (!value) return;
681 fn(value);
682 visit(value->next.main, fn); visit(value->next.secondary, fn);
683 }
684 void visibility() {
685 std::array<unsigned char, maximum_levels> visible{};
686 auto mark = [&](object_pointer const & value) {
687 require(value->level < height, "visible redundant level out of range");
688 auto & level = levels[value->level]; bool found = false;
689 for (unsigned s = 0; s != 3; ++s) if (level.slots[s].object == value) {
690 require(!(visible[value->level] & (1u << s)), "repeated visible redundant object");
691 visible[value->level] |= static_cast<unsigned char>(1u << s);
692 level.slots[s].ever_visible = true; found = true;
693 }
694 require(found, "visible redundant object escaped slots");
695 if (level.last_destination == value->identity) level.last_destination_visible = true;
696 };
697 visit(root.main, mark); visit(root.secondary, mark);
698 for (unsigned i = 0; i != height; ++i) for (unsigned s = 0; s != 3; ++s) {
699 auto & slot = levels[i].slots[s];
700 if (slot.state == redundant_slot_state::consumed && slot.ever_visible && !(visible[i] & (1u << s))) slot = {};
701 }
702 auto prepared = prepare_root(root.main ? root.main->pair : pair_type{}, root.secondary ? root.secondary->native : native_pointer{});
703 query = query_type::adopt_prepared(std::move(prepared)); changed = true;
704 }
705 void checkpoint() {
706 if (!unsafe) service_due = 0;
708 f.levels.assign(levels.begin(), levels.begin() + height);
709 std::vector<object_pointer> runs;
710 auto walk = [&](auto && self, object_pointer const & value) -> void {
711 if (!value) return;
712 self(self, value->next.main); self(self, value->next.secondary);
713 if (value->mass()) runs.push_back(value);
714 };
715 walk(walk, root.main); walk(walk, root.secondary);
716 std::uint64_t next = 0;
717 for (auto const & value : runs) { require(value->first == next, "redundant history gap or overlap"); next = value->last; }
718 require(next == admissions, "redundant checkpoint omits admissions");
719 auto state = std::make_shared<typename snapshot_type::state const>(typename snapshot_type::state{std::move(f), query, std::move(runs)});
720 published = snapshot_type(std::move(state)); work.checkpoints = add(work.checkpoints, 1);
721 checkpoint_pending = false; changed = false;
722 if (!unsafe) { recovery = false; credit = 0; service_due = 0; }
723 }
724 std::uint64_t admission_price() const {
725 auto entries = active(0); routes route;
726 if (!entries.count) if (auto c = find(0, redundant_slot_state::root_carrier)) route = levels[0].slots[*c].route;
727 auto main = entries.count ? augmented(levels[0].slots[entries.positions[0]].object) :
728 add(1, add(ceil(augmented(route.main), P::group_size), ceil(augmented(route.secondary), P::group_size)));
729 auto result = add(12, add(checkpoint_price(), visibility_price()));
730 if (!entries.count) result = add(result, index_price(1, augmented(route.main), augmented(route.secondary)));
731 return add(result, root_price(main, entries.count ? 1 : 0));
732 }
733 void admit(profile_record const & record) {
735 auto native = storage.singleton(record);
737 auto entries = active(0); unsigned pos; routes route; pair_type pair;
738 if (entries.count) pos = vacant(0);
739 else {
740 auto c = find(0, redundant_slot_state::root_carrier); pos = c ? *c : vacant(0);
741 if (c) route = levels[0].slots[pos].route;
742 pair = build_index(native, route);
743 }
744 auto next = add(admissions, 1);
745 auto value = object(std::move(native), std::move(pair), route, 0, admissions, next);
746 levels[0].slots[pos] = {redundant_slot_state::active, value, {}, {}, false};
747 if (entries.count) root.secondary = value; else root = {value, {}};
750 }
751 unsigned selected() const { require(unsafe != 0, "no unsafe redundant level"); return std::countr_zero(unsafe); }
752 routes index_targets(unsigned i) const {
753 auto const & r = *levels[i].job;
754 if (r.stage == redundant_stage::destination_index) return r.destination_route;
755 return r.new_main ? routes{r.output, {}} : routes{r.existing_main, r.output};
756 }
757 std::uint64_t price() const {
759 if (!unsafe) return 0;
760 auto i = selected();
761 if (!levels[i].job) return 8;
762 auto const & r = *levels[i].job; auto const & w = *workers[i];
763 switch (w.next) {
764 case action::native_start: return 3;
765 case action::native_step: return 3;
766 case action::native_finish: return add(ceil(w.merge->progress().keys, P::codec_block_size), 2);
767 case action::index_start: return 5;
768 case action::index_step: return P::group_size + 6;
770 auto t = index_targets(i);
771 return add(5, add(ceil(ceil(augmented(t.main), P::group_size), P::codec_block_size),
772 ceil(ceil(augmented(t.secondary), P::group_size), P::codec_block_size)));
773 }
774 case action::commit:
775 return i ? 8 : add(8, add(visibility_price(), root_price(r.carrier->virtual_size(), 0)));
776 }
777 error_detail::raise<std::logic_error>("invalid redundant worker action");
778 }
779 category charge_kind(unsigned i) const {
780 if (!levels[i].job) return category::metadata;
781 auto const & w = *workers[i];
782 if (w.next == action::commit) return i ? category::metadata : category::root;
783 auto stage = levels[i].job->stage;
786 }
787 void begin(unsigned i) {
788 auto input = active(i); require(input.count == 2, "redundant merge needs two active inputs");
789 require(i + 1 < maximum_levels, "redundant admission mass overflow");
790 if (i + 1 == height) ++height;
791 require(!(unsafe & (std::uint64_t{1} << (i + 1))), "adjacent unsafe redundant levels");
792 auto & destination = levels[i + 1];
793 require(!destination.last_destination || destination.last_destination_visible, "destination reused before visibility");
795 auto dest = carrier ? *carrier : vacant(i + 1);
796 auto present = active(i + 1); require(present.count <= 1 && (!carrier || !present.count), "invalid destination occupancy");
797 auto older = levels[i].slots[input.positions[0]].object, newer = levels[i].slots[input.positions[1]].object;
798 auto mass = std::uint64_t{1} << i;
799 require(older->last == newer->first && older->mass() == mass && newer->mass() == mass, "nonadjacent redundant merge history");
801 recipe.inputs = input.positions; recipe.destination = dest; recipe.carrier_slot = vacant(i);
802 recipe.destination_route = carrier ? destination.slots[dest].route : routes{};
803 recipe.new_main = bool(carrier) || !present.count;
804 if (present.count) {
805 recipe.existing_main = destination.slots[present.positions[0]].object;
806 require(!recipe.existing_main->secondary(), "single destination is secondary");
807 }
808 auto worker = std::make_unique<typename redundant_runtime::worker>();
809 worker->charged = 8;
810 levels[i].slots[recipe.carrier_slot] = {redundant_slot_state::carrier_building, {}, {}, {}, false};
811 destination.slots[dest].state = redundant_slot_state::reserved;
812 levels[i].job = std::move(recipe); workers[i] = std::move(worker); changed = true;
813 }
815 auto & r = *levels[i].job; auto & w = *workers[i];
816 r.merged = std::move(native);
817 if (r.new_main) r.stage = redundant_stage::destination_index;
818 else {
819 auto older = levels[i].slots[r.inputs[0]].object;
820 auto newer = levels[i].slots[r.inputs[1]].object;
821 r.output = object(r.merged, {}, {}, i + 1, older->first, newer->last);
822 levels[i + 1].slots[r.destination].object = r.output;
824 }
825 w.next = action::index_start; changed = true;
826 }
827 void perform(unsigned i) {
828 if (!levels[i].job) { begin(i); return; }
829 auto & r = *levels[i].job; auto & w = *workers[i];
830 auto source = [&](unsigned which) { return levels[i].slots[r.inputs[which]].object; };
831 switch (w.next) {
833 if constexpr (requires { storage.template reuse_merge<merge_compose>(source(0)->native, source(1)->native); }) {
834 if (auto result = storage.template reuse_merge<merge_compose>(source(0)->native, source(1)->native)) {
835 complete_native(i, std::move(result)); work.native_reuses = add(work.native_reuses, 1); break;
836 }
837 }
838 w.merge = storage.template make_merge<merge_compose>(source(0)->native, source(1)->native, merger());
839 w.next = w.merge->done() ? action::native_finish : action::native_step;
840 break;
841 case action::native_step: {
842 auto done = w.merge->step(1);
843 work.native_inputs = add(work.native_inputs, done.input_records); work.native_outputs = add(work.native_outputs, done.keys);
844 if (w.merge->done()) w.next = action::native_finish;
845 break;
846 }
848 auto result = storage.finish_merge(*w.merge); w.merge.reset();
849 complete_native(i, std::move(result)); break;
850 }
851 case action::index_start: {
852 auto t = index_targets(i);
853 w.index = storage.template make_index<node_type>(r.stage == redundant_stage::destination_index ? r.merged : empty,
854 t.main ? t.main->pair : pair_type{}, t.secondary ? t.secondary->native : native_pointer{});
855 w.next = w.index->done() ? action::index_finish : action::index_step;
856 break;
857 }
859 work.index_occurrences = add(work.index_occurrences, w.index->step(1));
860 if (w.index->done()) w.next = action::index_finish;
861 break;
863 auto pair = storage.template finish_index<node_type>(*w.index); w.index.reset(); work.indexes = add(work.indexes, 1);
864 if (r.stage == redundant_stage::destination_index) {
865 r.output = object(r.merged, std::move(pair), r.destination_route, i + 1, source(0)->first, source(1)->last);
866 levels[i + 1].slots[r.destination].object = r.output;
868 } else {
869 r.carrier = std::move(pair); r.stage = redundant_stage::commit; w.next = action::commit;
871 }
872 changed = true;
873 break;
874 }
875 case action::commit: {
876 auto recipe = r; auto charge = w.charged; auto mass = std::uint64_t{1} << i;
877 require(ceil(charge, mass) <= local_charge_bound, "redundant local structural bound exceeded");
879 for (auto input : recipe.inputs) levels[i].slots[input].state = redundant_slot_state::consumed;
880 auto target = recipe.new_main ? routes{recipe.output, {}} : routes{recipe.existing_main, recipe.output};
881 levels[i].slots[recipe.carrier_slot] = {redundant_slot_state::carrier_ready, {}, target, recipe.carrier, false};
882 auto & destination = levels[i + 1];
883 destination.slots[recipe.destination] = {redundant_slot_state::active, recipe.output, {}, {}, false};
884 destination.last_destination = recipe.output->identity; destination.last_destination_visible = false;
885 levels[i].job.reset(); workers[i].reset(); work.merges = add(work.merges, 1);
886 refresh(i); refresh(i + 1); changed = true;
887 if (!i) {
888 auto value = object(empty, recipe.carrier, target, 0, 0, 0);
889 levels[0].slots[recipe.carrier_slot] = {redundant_slot_state::root_carrier, value, target, {}, false};
890 root = {std::move(value), {}}; visibility(); checkpoint_pending = true;
891 } else if (!unsafe) checkpoint_pending = true;
892 break;
893 }
894 }
895 }
896 void serve() {
897 while (unsafe || checkpoint_pending) {
898 auto amount = price();
899 if (credit < amount) break;
900 if (checkpoint_pending) {
901 tally(amount, category::metadata); credit -= amount; checkpoint();
902 } else {
903 auto i = selected(); tally(amount, charge_kind(i)); credit -= amount;
904 if (workers[i]) workers[i]->charged = add(workers[i]->charged, amount);
905 perform(i);
906 }
907 }
908 if (!unsafe && !checkpoint_pending) { recovery = false; credit = 0; service_due = 0; }
909 }
910 };
911 std::unique_ptr<execution> e_;
912 explicit redundant_runtime(std::unique_ptr<execution> value) : e_(std::move(value)) {}
913 execution const & active() const { if (!e_) error_detail::raise<std::logic_error>("moved-from redundant runtime"); return *e_; }
914 execution & writable() { (void)active(); if (e_->failed) error_detail::raise<std::logic_error>("failed redundant runtime"); return *e_; }
915 };
916 // Select this executor through the same typed/storage family seam as the
917 // conservative binary backend, without changing the encoded policy.
932}
Executes charged encoded COLA carries behind immutable queryable snapshots.
std::uint64_t add(std::uint64_t a, std::uint64_t b)
Definition profile.h:39
std::uint64_t multiply(std::uint64_t a, std::uint64_t b)
Definition profile.h:44
Definition active_engine.h:18
redundant_slot_state
Definition redundant_runtime.h:151
redundant_stage
Definition redundant_runtime.h:152
encoded_sections< P > encode_native_sections(profile_array< P, stream_role::native > const &native)
Definition sections.h:405
Definition profile.h:166
bit_view view() const &
Definition profile.h:178
Definition profile.h:56
Definition catalog_bindings.h:25
Definition cola_index.h:496
auto finish()
Definition cola_index.h:581
Definition cola_index.h:114
std::uint64_t virtual_size() const noexcept
Definition cola_index.h:144
std::uint64_t group_count() const noexcept
Definition cola_index.h:145
Definition cola_index.h:315
static cola_query_root adopt_prepared(pair_type source)
Definition cola_query.h:47
pair_type head() const noexcept
Definition cola_query.h:63
cola_query_cursor< P, Blob > cursor(bit_view query) const
Definition cola_query.h:64
Definition cola_runtime.h:31
static std::shared_ptr< cola_runtime_native const > from_owned(profile_array< P > value)
Definition cola_runtime.h:33
Definition mapped_cola.h:33
Definition sections.h:442
Definition native_merge.h:174
Definition runtime_seal.h:36
Definition profile.h:1168
Definition native_writer.h:158
void append(bit_view key, bit_view value, std::optional< std::uint64_t > retained_limit_bits={})
Definition native_writer.h:181
profile_array< P > finish()
Definition native_writer.h:208
Definition profile.h:294
bit_string key
Definition profile.h:295
bit_string value
Definition profile.h:296
Definition redundant_runtime.h:21
static auto singleton(profile_record const &record)
Definition redundant_runtime.h:39
static auto finish_index(index_type< Node > &index)
Definition redundant_runtime.h:37
static auto finish_merge(Merge &merge)
Definition redundant_runtime.h:31
static auto sorted_native(std::span< profile_record const > records)
Definition redundant_runtime.h:42
static auto make_merge(std::shared_ptr< native_type const > older, std::shared_ptr< native_type const > newer, Compose compose)
Definition redundant_runtime.h:27
static auto empty()
Definition redundant_runtime.h:38
static auto make_index(std::shared_ptr< native_type const > native, typename Node::pair_type main={}, std::shared_ptr< native_type const > secondary={})
Definition redundant_runtime.h:33
static auto encode_native(profile_array< P > const &value)
Definition redundant_runtime.h:25
Definition query.h:51
Definition redundant_runtime.h:179
redundant_routes< P, Storage > root
Definition redundant_runtime.h:181
std::uint64_t next_identity
Definition redundant_runtime.h:180
std::uint64_t admissions
Definition redundant_runtime.h:180
std::uint64_t service_due
Definition redundant_runtime.h:180
std::vector< redundant_level< P, Storage > > levels
Definition redundant_runtime.h:182
Definition redundant_runtime.h:163
std::shared_ptr< redundant_object< P, Storage > const > existing_main
Definition redundant_runtime.h:168
redundant_routes< P, Storage > destination_route
Definition redundant_runtime.h:167
redundant_stage stage
Definition redundant_runtime.h:171
redundant_node< P, Storage >::native_pointer merged
Definition redundant_runtime.h:169
unsigned destination
Definition redundant_runtime.h:165
std::array< unsigned, 2 > inputs
Definition redundant_runtime.h:164
bool new_main
Definition redundant_runtime.h:166
redundant_node< P, Storage >::pair_type carrier
Definition redundant_runtime.h:170
unsigned carrier_slot
Definition redundant_runtime.h:165
std::shared_ptr< redundant_object< P, Storage > const > output
Definition redundant_runtime.h:168
Definition redundant_runtime.h:173
std::array< redundant_slot< P, Storage >, 3 > slots
Definition redundant_runtime.h:174
std::optional< redundant_job_recipe< P, Storage > > job
Definition redundant_runtime.h:175
bool last_destination_visible
Definition redundant_runtime.h:177
std::uint64_t last_destination
Definition redundant_runtime.h:176
Definition redundant_runtime.h:49
built_type::view_type view() const
Definition redundant_runtime.h:85
catalog_bindings< pair_binding< typename Storage::mapped_pair_type > > bindings_
Definition redundant_runtime.h:113
bool canonical_mapped() const noexcept
Definition redundant_runtime.h:94
std::uint64_t virtual_size() const
Definition redundant_runtime.h:89
static pair_type from_built(built_type value)
Definition redundant_runtime.h:56
std::shared_ptr< typename Storage::mapped_pair_type const > mapped() const noexcept
Definition redundant_runtime.h:93
static pair_type from_mapped_parts(std::shared_ptr< typename Storage::mapped_pair_type const > value, native_pointer native, pair_type main={}, native_pointer secondary={})
Definition redundant_runtime.h:77
std::shared_ptr< typename Storage::mapped_pair_type const > mapped_
Definition redundant_runtime.h:118
std::shared_ptr< redundant_node const > pair_type
Definition redundant_runtime.h:54
std::uint64_t group_count() const
Definition redundant_runtime.h:90
Storage storage_type
Definition redundant_runtime.h:51
static pair_type from_mapped(std::shared_ptr< typename Storage::mapped_pair_type const > head)
Definition redundant_runtime.h:63
pair_type main_target() const noexcept
Definition redundant_runtime.h:88
std::shared_ptr< built_type const > built() const noexcept
Definition redundant_runtime.h:92
std::uint64_t depth() const noexcept
Definition redundant_runtime.h:91
redundant_node(std::shared_ptr< typename Storage::mapped_pair_type const > value, native_pointer native, pair_type main, native_pointer secondary)
Definition redundant_runtime.h:124
redundant_node(std::shared_ptr< built_type const > value)
Definition redundant_runtime.h:121
bool canonical_mapped_
Definition redundant_runtime.h:120
std::shared_ptr< built_type const > built_
Definition redundant_runtime.h:117
native_pointer secondary_target() const noexcept
Definition redundant_runtime.h:87
static pair_type from_sealed_parts(std::shared_ptr< pair_binding< typename Storage::mapped_pair_type > const > binding, std::filesystem::path const &root, native_pointer native, pair_type main, native_pointer secondary)
Definition redundant_runtime.h:102
std::uint64_t depth_
Definition redundant_runtime.h:119
native_pointer native_owner() const noexcept
Definition redundant_runtime.h:86
native_pointer native_
Definition redundant_runtime.h:115
native_pointer secondary_
Definition redundant_runtime.h:115
catalog_bindings< redundant_node > mapped_owners_
Definition redundant_runtime.h:114
pair_type main_
Definition redundant_runtime.h:116
std::shared_ptr< native_type const > native_pointer
Definition redundant_runtime.h:53
static pair_type from_built(std::shared_ptr< built_type const > value)
Definition redundant_runtime.h:59
typename Storage::native_type native_type
Definition redundant_runtime.h:52
redundant_node(std::shared_ptr< typename Storage::mapped_pair_type const > value, pair_type main)
Definition redundant_runtime.h:128
P policy_type
Definition redundant_runtime.h:50
Definition redundant_runtime.h:139
native_pointer native
Definition redundant_runtime.h:144
std::uint64_t last
Definition redundant_runtime.h:142
redundant_routes< P, Storage > next
Definition redundant_runtime.h:146
unsigned level
Definition redundant_runtime.h:143
typename redundant_node< P, Storage >::pair_type pair_type
Definition redundant_runtime.h:141
std::uint64_t first
Definition redundant_runtime.h:142
std::uint64_t identity
Definition redundant_runtime.h:142
bool secondary() const noexcept
Definition redundant_runtime.h:147
std::uint64_t mass() const noexcept
Definition redundant_runtime.h:148
pair_type pair
Definition redundant_runtime.h:145
std::uint64_t augmented() const
Definition redundant_runtime.h:149
typename redundant_node< P, Storage >::native_pointer native_pointer
Definition redundant_runtime.h:140
Definition redundant_runtime.h:136
std::shared_ptr< redundant_object< P, Storage > const > main
Definition redundant_runtime.h:137
std::shared_ptr< redundant_object< P, Storage > const > secondary
Definition redundant_runtime.h:137
Definition redundant_runtime.h:526
unsigned count
Definition redundant_runtime.h:526
std::array< unsigned, 2 > positions
Definition redundant_runtime.h:526
Definition redundant_runtime.h:481
std::uint64_t admissions
Definition redundant_runtime.h:489
void perform(unsigned i)
Definition redundant_runtime.h:827
static std::uint64_t root_price(std::uint64_t main, std::uint64_t secondary)
Definition redundant_runtime.h:570
active_slots active(unsigned i) const
Definition redundant_runtime.h:527
std::uint64_t checkpoint_price() const
Definition redundant_runtime.h:599
void direct(std::uint64_t amount, category kind)
Definition redundant_runtime.h:607
snapshot_type published
Definition redundant_runtime.h:492
unsigned vacant(unsigned i) const
Definition redundant_runtime.h:540
static std::uint64_t initialization_price(std::uint64_t count)
Definition redundant_runtime.h:582
static std::uint64_t index_price(std::uint64_t native, std::uint64_t main, std::uint64_t secondary)
Definition redundant_runtime.h:564
static snapshot_type initial(pair_type pair)
Definition redundant_runtime.h:501
native_pointer make_empty()
Definition redundant_runtime.h:499
std::uint64_t visibility_price() const
Definition redundant_runtime.h:600
bool recovery
Definition redundant_runtime.h:494
void refresh(unsigned i)
Definition redundant_runtime.h:558
std::uint64_t price() const
Definition redundant_runtime.h:757
std::array< level_type, maximum_levels > levels
Definition redundant_runtime.h:486
routes root
Definition redundant_runtime.h:490
std::uint64_t admission_price() const
Definition redundant_runtime.h:724
std::optional< unsigned > find(unsigned i, redundant_slot_state state) const
Definition redundant_runtime.h:536
native_pointer empty
Definition redundant_runtime.h:484
static std::uint64_t initial_native_price(std::uint64_t count)
Definition redundant_runtime.h:579
std::uint64_t credit
Definition redundant_runtime.h:489
execution(snapshot_type source, Storage context, Compose value)
Definition redundant_runtime.h:508
merge_compose merger()
Definition redundant_runtime.h:562
void grant(std::uint64_t amount)
Definition redundant_runtime.h:608
std::array< std::unique_ptr< worker >, maximum_levels > workers
Definition redundant_runtime.h:487
bool initializable() const noexcept
Definition redundant_runtime.h:548
redundant_work work
Definition redundant_runtime.h:493
pair_type build_index(native_pointer native, routes target)
Definition redundant_runtime.h:662
void checkpoint()
Definition redundant_runtime.h:705
query_type query
Definition redundant_runtime.h:491
static std::uint64_t augmented(object_pointer const &object)
Definition redundant_runtime.h:563
void begin(unsigned i)
Definition redundant_runtime.h:787
unsigned selected() const
Definition redundant_runtime.h:751
static pair_type make_empty_pair(native_pointer native)
Definition redundant_runtime.h:500
unsigned height
Definition redundant_runtime.h:488
object_pointer object(native_pointer native, pair_type pair, routes next, unsigned level, std::uint64_t first, std::uint64_t last)
Definition redundant_runtime.h:658
void poison() noexcept
Definition redundant_runtime.h:495
std::uint64_t next_identity
Definition redundant_runtime.h:489
std::uint64_t unsafe
Definition redundant_runtime.h:489
void visibility()
Definition redundant_runtime.h:684
void admit(profile_record const &record)
Definition redundant_runtime.h:733
void serve()
Definition redundant_runtime.h:896
static void visit(object_pointer const &value, F &fn)
Definition redundant_runtime.h:679
routes index_targets(unsigned i) const
Definition redundant_runtime.h:752
bool checkpoint_pending
Definition redundant_runtime.h:494
Storage storage
Definition redundant_runtime.h:482
bool ready() const noexcept
Definition redundant_runtime.h:541
std::uint64_t service_due
Definition redundant_runtime.h:489
pair_type empty_pair
Definition redundant_runtime.h:485
pair_type prepare_root(pair_type main, native_pointer secondary={})
Definition redundant_runtime.h:668
category charge_kind(unsigned i) const
Definition redundant_runtime.h:779
execution(Storage context, Compose value)
Definition redundant_runtime.h:506
void tally(std::uint64_t amount, category kind)
Definition redundant_runtime.h:601
bool changed
Definition redundant_runtime.h:494
void initialize_sorted(std::span< profile_record const > records, std::uint64_t allowance, std::uint64_t depth_limit)
Definition redundant_runtime.h:609
void complete_native(unsigned i, native_pointer native)
Definition redundant_runtime.h:814
Compose compose
Definition redundant_runtime.h:483
bool failed
Definition redundant_runtime.h:494
void require_ready() const
Definition redundant_runtime.h:547
Definition redundant_runtime.h:475
std::uint64_t charged
Definition redundant_runtime.h:479
std::unique_ptr< index_type > index
Definition redundant_runtime.h:478
action next
Definition redundant_runtime.h:476
std::unique_ptr< merge_type > merge
Definition redundant_runtime.h:477
Definition redundant_runtime.h:918
typename Storage::native_type native_type
Definition redundant_runtime.h:929
Storage storage_type
Definition redundant_runtime.h:920
P policy_type
Definition redundant_runtime.h:919
Definition redundant_runtime.h:362
bool try_initialize_sorted(std::span< profile_record const > records, std::uint64_t allowance, std::uint64_t depth_limit)
Definition redundant_runtime.h:419
bool admission_ready() const noexcept
Definition redundant_runtime.h:410
static redundant_runtime from_snapshot(snapshot_type source, Storage storage, Compose compose={})
Definition redundant_runtime.h:387
redundant_work work() const
Definition redundant_runtime.h:397
snapshot_type advance(std::uint64_t budget)
Definition redundant_runtime.h:437
bool pending() const noexcept
Definition redundant_runtime.h:407
Storage const & storage() const &
Definition redundant_runtime.h:390
typename Storage::template merge_type< merge_compose > merge_type
Definition redundant_runtime.h:471
redundant_runtime(std::unique_ptr< execution > value)
Definition redundant_runtime.h:912
static redundant_runtime from_snapshot(snapshot_type source, Compose compose={})
Definition redundant_runtime.h:384
category
Definition redundant_runtime.h:474
void poison() noexcept
Definition redundant_runtime.h:409
execution & writable()
Definition redundant_runtime.h:914
snapshot_type contribute(profile_record const &record)
Definition redundant_runtime.h:453
std::uint64_t service_due() const
Definition redundant_runtime.h:398
std::optional< snapshot_type > try_contribute(profile_record const &record, std::uint64_t budget=0)
Definition redundant_runtime.h:444
static std::uint64_t ceil(std::uint64_t n, std::uint64_t d)
Definition redundant_runtime.h:462
static void require(bool value, char const *message)
Definition redundant_runtime.h:463
typename node_type::native_type native_type
Definition redundant_runtime.h:366
std::uint64_t next_service_cost() const
Definition redundant_runtime.h:413
redundant_runtime(Storage storage, Compose compose={})
Definition redundant_runtime.h:383
Storage storage_type
Definition redundant_runtime.h:364
redundant_runtime(Compose compose={})
Definition redundant_runtime.h:382
redundant_snapshot< P, Storage > snapshot_type
Definition redundant_runtime.h:369
bool recovering() const noexcept
Definition redundant_runtime.h:411
bool failed() const noexcept
Definition redundant_runtime.h:408
static std::uint64_t service_budget(std::uint64_t admissions)
Definition redundant_runtime.h:378
Storage const & storage() const &&=delete
typename node_type::native_pointer native_pointer
Definition redundant_runtime.h:367
static constexpr unsigned maximum_levels
Definition redundant_runtime.h:375
snapshot_type snapshot() const
Definition redundant_runtime.h:396
std::shared_ptr< object_type const > object_pointer
Definition redundant_runtime.h:372
typename snapshot_type::query_type query_type
Definition redundant_runtime.h:370
execution const & active() const
Definition redundant_runtime.h:913
static std::uint64_t add(std::uint64_t a, std::uint64_t b)
Definition redundant_runtime.h:461
snapshot_type checkpoint()
Definition redundant_runtime.h:401
std::conditional_t< std::is_same_v< Compose, replace_native_value >, Compose, std::reference_wrapper< Compose > > merge_compose
Definition redundant_runtime.h:470
static void validate(profile_record const &record)
Definition redundant_runtime.h:464
std::uint64_t credit() const
Definition redundant_runtime.h:412
P policy_type
Definition redundant_runtime.h:363
std::uint64_t admission_cost() const
Definition redundant_runtime.h:414
typename node_type::pair_type pair_type
Definition redundant_runtime.h:368
action
Definition redundant_runtime.h:473
typename Storage::template index_type< node_type > index_type
Definition redundant_runtime.h:472
std::unique_ptr< execution > e_
Definition redundant_runtime.h:911
static constexpr std::uint64_t local_charge_bound
Definition redundant_runtime.h:377
Definition redundant_runtime.h:153
std::shared_ptr< redundant_object< P, Storage > const > object
Definition redundant_runtime.h:155
redundant_slot_state state
Definition redundant_runtime.h:154
bool ever_visible
Definition redundant_runtime.h:158
redundant_routes< P, Storage > route
Definition redundant_runtime.h:156
redundant_node< P, Storage >::pair_type carrier
Definition redundant_runtime.h:157
Definition redundant_runtime.h:347
redundant_frontier< P, Storage > frontier
Definition redundant_runtime.h:348
query_type query
Definition redundant_runtime.h:349
std::vector< object_pointer > runs
Definition redundant_runtime.h:350
Definition redundant_runtime.h:193
Storage storage_type
Definition redundant_runtime.h:195
std::span< object_pointer const > runs() const &noexcept
Definition redundant_runtime.h:201
query_type const & query_root() const &&=delete
std::shared_ptr< redundant_object< P, Storage > const > object_pointer
Definition redundant_runtime.h:197
redundant_snapshot(std::shared_ptr< state const > value)
Definition redundant_runtime.h:353
P policy_type
Definition redundant_runtime.h:194
query_type const & query_root() const &noexcept
Definition redundant_runtime.h:203
static redundant_snapshot restore(redundant_frontier< P, Storage > frontier, typename redundant_node< P, Storage >::pair_type head)
Definition redundant_runtime.h:211
std::span< object_pointer const > runs() const &&=delete
redundant_frontier< P, Storage > const & frontier() const &noexcept
Definition redundant_runtime.h:199
std::uint64_t admissions() const noexcept
Definition redundant_runtime.h:198
auto cursor(bit_view key) const
Definition redundant_runtime.h:205
std::shared_ptr< state const > state_
Definition redundant_runtime.h:352
bool same_layout(redundant_snapshot const &other) const noexcept
Definition redundant_runtime.h:207
cola_query_root< P, redundant_node< P, Storage > > query_type
Definition redundant_runtime.h:196
auto cursor_owned(bit_string key) const
Definition redundant_runtime.h:206
redundant_frontier< P, Storage > const & frontier() const &&=delete
Definition redundant_runtime.h:184
std::uint64_t charged
Definition redundant_runtime.h:185
std::uint64_t native_reuses
Definition redundant_runtime.h:188
std::uint64_t native_inputs
Definition redundant_runtime.h:188
std::uint64_t metadata_work
Definition redundant_runtime.h:187
std::uint64_t checkpoints
Definition redundant_runtime.h:189
std::uint64_t granted
Definition redundant_runtime.h:185
std::uint64_t native_outputs
Definition redundant_runtime.h:188
std::uint64_t merges
Definition redundant_runtime.h:189
std::uint64_t index_occurrences
Definition redundant_runtime.h:188
std::uint64_t carriers
Definition redundant_runtime.h:189
std::uint64_t root_work
Definition redundant_runtime.h:187
std::uint64_t carrier_work
Definition redundant_runtime.h:186
std::uint64_t native_work
Definition redundant_runtime.h:186
std::uint64_t max_job_charge_per_mass
Definition redundant_runtime.h:190
std::uint64_t admissions
Definition redundant_runtime.h:189
std::uint64_t indexes
Definition redundant_runtime.h:189
std::uint64_t index_work
Definition redundant_runtime.h:186
Definition runtime_graph_sealer.h:22
Definition runtime_store.h:58
Definition sort_runtime_context.h:33