t_rc INXM_IndexHandle::CreateLastDataPage(STORM_PageHandle &pageHandle) { t_rc rc; int pageID; rc = this->sfh.ReservePage(pageHandle); if (rc != OK) { return rc; } rc = pageHandle.GetPageID(pageID); if (rc != OK) { return rc; } char *pageData; rc = pageHandle.GetDataPtr(&pageData); if (rc != OK) { return rc; } /* Write index init page header */ INXM_InitPageHeader pageHeader = { 1, 0 }; memcpy(pageData, &pageHeader, INXM_INITPAGEHEADER_SIZE); /* Update file header (new lastDataPage). */ this->inxmFileHeader.lastDataPage = pageID; memcpy(this->pData_FileHeader, &this->inxmFileHeader, INXM_FILEHEADER_SIZE); rc = this->sfh.FlushPage(this->pageNum_FileHeader); if (rc != OK) { return rc; } return(OK); }
t_rc INXM_IndexHandle::CreateNodePage(STORM_PageHandle &pageHandle, int &pageID, int parent, int next, int previous, bool isLeaf) { t_rc rc; rc = this->sfh.ReservePage(pageHandle); if (rc != OK) { return rc; } rc = pageHandle.GetPageID(pageID); if (rc != OK) { return rc; } char *pageData; rc = pageHandle.GetDataPtr(&pageData); if (rc != OK) { return rc; } /* Write index init page header */ INXM_InitPageHeader pageHeader = { 0, 0 }; memcpy(pageData, &pageHeader, INXM_INITPAGEHEADER_SIZE); /* Write index node page header */ INXM_NodePageHeader nPageHeader = { isLeaf, parent, next, previous }; memcpy(&pageData[INXM_INITPAGEHEADER_SIZE], &nPageHeader, INXM_NODEPAGEHEADER_SIZE); return(OK); }
// Δημιουργία νέου κόμβου/ρίζα t_rc INXM_IndexHandle::makeRoot(void *pData, const REM_RecordID &rid){ t_rc rc; int pageID; STORM_PageHandle myPageHandle; // Δέσμευση σελίδας rc = this->fh.ReservePage(myPageHandle); if (rc != OK) return rc; rc = this->fh.GetNextPage(this->fileHeaderPageID, myPageHandle); if (rc != OK) return rc; rc = myPageHandle.GetPageID(pageID); if (rc != OK) { return rc; } char* rData; rc = myPageHandle.GetDataPtr(&rData); if (rc != OK) { return rc; } this->fileHeader.rootPage = pageID; // Δημιουργία header για τη σελίδα // Κάθε σελίδα είναι και node NodeHeader nh; nh.numberOfItems = 1; for (int i = 0; i < 1200; i++) nh.sStatus.set(i,false); nh.sStatus.set(0, true); nh.left = -1; nh.right = -1; nh.parent = -1; nh.leaf = true; LeafItem item = { pData, rid }; // Εγγραφή του αντικειμένου memcpy(&rData[sizeof(NodeHeader)], this->getLeafItemData(item), this->getLeafItemSize()); this->fileHeader.numberOfNodes++; this->fileHeader.numberOfLeafNodes++; // Εγγραφή του nodeheader memcpy(&rData[0], &nh, sizeof(NodeHeader)); rc = this->fh.MarkPageDirty(pageID); if (rc != OK) return rc; rc = this->fh.FlushPage(pageID); if (rc != OK) return rc; rc = this->fh.UnpinPage(pageID); if (rc != OK) return rc; return(OK); }
//----------------------------------------------------------------------------------------------- // GetFirstPage // // Updates the page handle with the first reserved page of the file. //----------------------------------------------------------------------------------------------- t_rc STORM_FileHandle::GetFirstPage(STORM_PageHandle &pageHandle) { t_rc rc; if (!m_isOpened) return (STORM_FILENOTOPENED); rc = GetNextPage(0, pageHandle); if (rc != OK) return (rc); int curPageID; pageHandle.GetPageID(curPageID); m_filePos = curPageID; return (OK); }
t_rc INXM_IndexHandle::WriteData(STORM_PageHandle pageHandle, const REM_RecordID &rid, int &slot) { t_rc rc; INXM_Data *inxmData = new INXM_Data(); rid.GetPageID(inxmData->pageID); rid.GetSlot(inxmData->slot); char *leafPageData; rc = pageHandle.GetDataPtr(&leafPageData); if (rc != OK) { return rc; } /* Read leaf header. */ INXM_InitPageHeader pageHeader; memcpy(&pageHeader, leafPageData, INXM_INITPAGEHEADER_SIZE); /* Write data to correct place. */ memcpy(&leafPageData[INXM_INITPAGEHEADER_SIZE+pageHeader.nItems*INXM_DATA_SIZE], inxmData, INXM_DATA_SIZE); /* Update page header. */ slot = pageHeader.nItems; pageHeader.nItems++; memcpy(leafPageData, &pageHeader, INXM_INITPAGEHEADER_SIZE); int pageID; rc = pageHandle.GetPageID(pageID); if (rc != OK) { return rc; } /* Mark the page as dirty because we modified it */ rc = this->sfh.MarkPageDirty(pageID); if (rc != OK) { return rc; } rc = this->sfh.FlushPage(pageID); if (rc != OK) { return rc; } /* Unpin the page */ rc = this->sfh.UnpinPage (pageID); if (rc != OK) { return rc; } return(OK); }
t_rc INXM_IndexHandle::WriteNode(STORM_PageHandle pageHandle, int insertPoint, void *key, int left, int slot) { t_rc rc; INXM_Node *node = new INXM_Node(); node->left = left; node->slot = slot; char *nodePageData; rc = pageHandle.GetDataPtr(&nodePageData); if (rc != OK) { return rc; } /* Write data to correct place. */ memcpy(&nodePageData[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+insertPoint*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)], node, INXM_NODE_SIZE); memcpy(&nodePageData[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+insertPoint*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)+INXM_NODE_SIZE], key, this->inxmFileHeader.attrLength); /* Update page header. */ INXM_InitPageHeader pageHeader; rc = LoadInitHeaders(pageHandle, pageHeader); if (rc != OK) { return rc; } pageHeader.nItems++; memcpy(nodePageData, &pageHeader, INXM_INITPAGEHEADER_SIZE); int pageID; rc = pageHandle.GetPageID(pageID); if (rc != OK) { return rc; } /* Mark the page as dirty because we modified it */ rc = this->sfh.MarkPageDirty(pageID); if (rc != OK) { return rc; } rc = this->sfh.FlushPage(pageID); if (rc != OK) { return rc; } /* Unpin the page */ rc = this->sfh.UnpinPage (pageID); if (rc != OK) { return rc; } return(OK); }
t_rc INXM_IndexManager::OpenIndex(const char *fname, int indexNo, INXM_IndexHandle &ih) { /* Close index file handler if it's already open */ if (ih.isOpen) { CloseIndex(ih); } char buffer[128]; snprintf(buffer, sizeof(buffer), "%s.%d", fname, indexNo); /* Open file with STORM and assign a STORM File Handler to INXM Handler given in arguments */ t_rc rc = this->sm->OpenFile(buffer, ih.sfh); if (rc != OK) { return rc; } /* Use the STORM File Handler from INXM Handler given in arguments to get the first page. */ STORM_PageHandle pageHandle; rc = ih.sfh.GetFirstPage(pageHandle); if (rc != OK) { return rc; } /* Get data from first page. Those first data are the INXM File Header. */ rc = pageHandle.GetDataPtr(&ih.pData_FileHeader); if (rc != OK) { return rc; } rc = pageHandle.GetPageID(ih.pageNum_FileHeader); if (rc != OK) { return rc; } /* We keep File Header as a seperated copy inside the INXM Handler. * Using just a pointer in a sequence of dytes would be difficult. */ memcpy(&ih.inxmFileHeader, &ih.pData_FileHeader[0], INXM_FILEHEADER_SIZE); /* Successfully opened a record file handler */ ih.isOpen = true; return(OK); }
// Διαχωρισμός ΕΝΔΙΑΜΕΣΟΥ κόμβου ο οποίος έχει γεμίσει // Χρειάζομαι μόνο το id της σελίδας του κόμβου t_rc INXM_IndexHandle::splitInterNode(int pageToSplitID){ t_rc rc; // Διαβάζω τον Inter Node Header της σελίδας STORM_PageHandle pageHandle; char* data; rc = fh.GetPage(pageToSplitID, pageHandle); if (rc != OK) return rc; rc = pageHandle.GetDataPtr(&data); if (rc != OK) return rc; NodeHeader nh; // o header της σελίδας πρός διάσπαση memcpy(&nh, &data[0], sizeof(NodeHeader)); // Δημιουργία ΝΕΟΥ inter node // Δέσμευση σελίδας this->fh.ReservePage(pageHandle); if (rc != OK) return rc; int newInterPageID; rc = pageHandle.GetPageID(newInterPageID); if (rc != OK) { return rc; } char* newInterData; rc = pageHandle.GetDataPtr(&newInterData); if (rc != OK) { return rc; } // Αρχικοποίηση του νέου inter node header NodeHeader nhNew; nhNew.leaf = false; nhNew.parent = nh.parent; nhNew.right = -1; nhNew.left = -1; for (int i = 0; i < 1200; i++) nhNew.sStatus.set(i,false); // Μετακίνηση των μισών αντικειμένων από τον γεμάτο κόμβο // στον καινούριο for (int i = nh.numberOfItems/2; i < nh.numberOfItems; i++) { memcpy( &newInterData[sizeof(NodeHeader)+(i-nh.numberOfItems/2)*this->getInterItemSize()], &data[sizeof(NodeHeader)+i*this->getInterItemSize()], this->getInterItemSize()); // Μείωση πλήθους αντικειμένων στον έναν κόμβο nh.numberOfItems--; nh.sStatus.set(i, false); // Αύξηση πλήθους αντικειμένων στον άλλο κόμβο nhNew.numberOfItems++; nhNew.sStatus.set(i-nh.numberOfItems/2, true); } // Δημιουργία του ΠΑΤΕΡΑ ενδιάμεσου κόμβου // Δημιουργία του header NodeHeader nhParent; // Διαβάζω το ΠΡΩΤΟ item από το νέο ενδιάμεσο κόμβο που μόλις δημιούργησα char* firstItemData = new char[this->getInterItemSize()]; memcpy(&firstItemData, &newInterData[sizeof(NodeHeader)], this->getInterItemSize()); InterItem firstLeftItem = this->getInterItemStruct(firstItemData); // Δεικτόδοτηση του item που θα μπεί στον κόμβο πατέρα InterItem iItemNew; iItemNew.key = firstLeftItem.key; iItemNew.rightChild = newInterPageID; iItemNew.leftChild = pageToSplitID; if ( nh.parent > 0) { // Περίπτωση που ο προς διάσπαση κόμβος έχει πατέρα, δλδ δεν είναι ρίζα int parentPageID = nh.parent; char* parentData; rc = fh.GetPage(parentPageID, pageHandle); if (rc != OK) return rc; rc = pageHandle.GetDataPtr(&parentData); if (rc != OK) return rc; memcpy(&nhParent, &parentData[0], sizeof(NodeHeader)); if(checkInterNodeForSpace(nhParent)){ // περίπτωση που ο πατέρας έχει χώρο bool posFound = false; InterItem tempItem1 = iItemNew; InterItem tempItem2; int i; // Αντιγραφή του πρώτου item του δεξίου παιδιού // στον πατέρα for (i = 0; i < nhParent.numberOfItems+1; i++) { char* currentData = new char[this->getInterItemSize()]; InterItem currentItem; memcpy(currentData, &parentData[sizeof(NodeHeader)+i*this->getInterItemSize()], this->getInterItemSize()); currentItem = this->getInterItemStruct(currentData); if (keyCompare(iItemNew.key, currentItem.key) < 0 ) posFound = true; // Βρέθηκε η σωστή θέση μετακίνηση όλων των δεξίων item // μία θέση δεξιά if (posFound) { tempItem2 = currentItem; currentItem = tempItem1; tempItem1 = tempItem2; memcpy(&parentData[sizeof(NodeHeader)+i*this->getInterItemSize()],this->getInterItemData(currentItem),this->getInterItemSize()); } } nhParent.numberOfItems++; nhParent.sStatus.set(i-1,true); } else { // περίπτωση που ο πατέρας δεν έχει χώρο // ** // Anadromika splitInterNode(parentPageID); // ** } } else { // Περίπτωση που ο προς διάσπαση κόμβος ΔΕΝ έχει πατέρα, δλδ είναι ρίζα // Δημιουργία inter node // Δέσμευση σελίδας this->fh.ReservePage(pageHandle); if (rc != OK) return rc; int interPageID; rc = pageHandle.GetPageID(interPageID); if (rc != OK) { return rc; } char* interData; rc = pageHandle.GetDataPtr(&interData); if (rc != OK) { return rc; } nh.parent = interPageID; nhNew.parent = interPageID; for (int i = 0; i < 1200; i++) nhParent.sStatus.set(i,false); nhParent.parent = -1; nhParent.leaf = false; nhParent.sStatus.set(0,true); nhParent.numberOfItems++; nhParent.left = -1; nhParent.right = -1; // Εγγραφή του interItem memcpy(&interData[sizeof(NodeHeader)], this->getInterItemData(iItemNew), this->getInterItemSize()); // Ενημέρωση του header memcpy(&interData[0], &nhParent, sizeof(NodeHeader)); rc = this->fh.MarkPageDirty(interPageID); if (rc != OK) return rc; rc = this->fh.FlushPage(interPageID); if (rc != OK) return rc; rc = this->fh.UnpinPage(interPageID); if (rc != OK) return rc; } memcpy(&data[0], &nh, sizeof(NodeHeader)); memcpy(&newInterData[0], &nhNew, sizeof(NodeHeader)); return (OK); }
void testStorm() { STORM_StorageManager mgr; STORM_FileHandle fh; t_rc rc; int nAllocPages, nResPages; STORM_PageHandle ph; char *data; int val; int pid; int nreqs, nreads, nwrites, npinned, nframes; // ====================== STEP 1 =======================================// // Create the file. // Open the file. // Reserve 100 pages. // Store something in each page. // Close the file. //======================================================================// rc = mgr.CreateFile("test.dat"); if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);} rc = mgr.OpenFile("test.dat", fh); if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);} nAllocPages = fh.GetNumAllocatedPages(); nResPages = fh.GetNumReservedPages(); for (int i=1; i<=100; i++) { rc = fh.ReservePage(ph); if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);} // Copy something to the page. rc = ph.GetDataPtr(&data); memcpy(data, &i, sizeof(int)); // Mark the page as dirty. rc = ph.GetPageID(pid); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} rc = fh.MarkPageDirty(pid); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} // Unpin the page rc = fh.UnpinPage(pid); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} } mgr.GetStats(nreqs, nreads, nwrites, npinned, nframes); printf("reqs: %d, reads: %d, writes: %d, pinned: %d, frames: %d\n", nreqs, nreads, nwrites, npinned, nframes); printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages()); rc = mgr.CloseFile(fh); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} Pause(); // ====================== STEP 2 =======================================// // Open the file again. // Read every page of the file and print the page contents. // Release the first 50 pages. // Close the file. //======================================================================// rc = mgr.OpenFile("test.dat", fh); if (rc != OK){DisplayReturnCode(rc); exit(-1);} printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages()); // Display page contents. while (fh.GetNextPage(ph) != STORM_EOF) { rc = ph.GetDataPtr(&data); if (rc != OK) {DisplayReturnCode(rc);exit(-1);} memcpy(&val, data, sizeof(int)); ph.GetPageID(pid); printf("contents of page %d = %d\n", pid, val); // Unpin the page rc = fh.UnpinPage(pid); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} } // Release pages from 1 to 50. for (int p=1; p<=50; p++) { rc = fh.ReleasePage(p); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} } printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages()); rc = mgr.CloseFile(fh); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} Pause(); // ====================== STEP 3 =======================================// // Open the file again. // Read every page of the file and print the page contents. // Close the file. // Finally, destroy the file. // // We expect to see only 50 pages staring from 51 up to 100, since the // first 50 have been released in the previous step. //======================================================================// rc = mgr.OpenFile("test.dat", fh); if (rc != OK){DisplayReturnCode(rc); exit(-1);} // Display page contents. while (fh.GetNextPage(ph) != STORM_EOF) { rc = ph.GetDataPtr(&data); if (rc != OK) {DisplayReturnCode(rc);exit(-1);} memcpy(&val, data, sizeof(int)); ph.GetPageID(pid); printf("contents of page %d = %d\n", pid, val); // Unpin the page fh.UnpinPage(pid); } printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages()); rc = mgr.CloseFile(fh); if (rc != OK) {DisplayReturnCode(rc); exit(-1);} Pause(); rc = mgr.DestroyFile("test.dat"); if (rc != OK) {DisplayReturnCode(rc);exit(-1);} }
t_rc REM_RecordFileHandle::InsertRecord(const char *pData, REM_RecordID &rid) { /* Check is file is open. */ if (!this->isOpen) { return REM_FHCLOSED; } t_rc rc; /* Find an empty page to write the new record. */ STORM_PageHandle targetPage; REM_PageHeader pageHeader = {0}; // The default number of records in a page is 0. char *pageData; /* If there is no free space (lastPageID=-1) then we reserve a new page. */ if (this->remFileHeader.isLastPageFull) { rc = sfh.ReservePage(targetPage); // Reserve the new page. if (rc != OK) { return rc; } /* We mark the last page as not full. */ this->remFileHeader.isLastPageFull = false; /* We update the file header and mark as dirty. */ memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE); rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader); if (rc != OK) { return rc; } /* Get a pointer to the data of the new page to write the new data. */ rc = targetPage.GetDataPtr(&pageData); if (rc != OK) { return rc; } } /* If we have free space in a page, we just get the page. */ else { rc = this->sfh.GetLastPage(targetPage); if (rc != OK) { return rc; } /* Get a pointer to the data of the the page to read the REM Page Header. */ rc = targetPage.GetDataPtr(&pageData); if (rc != OK) { return rc; } memcpy(&pageHeader, pageData, REM_PAGEHEADER_SIZE); } /* We write the data to the proper position. The new record offset must be the page header size + the offset of each record there * is inside the page. We always place the new record at the end of the page. */ memcpy(&pageData[REM_PAGEHEADER_SIZE+(pageHeader.nRecords*this->remFileHeader.recordSize)], pData, this->remFileHeader.recordSize); /* Increase the number of records in the page header. This number is also the slot number of the record. */ int slotNum = ++pageHeader.nRecords; /* Declare page number, which is the pageID we are currently working on. */ int pageNum; rc = targetPage.GetPageID(pageNum); if (rc != OK) { return rc; } /* Check if page is full. */ if (pageHeader.nRecords == this->remFileHeader.recordsPerPage) { this->remFileHeader.isLastPageFull = true; /* We update the file header and mark as dirty. */ memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE); rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader); if (rc != OK) { return rc; } /* Get a pointer to the data of the new page to write the new data. */ rc = targetPage.GetDataPtr(&pageData); if (rc != OK) { return rc; } } /* Write the new REM Page Header. */ memcpy(pageData, &pageHeader, REM_PAGEHEADER_SIZE); /* Mark the page as dirty because we modified it */ rc = this->sfh.MarkPageDirty(pageNum); if (rc != OK) { return rc; } this->sfh.FlushPage(pageNum); // We should reconsider when we are flushing pages!!! /* Unpin the page */ rc = this->sfh.UnpinPage (pageNum); if (rc != OK) { return rc; } /* Set the passed RID's page number and slot number */ rc = rid.SetPageID(pageNum); if (rc != OK) { return rc; } rc = rid.SetSlot(slotNum); if (rc != OK) { return rc; } /* Successfuly inserted record */ return (OK); }
t_rc REM_RecordFileHandle::DeleteRecord(const REM_RecordID &rid) { /* Check is file is open. */ if (!this->isOpen) { return REM_FHCLOSED; } t_rc rc; /* Read page and slot we want to delete. */ int pageID, slot; rc = rid.GetPageID(pageID); if (rc != OK) { return rc; } rc = rid.GetSlot(slot); if (rc != OK) { return rc; } /* Get wanted page. */ STORM_PageHandle wantedPageHandle; rc = this->sfh.GetPage(pageID, wantedPageHandle); if (rc != OK) { return rc; } /* Get the wanted page header. */ char *wantedData; REM_PageHeader wantedPageHeader; rc = wantedPageHandle.GetDataPtr(&wantedData); if (rc != OK) { return rc; } memcpy(&wantedPageHeader, wantedData, REM_PAGEHEADER_SIZE); if (slot > wantedPageHeader.nRecords) { return REM_INVALIDRID; } STORM_PageHandle lastPageHandle; int lastPageID; rc = this->sfh.GetLastPage(lastPageHandle); if (rc != OK) { return rc; } rc = lastPageHandle.GetPageID(lastPageID); if (rc != OK) { return rc; } /* Determine if we need to retrive an other page to replace the record. */ if (lastPageID == pageID) { /* Determine if our record is the last. */ if (wantedPageHeader.nRecords == slot) { /* Check if we need to release the page. */ if (wantedPageHeader.nRecords == 1) { rc = this->sfh.ReleasePage(pageID); if (rc != OK) { return rc; } /* We must change the lastPageID in REM File Header. */ this->remFileHeader.isLastPageFull = true; /* Copy new file header at memory */ memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE); /* Mark REM File Header frame as dirty */ rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader); if (rc != OK) { return rc; } } else { /* If our record is the last one in the row but more data exist, we just decrease the number of records the page has. */ wantedPageHeader.nRecords--; /* Copy header back. */ memcpy(wantedData, &wantedPageHeader, REM_PAGEHEADER_SIZE); } } else { /* Copy the last record of this page (last page) in the position of the record we want to erase. */ memcpy(&wantedData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)], &wantedData[REM_PAGEHEADER_SIZE+((wantedPageHeader.nRecords-1)*this->remFileHeader.recordSize)], this->remFileHeader.recordSize); /* Decrease the number of records the pages has. */ wantedPageHeader.nRecords--; /* Copy header back. */ memcpy(wantedData, &wantedPageHeader, REM_PAGEHEADER_SIZE); } } else { /* Get last record from last page to replace the asked record. */ char *lastData; rc = lastPageHandle.GetDataPtr(&lastData); if (rc != OK) { return rc; } /* Get last's page header. */ REM_PageHeader lastPageHeader; memcpy(&lastPageHeader, lastData, REM_PAGEHEADER_SIZE); /* Copy the data between the two pages */ memcpy(&wantedData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)], &lastData[REM_PAGEHEADER_SIZE+((lastPageHeader.nRecords-1)*this->remFileHeader.recordSize)], this->remFileHeader.recordSize); /* Check if last page has no more records. */ if (lastPageHeader.nRecords == 1) { /* If we copied the last record we can safely release the last page. */ rc = this->sfh.ReleasePage(lastPageID); if (rc != OK) { return rc; } /* We must change the lastPageID in REM File Header. */ this->remFileHeader.isLastPageFull = true; /* Copy new file header at memory */ memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE); /* Mark REM File Header frame as dirty */ rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader); if (rc != OK) { return rc; } } else { /* Decrease last page record number in its page header. */ lastPageHeader.nRecords--; memcpy(lastData, &lastPageHeader, REM_PAGEHEADER_SIZE); /* Mark last page as dirty due to last record removal. */ rc = sfh.MarkPageDirty(lastPageID); if (rc != OK) { return rc; } /* Unpin last page. */ rc = sfh.UnpinPage (lastPageID); if (rc != OK) { return rc; } } } /* Mark the page as dirty because we modified it */ rc = sfh.MarkPageDirty(pageID); if (rc != OK) { return rc; } /* Unpin the page */ rc = sfh.UnpinPage (pageID); if (rc != OK) { return rc; } sfh.FlushPage(pageID); /* Record successfully deleted */ return (OK); }
t_rc INXM_IndexHandle::InsertIntoLeafAfterSplitting(int rootID, STORM_PageHandle leafPageHandle, void *key, const REM_RecordID &rid) { t_rc rc; STORM_PageHandle newLeafPageHandle; int newLeafPageID; rc = CreateNodePage(newLeafPageHandle, newLeafPageID, 0, 0, 0, true); if (rc != OK) { return rc; } /* Read leaf page headers. */ INXM_InitPageHeader leafPageHeader; rc = LoadInitHeaders(leafPageHandle, leafPageHeader); if (rc != OK) { return rc; } int insertPoint = 0; INXM_Node node; ReadNode(leafPageHandle, insertPoint, node); while (insertPoint < leafPageHeader.nItems && KeyCmp(node.key, key) < 0) { ReadNode(leafPageHandle, insertPoint, node); insertPoint++; } INXM_Node **temp_nodes = (INXM_Node **)malloc(INXM_NODE_SIZE*leafPageHeader.nItems); int i,j; for (i=0, j=0; i < leafPageHeader.nItems; i++, j++) { if (j == insertPoint) j++; ReadNode(leafPageHandle, i, *(temp_nodes[j])); } /* Write new data to last page. */ int newDataSlot; STORM_PageHandle lastDataPageHandle; rc = this->sfh.GetPage(this->inxmFileHeader.lastDataPage, lastDataPageHandle); if (rc != OK) { return rc; } rc = WriteData(lastDataPageHandle, rid, newDataSlot); if (rc != OK) { return rc; } /* Place new node to temp array. */ INXM_Node *newNode = new INXM_Node(); newNode->key = key; newNode->left = this->inxmFileHeader.lastDataPage; newNode->slot = newDataSlot; temp_nodes[insertPoint] = newNode; /* Reset leaf's nItems */ char *tmpData; leafPageHandle.GetDataPtr(&tmpData); leafPageHeader.nItems = 0; memcpy(tmpData, &leafPageHeader, INXM_INITPAGEHEADER_SIZE); int maxNodeRoom = (PAGE_DATA_SIZE-INXM_INITPAGEHEADER_SIZE-INXM_NODEPAGEHEADER_SIZE)/(INXM_NODE_SIZE+this->inxmFileHeader.attrLength); int split = Cut(maxNodeRoom); /* Write new data. */ for (i = 0; i < split; i++) { WriteNode(leafPageHandle, i, temp_nodes[i]->key, temp_nodes[i]->left, temp_nodes[i]->slot); } for (i = split, j = 0; i < maxNodeRoom; i++, j++) { WriteNode(newLeafPageHandle, j, temp_nodes[i]->key, temp_nodes[i]->left, temp_nodes[i]->slot); } free(temp_nodes); // This is not enough! INXM_NodePageHeader leafNodePageHeader; LoadNodeHeaders(leafPageHandle, leafPageHeader, leafNodePageHeader); INXM_NodePageHeader newLeafNodePageHeader; INXM_InitPageHeader newLeafPageHeader; rc = LoadNodeHeaders(newLeafPageHandle, newLeafPageHeader, newLeafNodePageHeader); if (rc != OK) { return rc; } int leafPageID; rc = leafPageHandle.GetPageID(leafPageID); if (rc != OK) { return rc; } newLeafNodePageHeader.next = leafNodePageHeader.next; newLeafNodePageHeader.previous = leafPageID; leafNodePageHeader.next = newLeafPageID; if (newLeafNodePageHeader.next != 0) { STORM_PageHandle nextLeafPageHandle; rc = this->sfh.GetPage(newLeafNodePageHeader.next, nextLeafPageHandle); if (rc != OK) { return rc; } INXM_InitPageHeader nextInitPageHeader; INXM_NodePageHeader nextNodePageHeader; LoadNodeHeaders(nextLeafPageHandle, nextInitPageHeader, nextNodePageHeader); nextNodePageHeader.previous = newLeafPageID; UpdateNodeHeaders(nextLeafPageHandle, nextInitPageHeader, nextNodePageHeader); } rc = UpdateNodeHeaders(leafPageHandle, leafPageHeader, leafNodePageHeader); if (rc != OK) { return rc; } rc = UpdateNodeHeaders(newLeafPageHandle, newLeafPageHeader, newLeafNodePageHeader); if (rc != OK) { return rc; } INXM_Node keyNode; rc = ReadNode(newLeafPageHandle, 0, keyNode); if (rc != OK) { return rc; } rc = InsertIntoParent(this->inxmFileHeader.treeRoot, leafPageHandle, keyNode, newLeafPageHandle); if (rc != OK) { return rc; } return(OK); }
t_rc INXM_IndexHandle::InsertIntoParent(int rootID, STORM_PageHandle leftPage, INXM_Node &keyNode, STORM_PageHandle rightPage) { t_rc rc; INXM_InitPageHeader leftInitPageHeader; INXM_NodePageHeader leftNodePageHeader; LoadNodeHeaders(leftPage, leftInitPageHeader, leftNodePageHeader); /* Case: new root. */ if (leftNodePageHeader.parent == 0) { int rightPageID; rc = rightPage.GetPageID(rightPageID); if (rc != OK) { return rc; } STORM_PageHandle newRootPageHandle; CreateNodePage(newRootPageHandle, this->inxmFileHeader.treeRoot, 0, rightPageID, 0, 0); int leftPageID; rc = leftPage.GetPageID(leftPageID); if (rc != OK) { return rc; } rc = WriteNode(newRootPageHandle, keyNode.key, leftPageID, 0); if (rc != OK) { return rc; } /* Update inxm file header. */ memcpy(this->pData_FileHeader, &this->inxmFileHeader, INXM_FILEHEADER_SIZE); rc = this->sfh.FlushPage(this->pageNum_FileHeader); if (rc != OK) { return rc; } /* Write all. */ rc = this->sfh.FlushAllPages(); if (rc != OK) { return rc; } return(OK); } /* Case: leaf or node. (Remainder of * function body.) */ /* Find the parent's node index to the left * page. */ int leftPageID; rc = leftPage.GetPageID(leftPageID); if (rc != OK) { return rc; } int rightPageID; rc = rightPage.GetPageID(rightPageID); if (rc != OK) { return rc; } int left_index = 0; INXM_Node node; INXM_InitPageHeader parentInitPageHeader; INXM_NodePageHeader parentNodePageHeader; LoadNodeHeaders(leftNodePageHeader.parent, parentInitPageHeader, parentNodePageHeader); while (left_index < parentInitPageHeader.nItems) { ReadNode(leftNodePageHeader.parent, left_index, node); if (node.left == leftPageID) { break; } left_index++; } /* Simple case: the new key fits into the page. */ STORM_PageHandle parentPageHandle; rc = this->sfh.GetPage(leftNodePageHeader.parent, parentPageHandle); if (rc != OK) { return rc; } if (LeafHasRoom(parentPageHandle)) { return InsertIntoNoLeaf(parentPageHandle, left_index, keyNode.key, rightPageID); } /* Harder case: split a not leaf page, in order * to preserve the B+ tree properties. */ // return insert_into_node_after_splitting(root, parent, left_index, key, right); return(OK); }
t_rc INXM_IndexManager::CreateIndex(const char *fname, int indexNo, t_attrType attrType, int attrLength) { // We need to find the number of records that fit in a page. int recordsPerPage = (PAGE_SIZE - INXM_INITPAGEHEADER_SIZE + INXM_NODEPAGEHEADER_SIZE)/(INXM_NODE_SIZE + attrLength); // We need only the integer part or we can "floor" the number. if (recordsPerPage < 1) { return (INXM_INVALIDRECSIZE); } char buffer[128]; snprintf(buffer, sizeof(buffer), "%s.%d", fname, indexNo); /* Create file by using STORM */ t_rc rc = this->sm->CreateFile(buffer); if (rc != OK) { return rc; } /* Open the created file */ STORM_FileHandle stormFileHandle; rc = this->sm->OpenFile(buffer, stormFileHandle); if (rc != OK) { return rc; } /* Allocate a new page for the INXM file header page. */ STORM_PageHandle stormPageHandle; rc = stormFileHandle.ReservePage(stormPageHandle); if (rc != OK) { return rc; } /* Get pointer to the contents (data) of the INXM file header page */ char *pData; int pageID; rc = stormPageHandle.GetDataPtr(&pData); if (rc != OK) { return rc; } /* Get the page number of the INXM file header page */ rc = stormPageHandle.GetPageID(pageID); if (rc != OK) { return rc; } /* Construct INXM File Header */ INXM_FileHeader fileHeader = { attrType, attrLength, 0, 0 }; /* Copy the INXM File Header to the first page */ memcpy(pData, &fileHeader, INXM_FILEHEADER_SIZE); /* Because we modified the INXM file header page, we write it to disk */ rc = stormFileHandle.MarkPageDirty(pageID); if (rc != OK) { return rc; } rc = stormFileHandle.FlushPage(pageID); if (rc != OK) { return rc; } /* We now unpin the header page because we are done modifying it. (We really need this?) */ rc = stormFileHandle.UnpinPage(pageID); if (rc != OK) { return rc; } /* We now close the file because we are done modifying it. (We really need this too?) */ rc = this->sm->CloseFile(stormFileHandle); if (rc != OK) { return rc; } return(OK); }