|
|
@ -269,26 +269,17 @@ typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::LeafInsertK
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
leaf_nodes_.InsertAfter(node, new_leaf);
|
|
|
|
leaf_nodes_.InsertAfter(node, new_leaf);
|
|
|
|
*split_node = new_leaf;
|
|
|
|
*split_node = new_leaf;
|
|
|
|
if (slot == node->slotuse_ && traits::kAppendMode) {
|
|
|
|
// 50/50 split
|
|
|
|
// Split high. Good for bulk load and keys are in asending order on insert
|
|
|
|
rc = node->Split(new_leaf);
|
|
|
|
*split_key = key;
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
// Just insert the new key to the new leaf. No further need to move the keys
|
|
|
|
*split_key = new_leaf->keys_[0];
|
|
|
|
// from one leaf to the other.
|
|
|
|
if (LessThan(key, *split_key)) {
|
|
|
|
rc = new_leaf->InsertIntoSlot(nullptr, 0, key, std::move(value));
|
|
|
|
rc = node->InsertIntoSlot(nullptr, slot, key, std::move(value));
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// 50/50 split
|
|
|
|
slot -= node->slotuse_;
|
|
|
|
rc = node->Split(new_leaf);
|
|
|
|
rc = new_leaf->InsertIntoSlot(nullptr, slot, key, std::move(value));
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
*split_key = new_leaf->keys_[0];
|
|
|
|
|
|
|
|
if (LessThan(key, *split_key)) {
|
|
|
|
|
|
|
|
rc = node->InsertIntoSlot(nullptr, slot, key, std::move(value));
|
|
|
|
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
slot -= node->slotuse_;
|
|
|
|
|
|
|
|
rc = new_leaf->InsertIntoSlot(nullptr, slot, key, std::move(value));
|
|
|
|
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
return rc;
|
|
|
@ -309,25 +300,18 @@ typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InnerInsert
|
|
|
|
rc = AllocateInner(&new_inner);
|
|
|
|
rc = AllocateInner(&new_inner);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
*split_node = new_inner;
|
|
|
|
*split_node = new_inner;
|
|
|
|
if (slot == node->slotuse_ && traits::kAppendMode) {
|
|
|
|
rc = node->Split(new_inner, split_key);
|
|
|
|
*split_key = key;
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
new_inner->data_[0] = node->data_[node->slotuse_];
|
|
|
|
if (LessThan(key, *split_key)) {
|
|
|
|
rc = new_inner->InsertIntoSlot(0, key, ptr);
|
|
|
|
// Need to readjust the slot position since the split key is no longer in the two children.
|
|
|
|
|
|
|
|
slot = FindSlot(node, key);
|
|
|
|
|
|
|
|
rc = node->InsertIntoSlot(slot, key, ptr);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
rc = node->Split(new_inner, split_key);
|
|
|
|
// Same reasoning as above
|
|
|
|
|
|
|
|
slot = FindSlot(new_inner, key);
|
|
|
|
|
|
|
|
rc = new_inner->InsertIntoSlot(slot, key, ptr);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
if (LessThan(key, *split_key)) {
|
|
|
|
|
|
|
|
// Need to readjust the slot position since the split key is no longer in the two children.
|
|
|
|
|
|
|
|
slot = FindSlot(node, key);
|
|
|
|
|
|
|
|
rc = node->InsertIntoSlot(slot, key, ptr);
|
|
|
|
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Same reasoning as above
|
|
|
|
|
|
|
|
slot = FindSlot(new_inner, key);
|
|
|
|
|
|
|
|
rc = new_inner->InsertIntoSlot(slot, key, ptr);
|
|
|
|
|
|
|
|
RETURN_IF_BAD_RC(rc);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
return rc;
|
|
|
@ -377,8 +361,7 @@ typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InsertKeyVa
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::Locate(RWLock *parent_lock,
|
|
|
|
typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::Locate(RWLock *parent_lock, bool forUpdate,
|
|
|
|
bool forUpdate,
|
|
|
|
|
|
|
|
BPlusTree<K, V, A, C, T>::BaseNode *top,
|
|
|
|
BPlusTree<K, V, A, C, T>::BaseNode *top,
|
|
|
|
const key_type &key,
|
|
|
|
const key_type &key,
|
|
|
|
BPlusTree<K, V, A, C, T>::LeafNode **ln,
|
|
|
|
BPlusTree<K, V, A, C, T>::LeafNode **ln,
|
|
|
@ -481,9 +464,6 @@ Status BPlusTree<K, V, A, C, T>::DoInsert(const key_type &key, std::unique_ptr<v
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
// Track all the paths to the target and lock each internal node in S.
|
|
|
|
// Track all the paths to the target and lock each internal node in S.
|
|
|
|
LockPathCB InsCB(this, retry);
|
|
|
|
LockPathCB InsCB(this, retry);
|
|
|
|
// Mark the numKeysArray invalid. We may latch the tree in S and multiple guys are doing insert.
|
|
|
|
|
|
|
|
// But it is okay as we all set the same value.
|
|
|
|
|
|
|
|
stats_.num_keys_array_valid_ = false;
|
|
|
|
|
|
|
|
// Initially we lock path in S unless we need to do node split.
|
|
|
|
// Initially we lock path in S unless we need to do node split.
|
|
|
|
retry = false;
|
|
|
|
retry = false;
|
|
|
|
BaseNode *new_child = nullptr;
|
|
|
|
BaseNode *new_child = nullptr;
|
|
|
@ -552,70 +532,6 @@ std::unique_ptr<V> BPlusTree<K, V, A, C, T>::DoUpdate(const key_type &key, std::
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
|
|
|
|
void BPlusTree<K, V, A, C, T>::PopulateNumKeys() {
|
|
|
|
|
|
|
|
// Start from the root and we calculate how many leaf nodes as pointed to by each inner node.
|
|
|
|
|
|
|
|
// The results are stored in the numKeys array in each inner node.
|
|
|
|
|
|
|
|
(void)PopulateNumKeys(root_);
|
|
|
|
|
|
|
|
// Indicate the result is accurate since we have the tree locked exclusive.
|
|
|
|
|
|
|
|
stats_.num_keys_array_valid_ = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
|
|
|
|
uint64_t BPlusTree<K, V, A, C, T>::PopulateNumKeys(BPlusTree<K, V, A, C, T>::BaseNode *n) {
|
|
|
|
|
|
|
|
if (n->is_leafnode()) {
|
|
|
|
|
|
|
|
auto *leaf = static_cast<LeafNode *>(n);
|
|
|
|
|
|
|
|
return leaf->slotuse_;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
auto *inner = static_cast<InnerNode *>(n);
|
|
|
|
|
|
|
|
uint64_t num_keys = 0;
|
|
|
|
|
|
|
|
for (auto i = 0; i < inner->slotuse_ + 1; i++) {
|
|
|
|
|
|
|
|
inner->num_keys_[i] = PopulateNumKeys(inner->data_[i]);
|
|
|
|
|
|
|
|
num_keys += inner->num_keys_[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_keys;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
|
|
|
|
typename BPlusTree<K, V, A, C, T>::key_type BPlusTree<K, V, A, C, T>::KeyAtPos(uint64_t inx) {
|
|
|
|
|
|
|
|
if (stats_.num_keys_array_valid_ == false) {
|
|
|
|
|
|
|
|
// We need exclusive access to the tree. If concurrent insert is going on, it is hard to get accurate numbers
|
|
|
|
|
|
|
|
UniqueLock lck(&rw_lock_);
|
|
|
|
|
|
|
|
// Check again.
|
|
|
|
|
|
|
|
if (stats_.num_keys_array_valid_ == false) {
|
|
|
|
|
|
|
|
PopulateNumKeys();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we know how many keys each inner branch contains, we can now traverse the correct node in log n time.
|
|
|
|
|
|
|
|
return KeyAtPos(root_, inx);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename K, typename V, typename A, typename C, typename T>
|
|
|
|
|
|
|
|
typename BPlusTree<K, V, A, C, T>::key_type BPlusTree<K, V, A, C, T>::KeyAtPos(BPlusTree<K, V, A, C, T>::BaseNode *n,
|
|
|
|
|
|
|
|
uint64_t inx) {
|
|
|
|
|
|
|
|
if (n->is_leafnode()) {
|
|
|
|
|
|
|
|
auto *leaf = static_cast<LeafNode *>(n);
|
|
|
|
|
|
|
|
return leaf->keys_[leaf->slot_dir_[inx]];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
auto *inner = static_cast<InnerNode *>(n);
|
|
|
|
|
|
|
|
if ((inx + 1) > inner->num_keys_[0]) {
|
|
|
|
|
|
|
|
inx -= inner->num_keys_[0];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return KeyAtPos(inner->data_[0], inx);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto i = 0; i < inner->slotuse_; i++) {
|
|
|
|
|
|
|
|
if ((inx + 1) > inner->num_keys_[inner->slot_dir_[i] + 1]) {
|
|
|
|
|
|
|
|
inx -= inner->num_keys_[inner->slot_dir_[i] + 1];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return KeyAtPos(inner->data_[inner->slot_dir_[i] + 1], inx);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, inx is way too big. Instead of throwing exception, we will just return the default value
|
|
|
|
|
|
|
|
// of key_type whatever it is.
|
|
|
|
|
|
|
|
return key_type();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace dataset
|
|
|
|
} // namespace dataset
|
|
|
|
} // namespace mindspore
|
|
|
|
} // namespace mindspore
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|