22#include <unordered_map>
23#include <unordered_set>
39 using pair_type = std::shared_ptr<mapped_cola_blob const>;
48 error_detail::raise<std::invalid_argument>(
"invalid COLA mapped pair components");
49 if (
bool(index->main_id()) !=
bool(
main) || (
main && *index->main_id() !=
main->identity()))
50 error_detail::raise<std::invalid_argument>(
"COLA main target identity mismatch");
51 if (
bool(
secondary) !=
bool(secondary_id) || secondary_id != index->secondary_id())
52 error_detail::raise<std::invalid_argument>(
"COLA secondary target identity mismatch");
54 if (index->borrowed(0).size() != (
main ?
main->group_count() : 0) ||
55 index->
borrowed(1).size() != secondary_count / P::group_size + (secondary_count % P::group_size != 0))
56 error_detail::
raise<std::invalid_argument>(
"COLA mapped target sample count mismatch");
92 using P =
typename Blob::policy_type;
96 if (
failed_)
throw std::logic_error(
"failed COLA recovery context");
97 try {
scan(head); }
catch (...) {
failed_ =
true;
throw; }
103 std::set<std::weak_ptr<index_type const>, std::owner_less<>>
indexes_;
104 std::set<std::weak_ptr<native_type const>, std::owner_less<>>
natives_;
106 std::unordered_set<Blob const *> path;
107 for (
auto current = &head; current; current = current->main_target().get()) {
108 if (!path.insert(current).second)
throw std::invalid_argument(
"cyclic COLA recovery graph");
109 auto index = current->index_object();
110 if (!
indexes_.insert(index).second)
break;
111 auto native = current->native_object(),
secondary = current->secondary_target();
119 auto view = source.view();
120 auto native = view.native().cursor();
121 std::array
borrowed{view.borrowed(0).cursor(), view.borrowed(1).cursor()};
122 using native_cursor =
decltype(
native);
123 using borrowed_cursors =
decltype(
borrowed);
128 unsigned origin()
const {
130 if (!
native.done()) { result = 0; best =
native.peek().key.prefix; }
131 for (
unsigned i = 0; i != 2; ++i)
132 if (!
borrowed[i].done() && (result == 3 || compare_bits<typename P::architecture>(
borrowed[i].peek().key.prefix, best) < 0)) {
133 result = i + 1; best =
borrowed[i].peek().key.prefix;
135 if (result == 3)
throw std::out_of_range(
"COLA recovery cursor at end");
138 bit_view key(
unsigned origin)
const {
return origin ?
borrowed[origin - 1].peek().key.prefix :
native.peek().key.prefix; }
139 void advance(
unsigned origin) {
if (origin)
borrowed[origin - 1].advance();
else native.advance(); }
142 std::array<bit_string, 2> previous_borrowed;
143 std::array<std::uint64_t, 2> borrowed_count{}, population{};
144 bool had_native =
false;
145 std::uint64_t ordinal = 0;
146 while (!cursor.done()) {
147 auto origin = cursor.origin();
148 auto key = cursor.key(origin);
149 auto group = ordinal / P::group_size;
150 if (ordinal % P::group_size == 0) {
151 for (
unsigned route = 0; route != 2; ++route) {
152 auto lcp = borrowed_count[route] ? compare_common_bits<typename P::architecture>(previous_borrowed[route].view(), key).common_bits : 0;
153 if (view.cut_lcps(route)[group] != lcp || view.interleave(route).template rank<typename P::architecture>(group) != borrowed_count[route])
154 error_detail::raise<std::invalid_argument>(
"COLA cut or rank disagrees with keys");
159 auto route = origin - 1;
160 bool expected = had_native && compare_bits<typename P::architecture>(previous_native.
view(), key) == 0;
161 if (view.false_borrow(route, borrowed_count[route]) != expected)
162 error_detail::raise<std::invalid_argument>(
"COLA false-borrow flag disagrees with keys");
164 ++borrowed_count[route]; ++population[route];
166 cursor.advance(origin);
168 if (ordinal % P::group_size == 0 || cursor.done())
169 for (
unsigned route = 0; route != 2; ++route)
170 if (view.interleave(route).class_at(group) != population[route])
171 error_detail::raise<std::invalid_argument>(
"COLA population disagrees with keys");
173 if (ordinal != source.virtual_size() || borrowed_count[0] != view.borrowed(0).size() ||
174 borrowed_count[1] != view.borrowed(1).size())
175 error_detail::raise<std::invalid_argument>(
"COLA merged stream count mismatch");
176 auto samples = view.borrowed(0).cursor();
177 if (
auto main = source.main_target()) {
179 while (!target.
done()) {
180 if (samples.done() || compare_bits<typename P::architecture>(samples.peek().key.prefix, target.
peek().key) != 0)
181 error_detail::raise<std::invalid_argument>(
"COLA main sample differs from target");
182 samples.advance(); target.
advance();
185 if (!samples.done()) error_detail::raise<std::invalid_argument>(
"COLA trailing main samples");
186 auto side_samples = view.borrowed(1).cursor();
187 if (
auto secondary = source.secondary_target()) {
188 auto target =
secondary->view().cursor();
189 std::uint64_t ordinal = 0;
190 while (!target.done()) {
191 if (ordinal % P::group_size == 0) {
192 if (side_samples.done() || compare_bits<typename P::architecture>(side_samples.peek().key.prefix, target.peek().key.prefix) != 0)
193 error_detail::raise<std::invalid_argument>(
"COLA secondary sample differs from target");
194 side_samples.advance();
196 target.advance(); ++ordinal;
199 if (!side_samples.done()) error_detail::raise<std::invalid_argument>(
"COLA trailing secondary samples");
222 auto found =
natives_.find(
id.hex());
223 if (found ==
natives_.end()) found =
natives_.emplace(
id.hex(), std::make_shared<native_type const>(
225 return found->second;
229 std::vector<pending> chain;
230 std::unordered_set<std::string> seen;
231 std::optional<blob_identity> current = head;
234 if (
auto known =
pairs_.find(current->index.hex()); known !=
pairs_.end()) {
235 if (known->second->identity() != *current)
236 error_detail::raise<std::invalid_argument>(
"COLA reused index has another native identity");
237 target = known->second;
break;
239 if (!seen.insert(current->index.hex()).second)
240 error_detail::raise<std::invalid_argument>(
"cyclic COLA object identities");
241 auto index = std::make_shared<index_type const>(
243 if (index->native_id() != current->native)
244 error_detail::raise<std::invalid_argument>(
"COLA chain native identity mismatch");
245 chain.push_back({*current,
native(current->native), index->secondary_id() ?
native(*index->secondary_id()) :
native_pointer{}, index});
246 current = index->main_id();
248 for (
auto i = chain.rbegin(); i != chain.rend(); ++i) {
249 target = blob::bind(i->identity, std::move(i->native), i->index,
250 std::move(target), std::move(i->secondary), i->index->secondary_id());
251 pairs_.emplace(i->identity.index.hex(), target);
257 std::unordered_map<std::string, native_pointer>
natives_;
258 std::unordered_map<std::string, pair_type>
pairs_;
262 std::filesystem::path
const & root,
blob_identity const & head) {
Enumerates native matches along a COLA main chain and its terminal secondaries.
Encodes two-target COLA routing in portable IX03 sections.
void raise(char const *message)
Definition error_detail.h:22
Definition active_engine.h:18
void scan_mapped_cola(Blob const &source)
Definition mapped_cola.h:202
mapped_cola_query_root< P > open_mapped_cola_query(std::filesystem::path const &root, blob_identity const &head)
Definition mapped_cola.h:261
std::filesystem::path object_path(object_id const &id, file_kind kind)
Definition object_path.h:52
bit_view view() const &
Definition profile.h:178
static bit_string copy(bit_view source)
Definition profile.h:181
object_id native
Definition sections.h:35
Definition cola_index.h:496
Definition cola_index.h:114
Definition cola_index.h:315
Definition cola_query.h:40
static cola_query_root adopt_prepared(pair_type source)
Definition cola_query.h:47
Definition cola_index.h:420
void advance()
Definition cola_index.h:433
bool done() const noexcept
Definition cola_index.h:423
cola_sample_view< P > peek() const &
Definition cola_index.h:425
Definition mapped_cola.h:33
cola_index_view< P > view_
Definition mapped_cola.h:81
void scan() const
Definition mapped_cola.h:74
cola_index_view< P > view() const &&=delete
blob_identity const & identity() const &&=delete
native_pointer native_object() const noexcept
Definition mapped_cola.h:63
std::shared_ptr< index_type const > index_pointer
Definition mapped_cola.h:38
mapped_cola_blob & operator=(mapped_cola_blob &&)=delete
blob_identity const & identity() const &noexcept
Definition mapped_cola.h:61
static pair_type bind(blob_identity identity, native_pointer native, index_pointer index, pair_type main={}, native_pointer secondary={}, std::optional< object_id > secondary_id={})
Definition mapped_cola.h:45
native_pointer secondary_target() const noexcept
Definition mapped_cola.h:66
blob_identity identity_
Definition mapped_cola.h:76
std::shared_ptr< mapped_cola_blob const > pair_type
Definition mapped_cola.h:39
mapped_cola_blob & operator=(mapped_cola_blob const &)=delete
pair_type main_target() const noexcept
Definition mapped_cola.h:65
index_pointer index_
Definition mapped_cola.h:78
std::shared_ptr< native_type const > native_pointer
Definition mapped_cola.h:36
mapped_cola_blob(mapped_cola_blob const &)=delete
P policy_type
Definition mapped_cola.h:34
index_pointer index_object() const noexcept
Definition mapped_cola.h:64
native_pointer native_
Definition mapped_cola.h:77
std::uint64_t virtual_size() const noexcept
Definition mapped_cola.h:69
pair_type main_
Definition mapped_cola.h:79
mapped_cola_blob(blob_identity identity, native_pointer native, index_pointer index, pair_type main, native_pointer secondary, cola_index_view< P > view)
Definition mapped_cola.h:82
mapped_cola_blob(mapped_cola_blob &&)=delete
native_pointer secondary_
Definition mapped_cola.h:80
std::uint64_t group_count() const noexcept
Definition mapped_cola.h:70
cola_index_view< P > view() const &
Definition mapped_cola.h:67
Definition cola_sections.h:266
Definition mapped_cola.h:214
std::unordered_map< std::string, pair_type > pairs_
Definition mapped_cola.h:258
typename blob::index_type index_type
Definition mapped_cola.h:217
std::unordered_map< std::string, native_pointer > natives_
Definition mapped_cola.h:257
typename blob::native_pointer native_pointer
Definition mapped_cola.h:218
typename blob::native_type native_type
Definition mapped_cola.h:216
native_pointer native(object_id const &id)
Definition mapped_cola.h:221
mapped_cola_resolver(std::filesystem::path root)
Definition mapped_cola.h:220
typename blob::pair_type pair_type
Definition mapped_cola.h:219
std::filesystem::path root_
Definition mapped_cola.h:256
pair_type pair(blob_identity const &head)
Definition mapped_cola.h:227
Blob blob
Definition mapped_cola.h:215
Definition mapped_cola.h:91
void operator()(Blob const &head)
Definition mapped_cola.h:95
static void scan_routes(Blob const &source)
Definition mapped_cola.h:118
typename Blob::index_type index_type
Definition mapped_cola.h:94
typename Blob::native_type native_type
Definition mapped_cola.h:93
void scan(Blob const &head)
Definition mapped_cola.h:105
std::set< std::weak_ptr< index_type const >, std::owner_less<> > indexes_
Definition mapped_cola.h:103
typename Blob::policy_type P
Definition mapped_cola.h:92
bool failed_
Definition mapped_cola.h:100
std::set< std::weak_ptr< native_type const >, std::owner_less<> > natives_
Definition mapped_cola.h:104
Definition sections.h:442
Definition object_path.h:38