bool SPSegment::update(TID tid, const Record& r){ Record r_old = this->lookup(tid); unsigned len_old = r_old.getLen(); unsigned len_new = r.getLen(); BufferFrame frame = bm->fixPage(tid.getPage(), true); SlottedPage* page = reinterpret_cast<SlottedPage*>(frame.getData()); if(len_old == len_new){ // If size doesn't change, use memcpy memcpy(page->getSlot(tid.getSlot())->getRecord(), &r, r.getLen()); } else if(len_old > len_new){ // Record has become smaller memcpy(page->getSlot(tid.getSlot())->getRecord(), &r, r.getLen()); // TODO Update freeSpace of page // TODO update FSI } else { // Record has become larger unsigned freeSpaceOnPage = page->remove(tid.getSlot()); this->fsi[tid.getPage()] = freeSpaceOnPage; if (freeSpaceOnPage >= len_new) { // It fits on the page after removal page->insert(r); } else { // Even after removal it is too large // Get another page uint64_t sndPageId = this->lastPage + 1; for (auto it = this->fsi.rbegin(); it != this->fsi.rend(); it++) { if (it->second >= r.getLen()) { sndPageId = it->first; break; } } BufferFrame sndFrame = bm->fixPage(sndPageId, true); // Create a new SlottedPage if necessary SlottedPage* sndPage = reinterpret_cast<SlottedPage*>(sndFrame.getData()); if (sndPageId > this->lastPage) { *sndPage = SlottedPage(); this->lastPage++; if (lastPage > 1l << 48) throw "Max page number reached."; } Slot* fstSlot = page->getSlot(tid.getSlot()); assert(fstSlot->isEmpty()); // Insert into new page unsigned sndSlotNum = sndPage->insert(r); this->fsi[sndPageId] -= r.getLen() + (sndSlotNum == sndPage->getMaxSlot() ? sizeof(Slot) : 0); // Update first slot to directo to second page. *fstSlot = Slot(TID(sndPageId, sndSlotNum)); bm->unfixPage(sndFrame, true); } } bm->unfixPage(frame, true); return true; }
Leaf<KeyType, KeyComparator> &BTree<KeyType, KeyComparator>::getLeaf(KeyType key) { BufferFrame *frame = findFrameForKey(key, false); Leaf<KeyType, KeyComparator> *leaf = reinterpret_cast<Leaf<KeyType, KeyComparator> *>(frame->getData()); bufferManager.unfixPage(*frame, false); return *leaf; }
bool BTree<K, Comp>::insert(K key, uint64_t tid) { //latch the root BufferFrame* curFrame = &bufferManager.fixPage(rootPID, true); Node<K, Comp>* curNode = reinterpret_cast<Node<K, Comp>*>(curFrame->getData()); BufferFrame* parFrame = NULL; while (!curNode->isLeaf()) { if (curNode->count >= maxNodeSize) { // --> split to safe inner pages if (parFrame == NULL) { //Need to create a new root (parent) first parFrame = createNewRoot(); } BufferFrame* newFrame = &bufferManager.fixPage(nextFreePage++, true); K splitKey = curNode->split(curFrame->pageId, newFrame, parFrame, smaller); //determine correct node and release the other one if (smaller(key, splitKey)) { bufferManager.unfixPage(*newFrame, true); } else { curNode = reinterpret_cast<Node<K, Comp>*>(newFrame->getData()); bufferManager.unfixPage(*curFrame, true); curFrame = newFrame; } } //release the parent node if (parFrame != NULL) { bufferManager.unfixPage(*parFrame, true); //TODO only set true when parent is really dirty? } parFrame = curFrame; //latch the next level uint64_t pos = curNode->findKeyPos(key, smaller); uint64_t nextPID = (pos == curNode->count) ? curNode->next : curNode->keyValuePairs[pos].second; curFrame = &bufferManager.fixPage(nextPID, true); curNode = reinterpret_cast<Node<K, Comp>*>(curFrame->getData()); } Node<K, Comp>* leaf = reinterpret_cast<Node<K, Comp>*>(curNode); if (leaf->count >= maxNodeSize) { if (parFrame == NULL) { parFrame = createNewRoot(); } BufferFrame* newFrame = &bufferManager.fixPage(nextFreePage++, true); K splitKey = leaf->split(curFrame->pageId, newFrame, parFrame, smaller); if (smaller(key, splitKey)) { bufferManager.unfixPage(*newFrame, true); } else { leaf = reinterpret_cast<Node<K, Comp>*>(newFrame->getData()); bufferManager.unfixPage(*curFrame, true); curFrame = newFrame; } } if (parFrame != NULL) { bufferManager.unfixPage(*parFrame, true); //TODO: only mark dirty when parent was actually updated } bool insertSuccessful = leaf->insertKey(key, tid, smaller); if (insertSuccessful) { elements++; } bufferManager.unfixPage(*curFrame, true); return insertSuccessful; }