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`// aboveif 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 operationdebug!("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)?;