T73WR2BX2QDQ6APOREBXUKNH52FDLJNBGWPQUYB2TAF2PT7XCL2AC
XEU2QVLCHPYOOD4TQIPEEVYOVSFMKFPLJYWEJYXYJAZ7S54KWDZAC
WAKPPBKONQUA3G7HWH52ZKYG5PLZEAG3HFAYGIYLA4NVEPRZUQEAC
H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC
KX3WVNZW5KHVEH6EOQTZ4RBEFFJ3SGF5I467X3JWZ74PURRK4HVAC
QEUTVAZ4F4EJXRDMWDMYXF6XEDMX7YPVG4IIXEKPIR3K54E5W5OAC
WS4ZQM4RMIHZ6XZKSDQJGHN5SSSWFL4H236USOPUA33S6RC53RFAC
OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC
W26CFMAQOXMUK4ZOJMAN4SMBXMWFQHO7HCTEVW73FQSRMJZFGJIQC
OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC
X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC
APPY2E7M5NHNC6MFYXSVEKJVAILK7YAZVTVE3W75EK2JNFVS3XBQC
EAAYH6BQWDK52EC5RG3BEZQU3FJPN5RRRN4U5KDKDVPKXBVJMNDAC
OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC
/// If `value` is `None`, delete one of the bindings associated to
/// `key` from the database (without any specific
/// preference). Else, delete the specified binding if present.
/// If `value` is `None`, delete the first entry for `key` from the
/// database, if present. Else, delete the entry for `(key, value)`,
/// if present.
// Find the leftmost page in the right subtree, that is where the
// "replacement" element is.
// Find the leftmost page in the right subtree of the deleted
// element, in order to find a replacement.
// Mark the replacement for deletion in the leaf, and copy it into
// (k0, v0) if the deletion happens in an internal node (`(k0,
// v0)` is uninitialized else).
// In the leaf, mark the replacement for deletion, and keep a
// reference to it in k0v0 if the deletion happens in an internal
// node (k0v0 is `Option::None` else).
if is_rc {
let mut c0 = c0.clone();
let mut c1 = c1.clone();
P::move_next(curs0.page.as_page(), &mut c1);
while let Some((k, v, _)) = P::next(txn, curs0.page.as_page(), &mut c0)
.or_else(|| P::next(txn, curs0.page.as_page(), &mut c1))
{
for o in k.page_offsets().chain(v.page_offsets()) {
txn.incr_rc(o)?;
}
}
}
// increase the RC of the replacement.
debug!("{:?}", c0);
// In this case, we need to save the replacement. If the
// replacement has references, we will increment them later,
// when updating the page where the deletion happens.
if let Some(s) = k0v0 {
let (k0, v0) = unsafe { P::from_saved(s) };
let other = txn.load_page(P::left_child(curs.page.as_page(), &curs.cursor))?;
let other_is_rced = if p > rc_l {
true
// Here, p == p0, meaning that we're deleting at an internal
// node. If that's the case, k0v0 is `Some`, hence we can
// safely unwrap the replacement.
let (k0, v0) = unsafe { P::from_saved(k0v0.as_ref().unwrap()) };
// Since we've picked the leftmost entry of the right child of
// the deleted entry, the other page to consider in the
// concatenation is the left child of the deleted entry.
let other = txn.load_page(P::left_child(curs.page.as_page(), &curs.cursor))?;
// Then, if the page at level `p` or one of its ancestor, is
// pointed at least twice (i.e. if `p >= rc_level`, or
// alternatively if `other` is itself pointed at least twice,
// the page is immutable, meaning that we can't delete on it
// when rebalancing.
let other_is_mutable = (p < rc_level) && txn.rc(other.offset)? < 2;
Ok(Concat {
modified: last_op,
mid: (k0, v0),
other,
mod_is_left: false,
other_is_mutable,
})
} else {
// Here, `p` is not a leaf (but `last_op` might be), and does
// not contain the deleted entry.
// In this case, the visited page at level `p+1` is always on
// the left-hand side of the cursor at level `p` (this is an
// invariant of cursors). However, if the cursor at level `p`
// is past the end of the page, we need to move one step back
// to find a middle element for the concatenation, in which
// case the visited page becomes the right-hand side of the
// cursor.
let ((k, v, r), mod_is_left) =
if let Some(x) = P::current(txn, curs.page.as_page(), &curs.cursor) {
// Not the last element of the page.
(x, true)
Ok(Concat {
modified: last_op,
mid: (k0, v0),
other,
mod_is_left: false,
other_is_mutable: !other_is_rced,
})
} else {
unreachable!()
}
} else {
let mut mod_is_left = true;
let (k, v, r) = if let Some(x) = P::current(txn, curs.page.as_page(), &curs.cursor) {
// Not the last element of the page.
x
} else {
// Last element of the page.
mod_is_left = false;
let (k, v, _) = P::prev(txn, curs.page.as_page(), &mut curs.cursor).unwrap();
let l = P::left_child(curs.page.as_page(), &curs.cursor);
debug!("prev: {:?}", l);
(k, v, l)
};
if incr_kv_rc {
// Here, note that the rebalancing element cannot
// possibly be the replacement element, so since it is
// copied, we need to increment its RC (the
// replacement entry has its RC incremented at
// deletion).
for o in k.page_offsets().chain(v.page_offsets()) {
txn.incr_rc(o)?;
}
}
last_op.skip_first = false
}
last_op.skip_first = false;
// If the split key is the replacement element, we have
// already increased its counter when we deleted it from
// its original position at the bottom of the tree.
//
// This can happen if we replaced an element and that
// replacement caused a split with the replacement as the
// middle element.
if let Some(k0v0) = k0v0 {
assert!(cursor.pointer() < p0);
let (k0, _) = unsafe { P::from_saved(k0v0) };
core::ptr::eq(k0, split_key)
} else {
false
}
};
// If the split key is the replacement element, we have
// already increased its counter when we deleted it from
// its original position at the bottom of the tree.
//
// This can happen if we replaced an element and that
// replacement caused a split with the replacement as the
// middle element.
let split_key_is_k0 = if let Some(k0v0) = k0v0 {
let (k0, _) = unsafe { P::from_saved(k0v0) };
(k0 as *const K) == (split_key as *const K)
} else {
false
};
}
// The insertions come from pages strictly below the page at
// cursor.pointer, so if `incr_ins`, we increment them here,
// except the replacement, already incremented in `leaf_delete`
// above
if p + 1 >= first_rc_level {
if let Some((k, v)) = m.ins {
// If this is the replacement, it has already been
// incremented in `leaf_delete`, so we don't need to
// increment it again.
if m.skip_first {
for o in k.page_offsets().chain(v.page_offsets()) {
txn.incr_rc(o)?;
}
}
if let Some((k, v)) = m.ins2 {
for o in k.page_offsets().chain(v.page_offsets()) {
txn.incr_rc(o)?;
}
}
}
}
if p >= first_rc_level {
// The insertions are taken care of in `handle_merge` above,
// so we can directly move to the `c1` part of the
// modification.
// Moving on to the first non-deleted element of `c1`: if we
// are not updating the right child of the first element,
// increment that right child's RC.
// If we are not updating the right child of the first
// element of `c1`, increment that right child's RC.
if !is_rc {
if P::is_dirty(last_op.page.as_page()) {
txn.decr_rc_owned(last_op.page.offset)?;
} else {
txn.decr_rc(last_op.page.offset)?;
}
if P::is_dirty(last_op.page.as_page()) {
txn.decr_rc_owned(last_op.page.offset)?;
} else {
txn.decr_rc(last_op.page.offset)?;
// Else, we execute the last operation
debug!("modify {:?}", last_op);
// Else, the last operation `last_op` was relative to the root,
// but it hasn't been applied yet. We apply it now:
P::put(
txn,
page.0,
true,
&c,
split_key,
split_value,
None,
left.0.offset,
right.0.offset,
)?;
P::put(txn, page.0, true, &c, k, v, None, l.0.offset, r.0.offset)?;