29inline std::uint64_t
ld64(
const Byte* p)
noexcept {
30 std::uint64_t
value = 0;
31 for (
int i = 7; i >= 0; --i)
value = (
value << 8) | p[i];
35 for (
int i = 0; i < 8; ++i) p[i] = static_cast<Byte>((
value >> (8 * i)) & 0xFF);
37inline std::uint32_t
ld32(
const Byte* p)
noexcept {
38 return static_cast<std::uint32_t
>(p[0]) | (
static_cast<std::uint32_t
>(p[1]) << 8)
39 | (
static_cast<std::uint32_t
>(p[2]) << 16) | (
static_cast<std::uint32_t
>(p[3]) << 24);
42 for (
int i = 0; i < 4; ++i) p[i] = static_cast<Byte>((
value >> (8 * i)) & 0xFF);
46 std::uint64_t
value = 14695981039346656037ull;
48 for (std::size_t i = 0; i < length; ++i) {
50 value *= 1099511628211ull;
53 void le64(std::uint64_t v)
noexcept {
60constexpr std::uint64_t
kMagic = 0x3142535243534650ull;
71constexpr std::size_t
kCell = 64;
74constexpr std::uint64_t
kLive = 1;
80constexpr std::uint64_t
kNoSlot = UINT64_MAX;
87 std::uint64_t
seq = 0;
133 : core_(core), loc_(loc), len_(len) {}
134 std::uint64_t
size() const noexcept
override {
return len_; }
136 if (offset > len_ || destination.size > len_ - offset
137 || (destination.size != 0 && destination.data ==
nullptr))
139 return core_->blob_read(loc_, offset, destination.size,
reinterpret_cast<Byte*
>(destination.data), pos_);
154 && (c.page_size & (c.page_size - 1)) == 0 && c.journal_slots >= 1 && c.index_slots >= 1
155 && c.order.id != 0 && c.order.compare !=
nullptr && c.page_size == b->page_size();
157 static std::size_t
round_up(std::size_t n, std::size_t a)
noexcept {
return (n + a - 1) / a * a; }
160 while (n < slots * 2) n <<= 1;
168 total += (c.page_count +
kWorkPages) * c.page_size;
190 Byte* base =
reinterpret_cast<Byte*
>(
this);
192 slot_ =
reinterpret_cast<Slot*
>(base + off);
194 bucket_ =
reinterpret_cast<std::int32_t*
>(base + off);
213 if (b->page_count() != 0)
open_status_ = Status::programming_error;
229 if (status != Status::io_error)
return;
230 backing_io_failed_ =
true;
256 return status == Status::not_found ? Status::corrupt : status;
262 std::size_t
bucket_of(std::uint64_t
id)
const noexcept {
263 return static_cast<std::size_t
>(((
id + 1) * 0x9E3779B97F4A7C15ull) >> 40) & (
nbuckets_ - 1);
265 std::int32_t
find(std::uint64_t
id)
noexcept {
268 if (
slot_[s].valid &&
slot_[s].
id ==
id)
return s;
277 *link =
slot_[s].next;
280 link = &
slot_[*link].next;
285 slot_[s].next = *head;
291 std::int32_t best = -1;
292 for (std::size_t i = 0; i <
slots_; ++i) {
293 const std::int32_t s =
static_cast<std::int32_t
>(i);
294 if (!
slot_[s].valid) {
298 if (best < 0 ||
slot_[s].tick <
slot_[best].tick) best = s;
300 if (
slot_[best].valid) {
301 if (
slot_[best].dirty) {
303 if (st != Status::ok)
return st;
304 slot_[best].dirty =
false;
307 slot_[best].valid =
false;
312 Status fetch(std::uint64_t
id,
bool load, std::int32_t& out)
noexcept {
313 std::int32_t s =
find(
id);
320 if (st != Status::ok)
return st;
322 slot_[s].valid =
false;
323 slot_[s].dirty =
false;
328 slot_[s].valid =
true;
335 for (std::size_t i = 0; i <
slots_; ++i) {
336 const std::int32_t s =
static_cast<std::int32_t
>(i);
337 if (!
slot_[s].valid || !
slot_[s].dirty)
continue;
339 if (st != Status::ok)
return st;
340 slot_[s].dirty =
false;
345 for (std::size_t i = 0; i <
slots_; ++i) {
346 slot_[i].valid =
false;
347 slot_[i].dirty =
false;
353 Status rd(std::uint64_t
id, std::size_t off, std::size_t len,
Byte* destination)
noexcept {
356 if (st != Status::ok)
return st;
357 std::memcpy(destination,
page_at(s) + off, len);
365 if (!
active_)
return Status::programming_error;
366 if (
id >=
hw0_)
return Status::ok;
369 if (st != Status::ok)
return st;
376 if (
cur_.pool_head != 0) {
377 image =
cur_.pool_head;
387 if (st != Status::ok)
return st;
391 st =
fetch(
id,
true, s);
392 if (st != Status::ok)
return st;
394 slot_[s].dirty =
true;
399 if (st != Status::ok)
return st;
401 st =
fetch(
id,
true, s);
402 if (st != Status::ok)
return st;
404 slot_[s].dirty =
true;
410 return wr(
id, off, 8, raw);
415 return wr(
id, off, 4, raw);
422 if (st != Status::ok)
return st;
424 st =
fetch(
id,
false, s);
425 if (st != Status::ok)
return st;
427 slot_[s].dirty =
true;
434 if (
cur_.free_head != 0) {
437 const Status st =
rd(
id, 16, 8, raw);
438 if (st != Status::ok)
return st;
447 if (st != Status::ok)
return st;
449 if (st != Status::ok)
return st;
456 std::uint64_t
cell_page(std::uint64_t cell)
const noexcept {
return cell >> 16; }
457 std::size_t
cell_off(std::uint64_t cell)
const noexcept {
458 return kHeader +
static_cast<std::size_t
>(cell & 0xFFFF) *
kCell;
461 if (
cur_.cell_free != 0) {
462 cell =
cur_.cell_free;
465 if (st != Status::ok)
return st;
470 std::uint64_t page = 0;
472 if (st != Status::ok)
return st;
476 if (st != Status::ok)
return st;
477 cur_.cell_bump = page;
480 cell = (
cur_.cell_bump << 16) |
cur_.cell_next;
486 std::size_t length)
noexcept {
495 if (length == 0)
return Status::ok;
498 std::uint64_t cell = 0;
500 if (st != Status::ok)
return st;
502 std::uint64_t done = 0;
505 std::uint64_t
next = 0;
506 if (done + n < length) {
508 if (st != Status::ok)
return st;
513 if (st != Status::ok)
return st;
515 if (st != Status::ok)
return st;
517 if (done == length)
break;
522 std::uint64_t page = 0;
524 if (st != Status::ok)
return st;
525 loc = (page << 1) | 1;
526 std::uint64_t done = 0;
529 std::uint64_t
next = 0;
530 if (done + n < length) {
532 if (st != Status::ok)
return st;
538 if (st != Status::ok)
return st;
540 if (st != Status::ok)
return st;
542 if (done == length)
break;
550 if (length == 0)
return Status::ok;
551 if (loc == 0)
return Status::corrupt;
552 const bool paged = (loc & 1) != 0;
554 const std::uint64_t want = offset / span;
555 if (pos.elem == 0 || pos.index > want) {
560 while (pos.index < want) {
562 if (st != Status::ok)
return st;
563 pos.elem =
ld64(raw);
565 if (pos.elem == 0)
return Status::corrupt;
567 std::size_t inner =
static_cast<std::size_t
>(offset % span);
569 const std::size_t n = length < span - inner ? length : span - inner;
570 const Status st = paged ?
rd(pos.elem, 24 + inner, n, destination)
572 if (st != Status::ok)
return st;
577 const Status hop = paged ?
rd(pos.elem, 16, 8, raw)
579 if (hop != Status::ok)
return hop;
580 pos.elem =
ld64(raw);
582 if (pos.elem == 0)
return Status::corrupt;
589 if (loc == 0)
return Status::ok;
591 if ((loc & 1) != 0) {
592 std::uint64_t page = loc >> 1;
595 if (st != Status::ok)
return st;
596 const std::uint64_t
next =
ld64(raw);
598 if (st != Status::ok)
return st;
603 std::uint64_t cell = loc >> 1;
606 if (st != Status::ok)
return st;
607 const std::uint64_t
next =
ld64(raw);
609 if (st != Status::ok)
return st;
610 cur_.cell_free = cell;
618 static std::uint64_t
mul_sat(std::uint64_t a, std::uint64_t b)
noexcept {
619 if (a != 0 && b > UINT64_MAX / a)
return UINT64_MAX;
623 std::uint64_t
span_of(std::uint64_t level)
const noexcept {
624 std::uint64_t span = 1;
642 if (
cur_.hroot == 0) {
643 if (!create)
return Status::ok;
644 std::uint64_t page = 0;
646 if (st != Status::ok)
return st;
650 if (st != Status::ok)
return st;
655 if (!create)
return Status::ok;
656 std::uint64_t page = 0;
658 if (st != Status::ok)
return st;
664 if (st != Status::ok)
return st;
668 std::uint64_t node =
cur_.hroot;
669 std::uint64_t rest = leaf_no;
670 for (std::uint64_t level =
cur_.hheight; level > 1; --level) {
671 if (path.depth >=
kMaxHeight)
return Status::corrupt;
672 const std::uint64_t span =
span_of(level - 1);
673 const std::size_t ci =
static_cast<std::size_t
>(rest / span);
674 rest -=
static_cast<std::uint64_t
>(ci) * span;
676 st =
rd(node, 16 + 8 * ci, 8, raw);
677 if (st != Status::ok)
return st;
678 std::uint64_t child =
ld64(raw);
680 if (!create)
return Status::ok;
682 if (st != Status::ok)
return st;
686 if (st != Status::ok)
return st;
687 st =
wr64(node, 16 + 8 * ci, child);
688 if (st != Status::ok)
return st;
690 st =
rd(node, 4, 4, count_raw);
691 if (st != Status::ok)
return st;
692 st =
wr32(node, 4,
ld32(count_raw) + 1);
693 if (st != Status::ok)
return st;
695 path.node[path.depth] = node;
696 path.slot[path.depth] = ci;
706 if (handle == 0 || handle >=
cur_.next_handle)
return Status::ok;
707 const std::uint64_t index = handle - 1;
708 std::uint64_t leaf = 0;
711 if (st != Status::ok || leaf == 0)
return st;
714 if (rs != Status::ok)
return rs;
715 entry.key_loc =
ld64(raw);
716 entry.val_loc =
ld64(raw + 8);
717 entry.key_len =
ld64(raw + 16);
718 entry.val_word =
ld64(raw + 24);
719 present = (entry.val_word & 3) != 0;
724 const std::uint64_t index = handle - 1;
725 std::uint64_t leaf = 0;
728 if (st != Status::ok)
return st;
729 const std::size_t off =
kHeader +
static_cast<std::size_t
>(index %
hleaf_cap_) * 32;
731 st =
rd(leaf, off, 32, raw);
732 if (st != Status::ok)
return st;
733 const bool was = (
ld64(raw + 24) & 3) != 0;
734 const bool now = (entry.val_word & 3) != 0;
735 st64(raw, entry.key_loc);
736 st64(raw + 8, entry.val_loc);
737 st64(raw + 16, entry.key_len);
738 st64(raw + 24, entry.val_word);
739 st =
wr(leaf, off, 32, raw);
740 if (st != Status::ok)
return st;
741 if (was == now)
return Status::ok;
743 st =
rd(leaf, 4, 4, count_raw);
744 if (st != Status::ok)
return st;
745 std::uint32_t count =
ld32(count_raw);
748 st =
wr32(leaf, 4, count);
749 if (st != Status::ok)
return st;
750 if (count != 0 || path.
depth == 0)
return Status::ok;
755 if (st != Status::ok)
return st;
756 for (std::size_t k = path.
depth; k-- > 0;) {
758 if (st != Status::ok)
return st;
759 st =
rd(path.
node[k], 4, 4, count_raw);
760 if (st != Status::ok)
return st;
761 const std::uint32_t children =
ld32(count_raw) - 1;
762 st =
wr32(path.
node[k], 4, children);
763 if (st != Status::ok)
return st;
764 if (children != 0 || k == 0)
break;
766 if (st != Status::ok)
return st;
775 bool present =
false;
777 if (st != Status::ok)
return st;
778 if (!present)
return Status::corrupt;
781 st =
order_.compare(
order_.context, probe, stored, order);
790 const Status st =
rd(page, 4, 4, raw);
791 if (st != Status::ok)
return st;
799 std::uint64_t& leaf)
noexcept {
804 if (
cur_.iroot == 0)
return Status::ok;
805 std::uint64_t page =
cur_.iroot;
806 for (std::uint64_t level =
cur_.iheight; level > 1; --level) {
807 if (path.depth >=
kMaxDepth)
return Status::corrupt;
808 std::uint32_t count = 0;
810 if (st != Status::ok)
return st;
811 std::uint32_t lo = 0, hi = count;
813 const std::uint32_t mid = lo + (hi - lo) / 2;
815 st =
rd(page, 24 + 16 *
static_cast<std::size_t
>(mid), 8, raw);
816 if (st != Status::ok)
return st;
819 if (st != Status::ok)
return st;
820 if (order >= 0) lo = mid + 1;
824 st =
rd(page, 16 + 16 *
static_cast<std::size_t
>(lo), 8, child_raw);
825 if (st != Status::ok)
return st;
826 path.page[path.depth] = page;
827 path.slot[path.depth] = lo;
829 page =
ld64(child_raw);
830 if (page == 0)
return Status::corrupt;
832 std::uint32_t count = 0;
834 if (st != Status::ok)
return st;
835 std::uint32_t lo = 0, hi = count;
837 const std::uint32_t mid = lo + (hi - lo) / 2;
839 st =
rd(page, 32 + 8 *
static_cast<std::size_t
>(mid), 8, raw);
840 if (st != Status::ok)
return st;
843 if (st != Status::ok)
return st;
844 if (order > 0) lo = mid + 1;
851 st =
rd(page, 32 + 8 *
static_cast<std::size_t
>(lo), 8, raw);
852 if (st != Status::ok)
return st;
855 if (st != Status::ok)
return st;
863 const Status st =
rd(leaf, 32 + 8 *
static_cast<std::size_t
>(pos), 8, raw);
864 if (st != Status::ok)
return st;
871 if (
cur_.iroot == 0)
return Status::ok;
872 std::uint64_t page =
cur_.iroot;
873 for (std::uint64_t level =
cur_.iheight; level > 1; --level) {
875 const Status st =
rd(page, 16, 8, raw);
876 if (st != Status::ok)
return st;
878 if (page == 0)
return Status::corrupt;
885 std::uint64_t page = 0;
887 if (st != Status::ok)
return st;
895 if (st != Status::ok)
return st;
903 for (
int level =
static_cast<int>(path.depth) - 1;; --level) {
904 if (level < 0)
return new_root(separator, right);
905 const std::uint64_t parent = path.page[level];
906 const std::uint32_t c = path.slot[level];
908 if (st != Status::ok)
return st;
909 const std::uint32_t count =
ld32(
w0_ + 4);
912 std::memmove(pairs + 16 *
static_cast<std::size_t
>(c + 1), pairs + 16 *
static_cast<std::size_t
>(c),
913 16 *
static_cast<std::size_t
>(count - c));
914 st64(pairs + 16 *
static_cast<std::size_t
>(c), separator);
915 st64(pairs + 16 *
static_cast<std::size_t
>(c) + 8, right);
919 const std::uint32_t total = count + 1;
920 const std::uint32_t mid = total / 2;
922 auto pair_sep = [&](std::uint32_t i) -> std::uint64_t {
923 return i < c ? ld64(w0_ + 24 + 16 * static_cast<std::size_t>(i))
924 : (i == c ? separator :
ld64(
w0_ + 24 + 16 *
static_cast<std::size_t
>(i - 1)));
926 auto pair_child = [&](std::uint32_t i) -> std::uint64_t {
927 return i < c ? ld64(w0_ + 32 + 16 * static_cast<std::size_t>(i))
928 : (i == c ? right :
ld64(
w0_ + 32 + 16 *
static_cast<std::size_t
>(i - 1)));
932 st32(
w1_ + 4, total - mid - 1);
933 st64(
w1_ + 16, pair_child(mid));
934 for (std::uint32_t j = 0; j + mid + 1 < total; ++j) {
935 st64(
w1_ + 24 + 16 *
static_cast<std::size_t
>(j), pair_sep(mid + 1 + j));
936 st64(
w1_ + 32 + 16 *
static_cast<std::size_t
>(j), pair_child(mid + 1 + j));
942 for (std::uint32_t j = 0; j < mid; ++j) {
943 st64(
w2_ + 24 + 16 *
static_cast<std::size_t
>(j), pair_sep(j));
944 st64(
w2_ + 32 + 16 *
static_cast<std::size_t
>(j), pair_child(j));
946 const std::uint64_t promoted = pair_sep(mid);
947 std::uint64_t new_page = 0;
949 if (st != Status::ok)
return st;
951 if (st != Status::ok)
return st;
953 if (st != Status::ok)
return st;
954 separator = promoted;
964 std::uint64_t page = 0;
966 if (st != Status::ok)
return st;
972 if (st != Status::ok)
return st;
978 if (st != Status::ok)
return st;
979 const std::uint32_t count =
ld32(
w0_ + 4);
982 std::memmove(entries + 8 *
static_cast<std::size_t
>(pos + 1), entries + 8 *
static_cast<std::size_t
>(pos),
983 8 *
static_cast<std::size_t
>(count - pos));
984 st64(entries + 8 *
static_cast<std::size_t
>(pos), handle);
988 const std::uint32_t total = count + 1;
989 const std::uint32_t mid = (total + 1) / 2;
990 auto at = [&](std::uint32_t i) -> std::uint64_t {
991 return i < pos ? ld64(w0_ + 32 + 8 * static_cast<std::size_t>(i))
992 : (i == pos ? handle :
ld64(
w0_ + 32 + 8 *
static_cast<std::size_t
>(i - 1)));
994 std::uint64_t right_page = 0;
996 if (st != Status::ok)
return st;
997 const std::uint64_t old_next =
ld64(
w0_ + 24);
998 const std::uint64_t old_prev =
ld64(
w0_ + 16);
1004 for (std::uint32_t i = mid; i < total; ++i) st64(w1_ + 32 + 8 * static_cast<std::size_t>(i - mid), at(i));
1010 for (std::uint32_t i = 0; i < mid; ++i) st64(w2_ + 32 + 8 * static_cast<std::size_t>(i), at(i));
1011 const std::uint64_t separator = at(mid);
1013 if (st != Status::ok)
return st;
1015 if (st != Status::ok)
return st;
1016 if (old_next != 0) {
1017 st =
wr64(old_next, 16, right_page);
1018 if (st != Status::ok)
return st;
1020 return insert_up(path, separator, right_page);
1027 bool present =
false;
1029 if (st != Status::ok)
return st;
1030 if (!present || (entry.
val_word & 3) !=
kGhost)
return Status::ok;
1032 if (st != Status::ok)
return st;
1037 int level =
static_cast<int>(path.depth) - 1;
1045 const std::uint64_t parent = path.page[level];
1046 const std::uint32_t c = path.slot[level];
1048 if (st != Status::ok)
return st;
1049 const std::uint32_t count =
ld32(
w0_ + 4);
1052 if (st != Status::ok)
return st;
1056 std::uint64_t separator;
1058 separator =
ld64(pairs + 16 *
static_cast<std::size_t
>(c - 1));
1059 std::memmove(pairs + 16 *
static_cast<std::size_t
>(c - 1), pairs + 16 *
static_cast<std::size_t
>(c),
1060 16 *
static_cast<std::size_t
>(count - c));
1062 separator =
ld64(pairs);
1064 std::memmove(pairs, pairs + 16, 16 *
static_cast<std::size_t
>(count - 1));
1068 if (st != Status::ok)
return st;
1070 if (st != Status::ok)
return st;
1073 while (
cur_.iheight > 1) {
1074 std::uint32_t count = 0;
1076 if (st != Status::ok)
return st;
1077 if (count != 0)
break;
1079 st =
rd(
cur_.iroot, 16, 8, raw);
1080 if (st != Status::ok)
return st;
1081 const std::uint64_t old_root =
cur_.iroot;
1085 if (st != Status::ok)
return st;
1092 if (st != Status::ok)
return st;
1093 const std::uint32_t count =
ld32(
w0_ + 4);
1094 if (pos >= count ||
ld64(
w0_ + 32 + 8 *
static_cast<std::size_t
>(pos)) != handle)
return Status::corrupt;
1096 std::memmove(entries + 8 *
static_cast<std::size_t
>(pos), entries + 8 *
static_cast<std::size_t
>(pos + 1),
1097 8 *
static_cast<std::size_t
>(count - pos - 1));
1100 const std::uint64_t prev =
ld64(
w0_ + 16);
1104 if (st != Status::ok)
return st;
1108 if (st != Status::ok)
return st;
1111 if (st != Status::ok)
return st;
1118 std::memset(buffer, 0,
page_);
1120 s.record_count, s.hw, s.free_head, s.hroot, s.hheight, s.iroot,
1121 s.iheight, s.cell_free, s.cell_bump, s.cell_next, s.pool_head, 0};
1124 st64(buffer + 8 * i, fields[i]);
1125 fold.
le64(fields[i]);
1133 fields[i] =
ld64(buffer + 8 * i);
1134 fold.
le64(fields[i]);
1138 order_id = fields[3];
1140 s.next_handle = fields[5];
1141 s.record_count = fields[6];
1143 s.free_head = fields[8];
1144 s.hroot = fields[9];
1145 s.hheight = fields[10];
1146 s.iroot = fields[11];
1147 s.iheight = fields[12];
1148 s.cell_free = fields[13];
1149 s.cell_bump = fields[14];
1150 s.cell_next = fields[15];
1151 s.pool_head = fields[16];
1156 if (
backing_->page_count() == 0)
return Status::not_found;
1158 std::uint64_t best_order = 0;
1160 for (std::uint64_t slot = 0; slot < 2; ++slot) {
1162 if (st == Status::not_found)
continue;
1163 if (st != Status::ok)
return st;
1165 std::uint64_t order_id = 0;
1167 if (!have || candidate.
seq > best.
seq) {
1169 best_order = order_id;
1173 if (!have)
return Status::corrupt;
1174 if (best_order !=
order_.id)
return Status::programming_error;
1175 if (best.
hw < 2)
return Status::corrupt;
1197 std::uint64_t new_pool =
cur_.pool_head;
1204 if (st != Status::ok)
return st;
1208 if (st != Status::ok)
return st;
1210 st =
bsync(durability);
1211 if (st != Status::ok)
return st;
1215 next.pool_head = new_pool;
1222 if (st != Status::ok)
return st;
1224 st =
bsync(durability);
1225 if (st != Status::ok)
return st;
1240 return Status::programming_error;
1258 if (target < 2 || target >=
hw0_)
return Status::corrupt;
1262 if (st != Status::ok)
return st;
1269 if (st != Status::ok)
return st;
1270 cur_.pool_head = image;
1276 if (st != Status::ok)
return st;
1279 const std::uint64_t pool =
cur_.pool_head;
1281 cur_.pool_head = pool;
1300 const std::uint64_t key_len =
key.size();
1301 const std::uint64_t val_len =
value.size();
1302 if (val_len >= (std::uint64_t{1} << 61) || key_len >= (std::uint64_t{1} << 61))
return Status::programming_error;
1305 std::uint32_t pos = 0;
1306 std::uint64_t leaf = 0;
1308 if (st != Status::ok)
return st;
1313 std::uint64_t handle = 0;
1315 if (st != Status::ok)
return st;
1317 bool present =
false;
1318 st =
hget(handle, old, present);
1319 if (st != Status::ok)
return st;
1320 if (!present)
return Status::corrupt;
1322 if (st != Status::ok)
return st;
1324 if (st != Status::ok)
return st;
1325 st =
hset(handle, entry);
1326 if (st != Status::ok)
return st;
1328 if (st != Status::ok)
return st;
1330 if (st != Status::ok)
return st;
1334 if (
cur_.next_handle >= (std::uint64_t{1} << 62))
return Status::programming_error;
1336 if (st != Status::ok)
return st;
1338 if (st != Status::ok)
return st;
1339 const std::uint64_t handle =
cur_.next_handle++;
1340 st =
hset(handle, entry);
1341 if (st != Status::ok)
return st;
1343 if (st != Status::ok)
return st;
1344 ++
cur_.record_count;
1351 backing_io_failed_ =
false;
1352 std::uint64_t handle = 0;
1354 if (st != Status::ok) {
1356 return backing_io_failed_ ? Status::io_error : Status::programming_error;
1366 std::uint32_t pos = 0;
1367 std::uint64_t leaf = 0;
1369 if (st != Status::ok)
return st;
1370 if (!equal || leaf == 0)
return Status::corrupt;
1371 std::uint64_t found = 0;
1373 if (st != Status::ok)
return st;
1374 if (found != handle)
return Status::corrupt;
1376 for (
unsigned level = 0; level < path.
depth; ++level) {
1377 const std::uint32_t c = path.
slot[level];
1378 if (c == 0)
continue;
1380 st =
rd(path.
page[level], 24 + 16 *
static_cast<std::size_t
>(c - 1), 8, raw);
1381 if (st != Status::ok)
return st;
1382 if (
ld64(raw) == handle) named =
true;
1386 if (st != Status::ok)
return st;
1388 ghost.
key_loc = entry.key_loc;
1389 ghost.
key_len = entry.key_len;
1391 st =
hset(handle, ghost);
1394 if (st != Status::ok)
return st;
1396 if (st != Status::ok)
return st;
1399 if (st != Status::ok)
return st;
1401 if (st != Status::ok)
return st;
1402 --
cur_.record_count;
1408 backing_io_failed_ =
false;
1410 bool present =
false;
1412 if (st != Status::ok) {
1414 return backing_io_failed_ ? Status::io_error : Status::programming_error;
1416 if (!present || (entry.
val_word & 3) !=
kLive)
return Status::not_found;
1418 if (st != Status::ok) {
1420 return backing_io_failed_ ? Status::io_error : Status::programming_error;
1431 bool present =
false;
1432 const Status st =
hget(handle, entry, present);
1433 if (st != Status::ok)
return st;
1434 if (!present || (entry.val_word & 3) !=
kLive)
return Status::not_found;
1439 if (!
readable())
return Status::programming_error;
1442 if (st != Status::ok)
return st;
1443 info.handle = handle;
1444 info.key_bytes = entry.
key_len;
1445 info.value_bytes = entry.
val_word >> 2;
1450 if (!
readable())
return Status::programming_error;
1453 if (st != Status::ok)
return st;
1456 const std::uint64_t length = is_key ? entry.
key_len : entry.
val_word >> 2;
1457 if (offset > length || destination.size > length - offset
1458 || (destination.size != 0 && destination.data ==
nullptr))
1459 return Status::programming_error;
1461 return source.read(offset, destination);
1465 if (!
readable() || !
page_ok(page) || visitor ==
nullptr)
return Status::programming_error;
1468 if (st != Status::ok)
return st;
1473 for (
int f = 0; f < 2; ++f) {
1475 const std::uint64_t length = f == 0 ? entry.
key_len : entry.
val_word >> 2;
1476 const std::uint64_t loc = f == 0 ? entry.
key_loc : entry.
val_loc;
1480 const bool go = visitor(context, view);
1482 if (!go)
return Status::cancelled;
1486 std::uint64_t done = 0;
1487 while (done < length) {
1488 const std::size_t n =
static_cast<std::size_t
>(length - done <
page_ ? length - done :
page_);
1490 if (rs != Status::ok)
return rs;
1493 const bool go = visitor(context, view);
1495 if (!go)
return Status::cancelled;
1503 if (!
readable() || !
page_ok(page) || visitor ==
nullptr)
return Status::programming_error;
1504 std::uint64_t leaf = 0;
1506 if (st != Status::ok)
return st;
1508 std::uint32_t count = 0;
1510 if (st != Status::ok)
return st;
1511 for (std::uint32_t i = 0; i < count; ++i) {
1512 std::uint64_t handle = 0;
1514 if (st != Status::ok)
return st;
1517 if (st != Status::ok)
return structural(st == Status::not_found ? Status::corrupt : st);
1526 const bool go = visitor(context, view);
1528 if (!go)
return Status::cancelled;
1531 st =
rd(leaf, 24, 8, raw);
1532 if (st != Status::ok)
return st;
1539 if (!
readable())
return Status::programming_error;
1540 std::uint64_t leaf = 0;
1542 if (st != Status::ok)
return st;
1547 std::uint64_t handle = 0;
1549 if (st != Status::ok)
return st;
1555 if (!
readable())
return Status::programming_error;
1558 if (st != Status::ok)
return st;
1562 std::uint32_t pos = 0;
1563 std::uint64_t leaf = 0;
1565 if (st != Status::ok)
return st;
1566 std::uint64_t found = 0;
1567 if (equal && leaf != 0) {
1569 if (st != Status::ok)
return st;
1571 if (found != current)
return Status::corrupt;
1572 std::uint32_t count = 0;
1574 if (st != Status::ok)
return st;
1575 if (pos + 1 < count) {
1576 std::uint64_t handle = 0;
1578 if (st != Status::ok)
return st;
1583 st =
rd(leaf, 24, 8, raw);
1584 if (st != Status::ok)
return st;
1585 const std::uint64_t next_leaf =
ld64(raw);
1586 if (next_leaf == 0) {
1590 std::uint64_t handle = 0;
1592 if (st != Status::ok)
return st;
1598 if (!
readable())
return Status::programming_error;
1601 std::uint32_t pos = 0;
1602 std::uint64_t leaf = 0;
1604 if (st != Status::ok)
return st;
1609 std::uint32_t count = 0;
1611 if (st != Status::ok)
return st;
1612 std::uint64_t handle = 0;
1615 if (st != Status::ok)
return st;
1620 st =
rd(leaf, 24, 8, raw);
1621 if (st != Status::ok)
return st;
1622 const std::uint64_t next_leaf =
ld64(raw);
1623 if (next_leaf == 0) {
1628 if (st != Status::ok)
return st;
1635 std::uint64_t done = 0;
1636 while (done < length) {
1637 const std::size_t n =
static_cast<std::size_t
>(length - done <
page_ ? length - done :
page_);
1639 if (st != Status::ok)
return st;
1640 fold.bytes(
reinterpret_cast<const Byte*
>(page.data), n);
1648 if (with_state &&
active_)
return Status::programming_error;
1655 std::uint64_t leaf = 0;
1657 if (st != Status::ok)
return st;
1659 std::uint32_t count = 0;
1661 if (st != Status::ok)
return st;
1662 for (std::uint32_t i = 0; i < count; ++i) {
1663 std::uint64_t handle = 0;
1665 if (st != Status::ok)
return st;
1668 if (st != Status::ok)
return structural(st == Status::not_found ? Status::corrupt : st);
1669 if (with_state) fold.
le64(handle);
1672 if (st != Status::ok)
return st;
1675 if (st != Status::ok)
return st;
1678 st =
rd(leaf, 24, 8, raw);
1679 if (st != Status::ok)
return st;
1682 result = fold.
value;
1742 bool backing_io_failed_ =
false;
1755 void* block = ::operator
new(total, std::nothrow);
1756 if (block ==
nullptr)
return;
1757 state_ =
new (block)
State(config, backing, total);
1761 if (state_ ==
nullptr)
return;
1764 ::operator
delete(
static_cast<void*
>(state_));
1771 return state_ && state_->carried_failure_ ? &*state_->carried_failure_ :
nullptr;
1775 return state_ ==
nullptr || state_->open_status_ !=
ScratchStatus::ok ? 0 : state_->cur_.record_count;
1778 return state_ !=
nullptr && state_->open_status_ ==
ScratchStatus::ok && state_->active_;
1804 void* context)
const noexcept {
1808 void* context)
const noexcept {
std::size_t page_size() const noexcept override
ScratchStatus ordered_digest(ScratchBuffer page, std::uint64_t &result) const noexcept
ScratchStatus state_digest(ScratchBuffer page, std::uint64_t &result) const noexcept
CommandScratchStore(ScratchStoreConfig config, ScratchBacking *backing) noexcept
ScratchStoreStats stats() const noexcept
ScratchStatus begin() noexcept
const ReportScratchIoError * carried_failure() const noexcept override
ScratchStatus read(ScratchHandle, ScratchField, std::uint64_t offset, ScratchBuffer destination) const noexcept override
ScratchStatus first(ScratchHandle &result) const noexcept
ScratchStatus rollback() noexcept
ScratchStatus for_each(ScratchBuffer page, ScratchRecordVisitor, void *context) const noexcept override
ScratchStatus point(ScratchHandle, ScratchRecordInfo &) const noexcept override
ScratchStatus commit(ScratchDurability durability) noexcept
ScratchStatus next(ScratchHandle current, ScratchHandle &result) const noexcept
ScratchStatus status() const noexcept
ScratchStatus lower_bound(const ScratchByteSource &probe, ScratchHandle &result) const noexcept
ScratchStatus erase(ScratchHandle) noexcept
std::uint64_t record_count() const noexcept override
~CommandScratchStore() noexcept override
ScratchStatus put(const ScratchByteSource &key, const ScratchByteSource &value, ScratchHandle &result) noexcept
bool transaction_active() const noexcept
ScratchStatus visit(ScratchHandle, ScratchBuffer page, ScratchChunkVisitor, void *context) const noexcept override
std::uint64_t size() const noexcept override
ScratchStatus read(std::uint64_t offset, ScratchBuffer destination) const noexcept override
BlobSource(Core *core, std::uint64_t loc, std::uint64_t len) noexcept
Status put_impl(const ScratchByteSource &key, const ScratchByteSource &value, std::uint64_t &result) noexcept
Status hset(std::uint64_t handle, const Entry &entry) noexcept
Status wr64(std::uint64_t id, std::size_t off, std::uint64_t value) noexcept
Status compare_with(const ScratchByteSource &probe, std::uint64_t handle, int &order) noexcept
Byte * page_at(std::int32_t s) noexcept
Status fetch(std::uint64_t id, bool load, std::int32_t &out) noexcept
Status bread(std::uint64_t id, Byte *destination) noexcept
std::uint64_t used_count_
Status reopen_load() noexcept
std::int32_t find(std::uint64_t id) noexcept
Status erase(ScratchHandle handle) noexcept
Status leftmost_leaf(std::uint64_t &leaf) noexcept
static std::size_t required_bytes(const ScratchStoreConfig &c, const ScratchBacking *b) noexcept
static std::uint64_t mul_sat(std::uint64_t a, std::uint64_t b) noexcept
Status victim(std::int32_t &out) noexcept
Status rollback_impl() noexcept
Status lower_bound(const ScratchByteSource &probe, ScratchHandle &result) noexcept
std::size_t bucket_of(std::uint64_t id) const noexcept
Status for_each(ScratchBuffer page, ScratchRecordVisitor visitor, void *context) noexcept
Core(const ScratchStoreConfig &c, ScratchBacking *b, std::size_t total) noexcept
Status fold_source(Fold &fold, std::uint64_t loc, std::uint64_t length, ScratchBuffer page) noexcept
bool readable() const noexcept
Status next(ScratchHandle current, ScratchHandle &result) noexcept
std::size_t blob_payload_
void link_in(std::int32_t s) noexcept
ScratchBacking * backing_
Status release_separator(std::uint64_t handle) noexcept
std::uint64_t cell_page(std::uint64_t cell) const noexcept
Status insert_up(const Path &path, std::uint64_t separator, std::uint64_t right) noexcept
void encode_super(const Super &s, Byte *buffer) const noexcept
Status tree_insert(const Path &path, std::uint64_t leaf, std::uint32_t pos, std::uint64_t handle) noexcept
Status rd_full(std::uint64_t page, Byte *buffer) noexcept
Status alloc_page(std::uint64_t &id) noexcept
static Status structural(Status status) noexcept
Status rollback() noexcept
Status put(const ScratchByteSource &key, const ScratchByteSource &value, ScratchHandle &result) noexcept
Status cell_alloc(std::uint64_t &cell) noexcept
Status rd(std::uint64_t id, std::size_t off, std::size_t len, Byte *destination) noexcept
Status tree_erase(const Path &path, std::uint64_t leaf, std::uint32_t pos, std::uint64_t handle) noexcept
Status commit(ScratchDurability durability) noexcept
void unlink(std::int32_t s) noexcept
Status blob_read(std::uint64_t loc, std::uint64_t offset, std::size_t length, Byte *destination, BlobPos &pos) noexcept
std::uint64_t tainted_slot_
std::size_t cells_per_page_
Status wr32(std::uint64_t id, std::size_t off, std::uint32_t value) noexcept
Status wr(std::uint64_t id, std::size_t off, std::size_t len, const Byte *source) noexcept
Status remove_child(const Path &path) noexcept
Status erase_impl(std::uint64_t handle, const Entry &entry) noexcept
Status index_count(std::uint64_t page, std::uint32_t &count) noexcept
Status read_source(const ScratchByteSource &source, std::uint64_t offset, Byte *destination, std::size_t length) noexcept
Status blob_free(std::uint64_t loc) noexcept
static std::size_t round_up(std::size_t n, std::size_t a) noexcept
Status live_entry(std::uint64_t handle, Entry &entry) noexcept
ScratchStoreStats stats() const noexcept
Status visit(ScratchHandle handle, ScratchBuffer page, ScratchChunkVisitor visitor, void *context) noexcept
Status hget(std::uint64_t handle, Entry &entry, bool &present) noexcept
Status blob_create(const ScratchByteSource &source, std::uint64_t length, std::uint64_t &loc) noexcept
void note_backing_failure(Status status) noexcept
bool decode_super(const Byte *buffer, Super &s, std::uint64_t &order_id) const noexcept
Status first(ScratchHandle &result) noexcept
Status point(ScratchHandle handle, ScratchRecordInfo &info) noexcept
void invalidate_all() noexcept
Status wr_page(std::uint64_t id, Byte *buffer) noexcept
Status touch(std::uint64_t id) noexcept
Status read(ScratchHandle handle, ScratchField field, std::uint64_t offset, ScratchBuffer destination) noexcept
std::size_t cell_off(std::uint64_t cell) const noexcept
std::uint64_t span_of(std::uint64_t level) const noexcept
std::optional< ReportScratchIoError > carried_failure_
Status new_root(std::uint64_t separator, std::uint64_t right) noexcept
Status free_page(std::uint64_t id) noexcept
Status commit_impl(ScratchDurability durability) noexcept
static bool geometry_ok(const ScratchStoreConfig &c, const ScratchBacking *b) noexcept
Status bwrite(std::uint64_t id, const Byte *source) noexcept
static std::size_t bucket_count(std::size_t slots) noexcept
bool page_ok(const ScratchBuffer &page) const noexcept
Status bsync(ScratchDurability durability) noexcept
Status hfind_leaf(std::uint64_t leaf_no, bool create, std::uint64_t &leaf, HPath &path) noexcept
Status digest(bool with_state, ScratchBuffer page, std::uint64_t &result) noexcept
Status descend(const ScratchByteSource &probe, Path &path, bool &equal, std::uint32_t &pos, std::uint64_t &leaf) noexcept
Status leaf_entry(std::uint64_t leaf, std::uint32_t pos, std::uint64_t &handle) noexcept
constexpr std::size_t kCell
constexpr std::uint32_t kTypeIndexLeaf
constexpr std::uint64_t kMagic
std::uint64_t ld64(const Byte *p) noexcept
constexpr std::size_t kHeader
constexpr std::uint32_t kTypeFree
constexpr std::uint32_t kTypeBlob
constexpr std::uint64_t kGhost
constexpr std::size_t kSuperFields
constexpr std::uint32_t kTypeCells
constexpr std::size_t kCellPayload
void st32(Byte *p, std::uint32_t value) noexcept
void st64(Byte *p, std::uint64_t value) noexcept
constexpr std::size_t kTrailer
constexpr unsigned kMaxDepth
constexpr std::size_t kWorkPages
constexpr std::uint32_t kTypeHandleLeaf
constexpr std::uint64_t kLive
constexpr std::uint32_t kTypeHandleNode
constexpr std::uint64_t kVersion
constexpr std::uint64_t kNoSlot
constexpr std::size_t kMaxHeight
std::uint32_t ld32(const Byte *p) noexcept
constexpr std::uint32_t kTypeIndexNode
constexpr std::size_t scratch_min_page_count
bool(*)(void *, const ScratchChunkView &) noexcept ScratchChunkVisitor
std::uint64_t ScratchHandle
constexpr ScratchHandle scratch_no_handle
constexpr std::size_t scratch_min_page_size
bool(*)(void *, const ScratchRecordView &) noexcept ScratchRecordVisitor
State(const ScratchStoreConfig &config, ScratchBacking *backing, std::size_t total) noexcept
std::uint64_t value_bytes
std::uint64_t page_writes
std::uint64_t resident_bytes
std::uint64_t backing_pages
std::uint64_t backing_bytes
std::size_t slot[kMaxHeight]
std::uint64_t node[kMaxHeight]
std::uint64_t page[kMaxDepth]
std::uint32_t slot[kMaxDepth]
std::uint64_t record_count
std::uint64_t next_handle
void bytes(const Byte *data, std::size_t length) noexcept
void le64(std::uint64_t v) noexcept