mirror of
https://github.com/YuhangQ/InvoDB.git
synced 2025-01-28 23:50:59 +00:00
445 lines
15 KiB
C++
445 lines
15 KiB
C++
//
|
|
// Created by YuhangQ on 2021/10/25.
|
|
//
|
|
|
|
#ifndef INVODB_BTREE_H
|
|
#define INVODB_BTREE_H
|
|
|
|
#include "btree/node.h"
|
|
#include "utils/uuid.h"
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
class BTree {
|
|
public:
|
|
BTree(const int& address);
|
|
void insert(const KT &key, const int &value);
|
|
void update(const KT &key, const int &value);
|
|
void remove(const KT &key);
|
|
bool exists(const KT &key);
|
|
int getNodeSize();
|
|
int find(const KT &key);
|
|
int size();
|
|
private:
|
|
void removeEntry(int curAdd, const KT& key, const int& pointer);
|
|
bool canCoalesce(int curAdd, int sibAdd);
|
|
void coalesce(int curAdd, int sibAdd);
|
|
bool canRedistribute(int curAdd, int sibAdd);
|
|
void redistribute(int curAdd, int sibAdd);
|
|
int findNode(const KT &key);
|
|
void split(const KT &key, int address, int parentAdd, int curAdd);
|
|
void insertInternal(const KT &key, int curAdd, int lLeafAdd, int rLeafAdd);
|
|
int root;
|
|
int n_size;
|
|
};
|
|
|
|
// BTree<M_SIZE, KT, K_SIZE> BTreeNode<M_SIZE, KT, K_SIZE>
|
|
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
BTree<M_SIZE, KT, K_SIZE>::BTree(const int& address) {
|
|
root = address;
|
|
n_size = 0;
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::insert(const KT &key, const int &value) {
|
|
if(exists(key)) {
|
|
throw "keySet already exists.";
|
|
}
|
|
|
|
n_size++;
|
|
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(findNode(key));
|
|
|
|
// insert directly
|
|
if(cur->size < cur->m - 1) {
|
|
cur->linkSet[cur->insert(key)] = value;
|
|
cur->save();
|
|
return;
|
|
}
|
|
|
|
// split
|
|
split(key, value, cur->parent, cur->address);
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::update(const KT &key, const int &value) {
|
|
if(!exists(key)) {
|
|
throw "keySet doesn't exists.";
|
|
}
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(findNode(key));
|
|
cur->linkSet[cur->findPos(key)] = value;
|
|
cur->save();
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::remove(const KT &key) {
|
|
if(!exists(key)) {
|
|
throw "keySet already exists.";
|
|
}
|
|
n_size--;
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(findNode(key));
|
|
removeEntry(cur->address, key, find(key));
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
int BTree<M_SIZE, KT, K_SIZE>::find(const KT &key) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(findNode(key));
|
|
for(int i=0; i<cur->size; i++) {
|
|
if(key == cur->keySet[i]) return cur->linkSet[i];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
int BTree<M_SIZE, KT, K_SIZE>::size() {
|
|
return n_size;
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::removeEntry(int curAdd, const KT &key, const int &pointer) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
int pos = cur->findPos(key);
|
|
if(pos == -1) return;
|
|
for(int i=pos; i<cur->size-1; i++) {
|
|
cur->keySet[i] = cur->keySet[i + 1];
|
|
}
|
|
for(int i=pos+(cur->linkSet[pos] != pointer); i<cur->size; i++) {
|
|
cur->linkSet[i] = cur->linkSet[i + 1];
|
|
}
|
|
cur->size--;
|
|
cur->save();
|
|
|
|
if(curAdd == root && !cur->leaf && cur->size == 0) {
|
|
root = cur->linkSet[0];
|
|
auto root = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->linkSet[0]);
|
|
root->parent = 0;
|
|
root->save();
|
|
cur->release();
|
|
return;
|
|
}
|
|
|
|
if(cur->enough() || cur->address == root) return;
|
|
|
|
if(canCoalesce(cur->address, cur->left)) {
|
|
coalesce(cur->address, cur->left);
|
|
} else if(canCoalesce(cur->address, cur->right)) {
|
|
coalesce(cur->address, cur->right);
|
|
} else if(canRedistribute(cur->address, cur->left)) {
|
|
redistribute(cur->address, cur->left);
|
|
} else if(canRedistribute(cur->address, cur->right)) {
|
|
redistribute(cur->address, cur->right);
|
|
} else {
|
|
throw "these is a bug!";
|
|
}
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
bool BTree<M_SIZE, KT, K_SIZE>::canCoalesce(int curAdd, int sibAdd) {
|
|
if(sibAdd == 0) return false;
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
auto sib = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sibAdd);
|
|
if(cur->parent != sib->parent) return false;
|
|
return (cur->size + sib->size <= BTreeNode<M_SIZE, KT, K_SIZE>::m - 1 - !cur->leaf);
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::coalesce(int curAdd, int sibAdd) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
auto sib = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sibAdd);
|
|
auto parent = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->parent);
|
|
KT *k;
|
|
for(int i=0; i<parent->size; i++) {
|
|
if((parent->linkSet[i] == curAdd && parent->linkSet[i+1] == sibAdd)
|
|
|| (parent->linkSet[i] == sibAdd && parent->linkSet[i+1] == curAdd)) {
|
|
k = &parent->keySet[i];
|
|
break;
|
|
}
|
|
}
|
|
BTreeNode<M_SIZE, KT, K_SIZE>* newNode = nullptr;
|
|
if(cur->left == sibAdd) {
|
|
if(!cur->leaf) sib->insert(*k);
|
|
for(int i=0; i<cur->size; i++) {
|
|
sib->linkSet[sib->insert(cur->keySet[i])] = cur->linkSet[i];
|
|
}
|
|
sib->linkSet[sib->size] = cur->linkSet[cur->size];
|
|
sib->right = cur->right;
|
|
if(cur->right) {
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *right = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->right);
|
|
right->left = sib->address;
|
|
right->save();
|
|
}
|
|
newNode = sib;
|
|
newNode->save();
|
|
removeEntry(parent->address, *k, curAdd);
|
|
cur->release();
|
|
} else {
|
|
if(!cur->leaf) cur->insert(*k);
|
|
for(int i=0; i<sib->size; i++) {
|
|
cur->linkSet[cur->insert(sib->keySet[i])] = sib->linkSet[i];
|
|
}
|
|
cur->linkSet[cur->size] = sib->linkSet[sib->size];
|
|
|
|
cur->right = sib->right;
|
|
|
|
if(sib->right) {
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *right = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sib->right);
|
|
right->left = cur->address;
|
|
right->save();
|
|
}
|
|
newNode = cur;
|
|
newNode->save();
|
|
removeEntry(parent->address, *k, sibAdd);
|
|
sib->release();
|
|
}
|
|
if(newNode->leaf) return;
|
|
for(int i=0; i<=newNode->size; i++) {
|
|
auto child = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(newNode->linkSet[i]);
|
|
child->parent = newNode->address;
|
|
child->save();
|
|
}
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
bool BTree<M_SIZE, KT, K_SIZE>::canRedistribute(int curAdd, int sibAdd) {
|
|
if(sibAdd == 0) return false;
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
auto sib = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sibAdd);
|
|
if(cur->parent != sib->parent) return false;
|
|
return sib->size > ((sib->m - !sib->leaf) / 2);
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::redistribute(int curAdd, int sibAdd) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
auto sib = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sibAdd);
|
|
auto parent = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->parent);
|
|
KT k;
|
|
int pos;
|
|
for(pos=0; pos<parent->size; pos++) {
|
|
if((parent->linkSet[pos] == curAdd && parent->linkSet[pos+1] == sibAdd)
|
|
|| (parent->linkSet[pos] == sibAdd && parent->linkSet[pos+1] == curAdd)) {
|
|
k = parent->keySet[pos];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(cur->left == sibAdd) {
|
|
if(cur->leaf) {
|
|
cur->linkSet[cur->insert(sib->keySet[sib->size-1])] = sib->linkSet[sib->size-1];
|
|
parent->keySet[pos] = cur->keySet[0];
|
|
} else{
|
|
cur->linkSet[cur->insert(k)] = sib->linkSet[sib->size];
|
|
parent->keySet[pos] = sib->keySet[sib->size-1];
|
|
}
|
|
if(!cur->leaf) {
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *child = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sib->linkSet[sib->size - cur->leaf]);
|
|
child->parent = cur->address;
|
|
child->save();
|
|
}
|
|
sib->size--;
|
|
} else {
|
|
if(cur->leaf) {
|
|
cur->linkSet[cur->insert(sib->keySet[0])] = sib->linkSet[0];
|
|
for(int i=0; i<sib->size; i++) {
|
|
sib->keySet[i] = sib->keySet[i+1];
|
|
sib->linkSet[i] = sib->linkSet[i+1];
|
|
}
|
|
parent->keySet[pos] = sib->keySet[0];
|
|
} else {
|
|
if(cur->size != 0) {
|
|
cur->linkSet[cur->insert(k)+1] = sib->linkSet[0];
|
|
} else {
|
|
cur->keySet[0] = k;
|
|
cur->linkSet[1] = sib->linkSet[0];
|
|
cur->size++;
|
|
}
|
|
parent->keySet[pos] = sib->keySet[0];
|
|
if(!cur->leaf) {
|
|
auto child = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(sib->linkSet[0]);
|
|
child->parent = cur->address;
|
|
child->save();
|
|
}
|
|
for(int i=0; i<sib->size; i++) {
|
|
sib->keySet[i] = sib->keySet[i+1];
|
|
sib->linkSet[i] = sib->linkSet[i+1];
|
|
}
|
|
}
|
|
sib->size--;
|
|
}
|
|
|
|
cur->save();
|
|
sib->save();
|
|
parent->save();
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
int BTree<M_SIZE, KT, K_SIZE>::findNode(const KT &key) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(root);
|
|
while(!cur->leaf) {
|
|
for(int i=0; i<cur->size; i++) {
|
|
if(key < cur->keySet[i]) {
|
|
cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->linkSet[i]);
|
|
break;
|
|
}
|
|
if(i == cur->size - 1) {
|
|
cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->linkSet[i + 1]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cur->address;
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::split(const KT &key, int address, int parentAdd, int curAdd) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
|
|
cur->linkSet[cur->insert(key)] = address;
|
|
|
|
auto lLeaf = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
auto rLeaf = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
|
|
int mid = (cur->m / 2);
|
|
for(int i=0; i<mid; i++) lLeaf->linkSet[lLeaf->insert(cur->keySet[i])] = cur->linkSet[i];
|
|
lLeaf->right = rLeaf->address;
|
|
lLeaf->left = cur->left;
|
|
for(int i=mid; i<cur->m; i++) rLeaf->linkSet[rLeaf->insert(cur->keySet[i])] = cur->linkSet[i];
|
|
rLeaf->left = lLeaf->address;
|
|
rLeaf->right = cur->right;
|
|
|
|
if(cur->left) {
|
|
auto curLeft = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->left);
|
|
curLeft->right = lLeaf->address;
|
|
curLeft->save();
|
|
}
|
|
|
|
if(cur->right) {
|
|
auto curRight = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->right);
|
|
curRight->left = rLeaf->address;
|
|
curRight->save();
|
|
}
|
|
|
|
cur->release();
|
|
|
|
if(cur->address == root) {
|
|
auto newRoot = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
newRoot->insert(rLeaf->keySet[0]);
|
|
newRoot->linkSet[0] = lLeaf->address;
|
|
newRoot->linkSet[1] = rLeaf->address;
|
|
newRoot->leaf = false;
|
|
root = newRoot->address;
|
|
newRoot->parent = 0;
|
|
lLeaf->parent = rLeaf->parent = root;
|
|
|
|
newRoot->save();
|
|
lLeaf->save();
|
|
rLeaf->save();
|
|
} else {
|
|
lLeaf->save();
|
|
rLeaf->save();
|
|
insertInternal(rLeaf->keySet[0], cur->parent, lLeaf->address, rLeaf->address);
|
|
}
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
void BTree<M_SIZE, KT, K_SIZE>::insertInternal(const KT &key, int curAdd, int lLeafAdd, int rLeafAdd) {
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(curAdd);
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *lLeaf = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(lLeafAdd);
|
|
BTreeNode<M_SIZE, KT, K_SIZE> *rLeaf = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(rLeafAdd);
|
|
|
|
if(cur->size < cur->m - 1) {
|
|
int pos = cur->insert(key);
|
|
cur->linkSet[pos] = lLeaf->address;
|
|
cur->linkSet[pos+1] = rLeaf->address;
|
|
lLeaf->parent = rLeaf->parent = curAdd;
|
|
cur->save();
|
|
lLeaf->save();
|
|
rLeaf->save();
|
|
return;
|
|
}
|
|
|
|
auto newLChild = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
auto newRChild = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
newLChild->leaf = false;
|
|
newRChild->leaf = false;
|
|
newLChild->right = newRChild->address;
|
|
newLChild->left = cur->left;
|
|
newRChild->left = newLChild->address;
|
|
newRChild->right = cur->right;
|
|
|
|
if(cur->left) {
|
|
auto curLeft = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->left);
|
|
curLeft->right = newLChild->address;
|
|
curLeft->save();
|
|
}
|
|
|
|
if(cur->right) {
|
|
auto curRight = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(cur->right);
|
|
curRight->left = newRChild->address;
|
|
curRight->save();
|
|
}
|
|
|
|
int pos = cur->insert(key);
|
|
cur->linkSet[pos] = lLeaf->address;
|
|
cur->linkSet[pos+1] = rLeaf->address;
|
|
|
|
int mid = cur->size / 2;
|
|
|
|
for(int i=0; i<mid; i++) newLChild->insert(cur->keySet[i]);
|
|
for(int i=0; i<=mid; i++) newLChild->linkSet[i] = cur->linkSet[i];
|
|
|
|
for(int i=mid+1; i<cur->m; i++) newRChild->insert(cur->keySet[i]);
|
|
for(int i=mid+1; i<=cur->m; i++) newRChild->linkSet[i-mid-1] = cur->linkSet[i];
|
|
|
|
for(int i=0; i<=newLChild->size; i++) {
|
|
auto child = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(newLChild->linkSet[i]);
|
|
child->parent = newLChild->address;
|
|
child->save();
|
|
}
|
|
for(int i=0; i<=newRChild->size; i++) {
|
|
auto child = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(newRChild->linkSet[i]);
|
|
child->parent = newRChild->address;
|
|
child->save();
|
|
}
|
|
|
|
cur->release();
|
|
|
|
if(cur->address == root) {
|
|
auto newRoot = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(PageManager::Instance().allocate());
|
|
newRoot->insert(cur->keySet[mid]);
|
|
newRoot->linkSet[0] = newLChild->address;
|
|
newRoot->linkSet[1] = newRChild->address;
|
|
newRoot->leaf = false;
|
|
root = newRoot->address;
|
|
newRoot->parent = 0;
|
|
newLChild->parent = newRChild->parent = root;
|
|
|
|
newRoot->save();
|
|
newLChild->save();
|
|
newRChild->save();
|
|
} else {
|
|
newLChild->save();
|
|
newRChild->save();
|
|
insertInternal(cur->keySet[mid], cur->parent, newLChild->address, newRChild->address);
|
|
}
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
int BTree<M_SIZE, KT, K_SIZE>::getNodeSize() {
|
|
auto p = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(root);
|
|
return p->save();
|
|
}
|
|
|
|
template<int M_SIZE, typename KT, int K_SIZE>
|
|
bool BTree<M_SIZE, KT, K_SIZE>::exists(const KT &key) {
|
|
auto cur = BTreeNode<M_SIZE, KT, K_SIZE>::getNode(findNode(key));
|
|
for(int i=0; i<cur->size; i++) {
|
|
if(key == cur->keySet[i]) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
#endif //INVODB_BTREE_H
|