// http://www.cs.msstate.edu/~cs2314/global/BTreeAnimation/algorithm.html #include <stdlib.h> #include <string.h> #include <stdio.h> #include <iostream> #include "btree.h" #include "inode.h" #include "assert.h" using namespace std; #define VERIFY(x, y, z, n) if ((x) != (y)) { cout << "verify " << z << " failed" << endl; PrintWholeTree(); } bTree::bTree(ubixfsInode * inode) : root(NULL) { treeDepth = 1; treeWidth = 0; treeLeafCount = 0; if (inode == NULL) return; root = allocEmptyNode(); if (root == NULL) return; root->used = 1; root->parent = NULL; root->leaf = true; root->childCount[1] = 1; // cout << "---Creating " << inode->name << "@" << inode << endl; strncpy(root->keys[0], inode->name, B_MAX_NAME_LENGTH); // insert pointer to data page to the right of the data root->head[1] = (void *)inode; root->tail[1] = (void *)inode; root->present[1] = true; if (inode != NULL) { inode->next = inode->prev = NULL; } // if return; } // bTree:bTree bool bTree::Insert(ubixfsInode * inode) { bNode * bnode = root; ubixfsInode * tmpInode = NULL; unsigned int curSlot = 0; if (inode == NULL) return false; // note: this code is right out of the constructor if (root == NULL) { treeDepth = 1; treeWidth = 0; treeLeafCount = 0; root = allocEmptyNode(); assert(root); if (root == NULL) return false; root->used = 1; root->parent = NULL; root->leaf = true; root->childCount[1] = 1; strncpy(root->keys[0], inode->name, B_MAX_NAME_LENGTH); // insert pointer to data page to the right of the data root->head[1] = (void *)inode; root->tail[1] = (void *)inode; root->present[1] = true; inode->next = inode->prev = NULL; return true; } // if tmpInode = Find(inode->name); if (tmpInode != NULL) return false; // PrintWholeTree(); // cout << "Insert(" << inode->name << ")" << endl; //Info(bnode); ++treeLeafCount; /* * Find the leaf node the inode goes into */ assert(bnode->used); // cout << "---Inserting " << inode->name << "@" << inode << endl; while (bnode != NULL && !bnode->leaf) { if (strcmp(inode->name, bnode->keys[0]) < 0) { bnode = (bNode *)bnode->head[0]; } else { if (strcmp(inode->name, bnode->keys[bnode->used-1]) >= 0) { bnode = (bNode *)bnode->head[bnode->used]; } else { for (unsigned int i = 1; i < bnode->used; i++) { if (strcmp(inode->name, bnode->keys[i]) < 0) { bnode = (bNode *)bnode->head[i]; break; } // if } // for i } // else } } // while /* * */ assert(bnode); if (bnode->leaf != true) cout << "leafnode!=true" << endl; assert(inode); if (strcmp(inode->name, bnode->keys[curSlot = 0]) < 0) tmpInode = (ubixfsInode *)bnode->head[curSlot]; else if (strcmp(inode->name, bnode->keys[(curSlot = bnode->used)-1]) >= 0) tmpInode = (ubixfsInode *)bnode->head[bnode->used]; else { for (curSlot = 1; curSlot < bnode->used; curSlot++) { if (strcmp(inode->name, bnode->keys[curSlot]) < 0) { tmpInode = (ubixfsInode *)bnode->head[curSlot]; break; } // if } // for curSlot tmpInode = (ubixfsInode *)bnode->head[curSlot]; } // else if (tmpInode == NULL) { /* * This is the first node in this leaf */ bnode->head[curSlot] = bnode->tail[curSlot] = inode; bnode->present[curSlot] = true; if (curSlot == 0) { if (bnode->head[1] != NULL) { ubixfsInode * iptr = (ubixfsInode *)bnode->head[1]; inode->prev = iptr->prev; inode->next = iptr; iptr->prev = inode; if (inode->prev != NULL) inode->prev->next = inode; } else { inode->next = inode->prev = NULL; } // else } else { ++bnode->used; } // else } else { /* * Add node to leaf page. Scan through to find where it goes. */ if (strcmp(inode->name, ((ubixfsInode *)bnode->head[curSlot])->name) < 0) { inode->next = (ubixfsInode *)bnode->head[curSlot]; inode->prev = inode->next->prev; inode->next->prev = inode; if (inode->prev != NULL) inode->prev->next = inode; bnode->head[curSlot] = (void *)inode; } else { if (strcmp(inode->name, ((ubixfsInode *)bnode->tail[curSlot])->name) > 0) { inode->prev = (ubixfsInode *)bnode->tail[curSlot]; inode->next = inode->prev->next; inode->prev->next = inode; if (inode->next != NULL) inode->next->prev = inode; bnode->tail[curSlot] = inode; } else { ubixfsInode * tmpInode = (ubixfsInode *)bnode->head[curSlot]; for (unsigned int i = 0; i < bnode->childCount[curSlot]; i++) { if (strcmp(inode->name, tmpInode->name) < 0) { inode->next = tmpInode; inode->prev = tmpInode->prev; inode->next->prev = inode; inode->prev->next = inode; break; } // if tmpInode = tmpInode->next; } // for i } // else } // else } // else if (++bnode->childCount[curSlot] == B_MAX_CHILD_COUNT) { // cout << "---- before split ----" << endl; // Info(bnode); if (curSlot != bnode->used) { int shift = bnode->used - curSlot +1; memmove(&bnode->head[curSlot+1], &bnode->head[curSlot], sizeof(bnode->head[0]) * shift); memmove(&bnode->tail[curSlot+1], &bnode->tail[curSlot], sizeof(bnode->tail[0]) * shift); memmove(&bnode->present[curSlot+1], &bnode->present[curSlot], sizeof(bnode->present[0]) * shift); memmove(&bnode->childCount[curSlot+1], &bnode->childCount[curSlot], sizeof(bnode->childCount[0]) * shift); memmove(&bnode->keys[curSlot+1], &bnode->keys[curSlot], sizeof(bnode->keys[0]) * (shift-1)); memset(bnode->keys[curSlot], 0, B_MAX_NAME_LENGTH); } else { bnode->head[curSlot+1] = bnode->head[curSlot]; bnode->tail[curSlot+1] = bnode->tail[curSlot]; bnode->childCount[curSlot+1] = bnode->childCount[curSlot]; bnode->present[curSlot+1] = bnode->present[curSlot]; } // else ubixfsInode * tmpInode = (ubixfsInode *)bnode->head[curSlot]; for (unsigned int i = 0; i < (B_MAX_CHILD_COUNT+1) >> 1; i++) { assert(tmpInode); tmpInode = tmpInode->next; } // for i strncpy(bnode->keys[curSlot], tmpInode->name, B_MAX_NAME_LENGTH); bnode->head[curSlot+1] = (void *)tmpInode; bnode->tail[curSlot] = (void *)tmpInode->prev; bnode->childCount[curSlot] = (B_MAX_CHILD_COUNT+1) >> 1; bnode->childCount[curSlot+1] -= bnode->childCount[curSlot]; bnode->present[curSlot] = true; ++treeWidth; if (++bnode->used == B_MAX_KEYS) splitNode(bnode); } // if leaf is full // Info(bnode); return true; } // bTree::Insert void bTree::splitNode(bNode * oldNode) { ubixfsInode * tmpInode = NULL; assert(oldNode); if (oldNode == NULL) return; if (oldNode->used != B_MAX_KEYS) return; bNode * newNode = allocEmptyNode(); if (newNode == NULL) return; unsigned int shift = B_MAX_KEYS >> 1; unsigned int splitLoc = B_MAX_KEYS - shift; ++ shift; // cout << "oldNode before split: " << endl; // Info(oldNode); // cout << "splitLoc: " << splitLoc << endl; // cout << "shift: " << shift << endl; newNode->used = oldNode->used = B_MAX_KEYS >> 1; newNode->parent = oldNode->parent; assert(newNode->parent != oldNode); assert(oldNode->parent != newNode); newNode->leaf = oldNode->leaf; // cout << "newNode->used: " << newNode->used << endl; // cout << "oldNode->used: " << oldNode->used << endl; memcpy(&newNode->keys[0], &oldNode->keys[splitLoc], sizeof(newNode->keys[0]) * (shift-1)); memset(&oldNode->keys[splitLoc], 0, sizeof(newNode->keys[0]) * (shift-1)); memcpy(&newNode->present[0], &oldNode->present[splitLoc], sizeof(newNode->present[0]) * shift); memset(&oldNode->present[splitLoc], 0, sizeof(newNode->present[0]) * shift); memcpy(&newNode->head[0], &oldNode->head[splitLoc], sizeof(newNode->head[0]) * shift); memset(&oldNode->head[splitLoc], 0, sizeof(newNode->head[0]) * shift); memcpy(&newNode->tail[0], &oldNode->tail[splitLoc], sizeof(newNode->tail[0]) * shift); memset(&oldNode->tail[splitLoc], 0, sizeof(newNode->tail[0]) * shift); memcpy(&newNode->childCount[0], &oldNode->childCount[splitLoc], sizeof(newNode->childCount[0]) * shift); memset(&oldNode->childCount[splitLoc], 0, sizeof(newNode->childCount[0]) * shift); if (!newNode->leaf) { for (unsigned int i = 0; i <= newNode->used; i++) { ((bNode *)newNode->head[i])->parent = newNode; } // for i } // if newNode isn't a leaf tmpInode = GetFirstNode(newNode); assert(tmpInode); if (oldNode == root) { // allocate a new root node ++treeDepth; root = allocEmptyNode(); oldNode->parent = root; newNode->parent = root; // strncpy(root->keys[0], newNode->keys[0], B_MAX_NAME_LENGTH); strncpy(root->keys[0], tmpInode->name, B_MAX_NAME_LENGTH); root->head[0] = oldNode; root->tail[0] = root->tail[1] = NULL; root->head[1] = newNode; root->used = 1; root->leaf = false; root->present[0] = root->present[1] = true; root->childCount[0] = root->childCount[1] = 0; // root->childCount[0] = oldNode->used; // root->childCount[1] = newNode->used; // cout << "parent" << endl; // Info(newNode->parent); // cout << "oldNode" << endl; // Info(oldNode); // cout << "-----" << endl; // cout << "newNode" << endl; // Info(newNode); // cout << "-----" << endl; } else { assert(newNode->parent != oldNode); assert(oldNode->parent != newNode); insertNode(newNode->parent, tmpInode->name, newNode, NULL); assert(newNode->parent != oldNode); assert(oldNode->parent != newNode); // if (oldNode->parent->used == B_MAX_KEYS) splitNode(oldNode->parent); } // else assert(newNode->parent != oldNode); assert(oldNode->parent != newNode); return; } // bTree::splitNode void bTree::insertNode(bNode * node, const char * key, void * headPtr, void * tailPtr) { unsigned int curSlot = 0; if (node == NULL || key == NULL) return; if (strcmp(key, node->keys[node->used-1]) >= 0){ curSlot = node->used; memset(node->keys[curSlot], 0, B_MAX_NAME_LENGTH); strncpy(node->keys[curSlot], key, B_MAX_NAME_LENGTH); node->head[curSlot+1] = headPtr; node->tail[curSlot+1] = tailPtr; node->present[curSlot+1] = true; node->childCount[node->used] = 0; // maybe? } else { for (curSlot = 0; curSlot < node->used; curSlot++) { if (strcmp(key, node->keys[curSlot]) < 0) break; } // for /* * note that there is one more item for everything but keys * So, make the shift count +1 and just subtract it from the key shift * later */ int shift = node->used - curSlot +1; memmove(&node->head[curSlot+1], &node->head[curSlot], sizeof(node->head[0]) * shift); memmove(&node->tail[curSlot+1], &node->tail[curSlot], sizeof(node->tail[0]) * shift); memmove(&node->present[curSlot+1], &node->present[curSlot], sizeof(node->present[0]) * shift); memmove(&node->childCount[curSlot+1], &node->childCount[curSlot], sizeof(node->childCount[0]) * shift); memmove(&node->keys[curSlot+1], &node->keys[curSlot], sizeof(node->keys[0]) * (shift-1)); memset(node->keys[curSlot], 0, B_MAX_NAME_LENGTH); strncpy(node->keys[curSlot], key, B_MAX_NAME_LENGTH); node->head[curSlot+1] = headPtr; node->tail[curSlot+1] = tailPtr; node->present[curSlot+1] = true; // node->childCount[node->used] = ?; } // else if (++node->used == B_MAX_KEYS) splitNode(node); return; } // bTree::insertNode bNode * bTree::allocEmptyNode(void) { bNode * newNode = (bNode *)malloc(sizeof(bNode)); memset(newNode, 0, sizeof(bNode)); newNode->magic1 = B_NODE_MAGIC_1; newNode->magic2 = B_NODE_MAGIC_2; newNode->parent = NULL; return newNode; } // bTree::allocEmptyNode void bTree::Info(const bNode * node) { ubixfsInode * inode = NULL; if (node == NULL) return; cout << node << " | " << node->parent << endl; for (unsigned int i = 0; i <= node->used; i++) { inode = (ubixfsInode *)node->head[i]; // cout << "(" << node->childCount[i] << ")"; for (unsigned int k = 0; k < node->childCount[i]; k++) { cout << "[" << inode->name << "]"; inode = inode->next; } // for k if (i != node->used) cout << " {" << node->keys[i] << "} "; } // for i cout << endl; return; #if 0 for (unsigned int i = 0; i < node->used; i++) { cout << "keys[" << i << "]: " << node->keys[i] << " "; } // for i cout << endl; cout << "node->used: " << node->used << endl; cout << "leaf: " << node->leaf << endl; for (unsigned int i = 0; i <= node->used; i++) { inode = (ubixfsInode *)node->head[i]; cout << "node->childCount["<<i<<"]: " << node->childCount[i] << endl; for (unsigned int j = 0; j < node->childCount[i]; j++) { assert(inode); cout << "[" << i << "].[" << j << "]->" << inode->name << endl; inode = inode->next; } // for j } // for i #endif } // bTree::Info void bTree::Info(void) { ubixfsInode * inode = NULL; if (root == NULL) return; for (unsigned int i = 0; i <= root->used; i++) { cout << "CC[" << i << "]: " << root->childCount[i] << " "; } // for i cout << endl; for (unsigned int i = 0; i <= root->used; i++) { cout << "CH[" << i << "]: " << root->head[i] << " "; } // for i cout << endl; for (unsigned int i = 0; i <=root->used; i++) { cout << "CT[" << i << "]: " << root->tail[i] << " "; } // for i cout << endl; for (unsigned int i = 0; i < root->used; i++) { cout << "keys[" << i << "]: " << root->keys[i] << " "; } // for i cout << endl; cout << "root->used: " << root->used << endl; for (unsigned int i = 0; i <= root->used; i++) { inode = (ubixfsInode *)root->head[i]; cout << "root->childCount["<<i<<"]: " << root->childCount[i] << endl; if (root->leaf) { cout << "root contains leaf node" << endl; for (unsigned int j = 0; j < root->childCount[i]; j++) { assert(inode); cout << "[" << i << "].[" << j << "]->" << inode->name << endl; inode = inode->next; } // for j } // if root->leaf } // for i } // bTree::Info void bTree::Print(void) { ubixfsInode * node = GetFirstNode(); while (node != NULL) { cout << node->name << endl; node = node->next; } } // bTree::Print ubixfsInode * bTree::Find(const char * key) { ubixfsInode * tmp = GetFirstNode(); while (tmp!=NULL) { if (strcmp(tmp->name, key) == 0) return tmp; tmp = tmp->next; } return NULL; // return treeSearch(root, key); } // bTree::Find ubixfsInode * bTree::inodeSearch(ubixfsInode * inode, const char * key) { if (inode == NULL || key == NULL) return NULL; int result = strcmp(inode->name, key); if (result == 0) return inode; if (result < 0) { inode = inode->next; while (inode != NULL && ((result = strcmp(inode->name, key)) < 0)) { inode = inode->next; } // while } else { inode = inode->prev; while (inode != NULL && ((result = strcmp(inode->name, key)) > 0)) { inode = inode->prev; } // while } // else return (result == 0 ? inode : NULL); } // bTree::inodeSearch ubixfsInode * bTree::treeSearch(bNode * bnode, const char * key) { if (bnode == NULL || key == NULL || bnode->used == 0) return NULL; if (bnode->leaf) return inodeSearch(GetFirstNode(bnode), key); /* * if (bnode->head[0] != NULL) * return inodeSearch((ubixfsInode *)bnode->head[0], key); * else * return inodeSearch((ubixfsInode *)bnode->head[1], key); */ // cout << "key: " << key << " keys[0]: " << bnode->keys[0] << " result: " << strcmp(key, bnode->keys[0]) << endl; if (strcmp(key, bnode->keys[0]) < 0) return treeSearch((bNode *)bnode->head[0], key); if (strcmp(key, bnode->keys[bnode->used-1]) >= 0) return treeSearch((bNode *)bnode->head[bnode->used], key); for (unsigned int i = 1; i < bnode->used; i++) { if (strcmp(key, bnode->keys[i]) < 0) return treeSearch((bNode *)bnode->head[i], key); } // for i return NULL; } // bTree::treeSearch ubixfsInode * bTree::GetFirstNode(void) { return GetFirstNode(root); } // bTree::GetFirstNode ubixfsInode * bTree::GetFirstNode(bNode * node) { bNode * tmpNode = node; if (tmpNode == NULL) return NULL; while (!tmpNode->leaf) { for (unsigned int i = 0; i < tmpNode->used; i++) { if (tmpNode->head[i] != NULL) { tmpNode = (bNode *)tmpNode->head[i]; break; } // if } // for i } // while for (unsigned int i = 0; i < tmpNode->used; i++) { if (tmpNode->head[i] != NULL) return (ubixfsInode * )tmpNode->head[i]; } // for i return NULL; } // bTree::GetFirstNode bNode * bTree::findLeafNode(bNode * node, const char * key) { assert(node); assert(key); if (node == NULL || key == NULL) return NULL; assert(node->used); if (node->leaf) return node; if (strcmp(key, node->keys[0]) < 0) return findLeafNode((bNode *)node->head[0], key); if (strcmp(key, node->keys[node->used-1]) >= 0) return findLeafNode((bNode *)node->head[node->used], key); for (unsigned int i = 1; i < node->used; i++) { if (strcmp(key, node->keys[i]) < 0) return findLeafNode((bNode *)node->head[i], key); } // for i return NULL; } // bTree::findLeafNode bool bTree::Save(const char * filename) { if (filename == NULL) return false; return true; } // bTree::Save bool bTree::Load(const char * filename) { if (filename == NULL) return false; return true; } // bTree::Load bool bTree::Delete(const char * key) { if (key == NULL) return false; return true; } // bTree::Delete bool bTree::Verify(void) { ubixfsInode * node = GetFirstNode(); if (node == NULL) return true; while (node != NULL) { if (node->next != NULL) { // cout << node->name << "::" << node->next->name << ":::" << strcmp(node->name, node->next->name) << endl; if (strcmp(node->name, node->next->name) > 0) return false; } node = node->next; } // while return true; } // bTree::Verify void bTree::Print(bNode * node) { if (node == NULL) return; Info(node); if (!node->leaf) for (unsigned int i = 0; i <= node->used; i++) { Print((bNode *)node->head[i]); } // for i } // bTree::Print void bTree::PrintWholeTree(void) { Print(root); } // bTree::PrintWholeTree; bTree::~bTree(void) { cout << "tree depth: " << treeDepth << endl; cout << "tree width: " << treeWidth << endl; cout << "tree leaf count: " << treeLeafCount << endl; } // bTree::~bTree