void sync(RM_FileHandle* rmfh) { if(!rmfh->modified) return; PF_PageHandle pageHandle; initPF_PageHandle(&pageHandle); char* pData; rmfh->pf_FileHandle->GetFirstPage(rmfh->pf_FileHandle,&pageHandle); pageHandle.GetData(&pageHandle, &pData); *(PageNum*)pData = rmfh->firstFree; rmfh->pf_FileHandle->MarkDirty(rmfh->pf_FileHandle, pageHandle.pagenum); rmfh->pf_FileHandle->ForcePages(rmfh->pf_FileHandle, pageHandle.pagenum); }
RC IX_IndexHandle::DeleteEntry(void *attr, const RID &rid) { RC rc; if (!_opened) return IX_INVALIDINDEXHANDLE; PF_PageHandle thisPage; if ((rc = IX_LocateAttr(*this, (char *) attr, thisPage))) return rc; char *thisData; if ((rc = thisPage.GetData(thisData))) return rc; IX_PageHeader *thisHeader = reinterpret_cast<IX_PageHeader *>(thisData); if (thisHeader->numKeys == 0) return IX_EMPTYNODE; char *thisKey = NULL; for (unsigned i = 0; i < thisHeader->numKeys; i++) { thisKey = IX_GetLeafKey(thisData, _attrLength, i); RID thisRid = IX_GetLeafRID(thisKey); if (thisRid == rid) { IX_SetLeafDeleted(thisKey, true); PageNum thisPageNum; if ((rc = thisPage.GetPageNum(thisPageNum))) return rc; if ((rc = _fileHandle.MarkDirty(thisPageNum))) return rc; break; } } PageNum thisPageNum; if ((rc = thisPage.GetPageNum(thisPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; return 0; }
RC IX_IndexHandle::UpdateKey(PageNum leafParentPageNum, char *attr) { RC rc; PageNum thisPageNum = leafParentPageNum; PF_PageHandle thisPage; if ((rc = _fileHandle.GetThisPage(thisPageNum, thisPage))) return rc; char *thisData; if ((rc = thisPage.GetData(thisData))) return rc; IX_PageHeader *thisHeader = (IX_PageHeader *)thisData; char *firstKey = IX_GetInternalKey(thisData, _attrLength, 0); if (!IX_AttrEQ(IX_GetInternalAttr(firstKey), attr, _attrType, _attrLength)) { if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; return 0; } memcpy(IX_GetInternalAttr(firstKey), attr, _attrLength); PageNum parentPageNum = thisHeader->parent; if (parentPageNum == 0) { if ((rc = _fileHandle.MarkDirty(thisPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; return 0; } if ((rc = _fileHandle.MarkDirty(thisPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; return UpdateKey(parentPageNum, attr); }
RC IX_IndexHandle::PrintTree(PageNum thisPageNum) { RC rc; PF_PageHandle thisPage; if ((rc = _fileHandle.GetThisPage(thisPageNum, thisPage))) return rc; char *thisData; if ((rc = thisPage.GetData(thisData))) return rc; IX_PageHeader *thisHeader = (IX_PageHeader *)thisData; printf("Page %d (Parent %d): [", thisPageNum, thisHeader->parent); vector<PageNum> childs; if (thisHeader->flag & IXF_LEAF) { for (int i = 0; i < thisHeader->numKeys; i++) { char *pKey = IX_GetLeafKey(thisData, _attrLength, i); printf("%d%s ", *(int *)IX_GetLeafAttr(pKey), IX_IsLeafDeleted(pKey)?"(DEL)":""); } } else { for (int i = 0; i < thisHeader->numKeys; i++) { char *pKey = IX_GetInternalKey(thisData, _attrLength, i); printf("(%d->%d) ", *(int *)IX_GetInternalAttr(pKey), IX_GetInternalChild(pKey)); childs.push_back(IX_GetInternalChild(pKey)); } } printf("]\n"); if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; for (int i = 0; i < childs.size(); i++) { if ((rc = PrintTree(childs[i]))) return rc; } return 0; }
RC IX_IndexHandle::SolveUpperOverflow(PageNum thisPageNum) { RC rc; PF_PageHandle thisPage; if ((rc = _fileHandle.GetThisPage(thisPageNum, thisPage))) return rc; char *thisData; if ((rc = thisPage.GetData(thisData))) return rc; IX_PageHeader *thisHeader = reinterpret_cast<IX_PageHeader *>(thisData); // 递归终止条件:不满足分裂条件。 if (thisHeader->flag & IXF_LEAF) { if (thisHeader->numKeys < IX_MaxLeafKeys(_attrLength)) return 0; } else { if (thisHeader->numKeys < IX_MaxInternalKeys(_attrLength)) return 0; } // 分配新页 PF_PageHandle anotherPage; if ((rc = _fileHandle.AllocatePage(anotherPage))) return rc; char *anotherData; if ((rc = anotherPage.GetData(anotherData))) return rc; IX_PageHeader *anotherHeader = reinterpret_cast<IX_PageHeader *>(anotherData); PageNum anotherPageNum; if ((rc = anotherPage.GetPageNum(anotherPageNum))) return rc; if (thisHeader->flag & IXF_LEAF) { // Leaf page. unsigned anotherStart = thisHeader->numKeys / 2; anotherHeader->numKeys = thisHeader->numKeys - anotherStart; anotherHeader->flag = IXF_LEAF; anotherHeader->parent = thisHeader->parent; // Move half of the keys to another page. for (unsigned i = anotherStart; i < thisHeader->numKeys; i++) { char *thisKey = IX_GetLeafKey(thisData, _attrLength, i); char *anotherKey = IX_GetLeafKey(anotherData, _attrLength, i - anotherStart); memcpy(anotherKey, thisKey, sizeof(RID) + sizeof(int) + _attrLength); } thisHeader->numKeys = anotherStart; PageNum nextPageNum = thisHeader->next; if (nextPageNum != 0) { PF_PageHandle nextPage; if ((rc = _fileHandle.GetThisPage(nextPageNum, nextPage))) return rc; char *nextData; if ((rc = nextPage.GetData(nextData))) return rc; IX_PageHeader *nextHeader = reinterpret_cast<IX_PageHeader *>(nextData); nextHeader->prev = anotherPageNum; if ((rc = _fileHandle.MarkDirty(nextPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(nextPageNum))) return rc; } anotherHeader->next = nextPageNum; anotherHeader->prev = thisPageNum; thisHeader->next = anotherPageNum; } else { // Internal page. unsigned anotherStart = thisHeader->numKeys / 2; anotherHeader->numKeys = thisHeader->numKeys - anotherStart; anotherHeader->flag = 0; anotherHeader->parent = thisHeader->parent; anotherHeader->next = anotherHeader->prev = 0; for (unsigned i = anotherStart; i < thisHeader->numKeys; i++) { char *thisKey = IX_GetInternalKey(thisData, _attrLength, i); char *anotherKey = IX_GetInternalKey(anotherData, _attrLength, i - anotherStart); memcpy(anotherKey, thisKey, sizeof(PageNum) + _attrLength); // 修改该Child的父亲指针 PageNum childPageNum = IX_GetInternalChild(anotherKey); PF_PageHandle childPage; if ((rc = _fileHandle.GetThisPage(childPageNum, childPage))) return rc; char *childData; if ((rc = childPage.GetData(childData))) return rc; IX_PageHeader *childHeader = (IX_PageHeader *)childData; childHeader->parent = anotherPageNum; if ((rc = _fileHandle.MarkDirty(childPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(childPageNum))) return rc; } thisHeader->numKeys = anotherStart; } // 如果thisPage是根节点,就要首先创建一个新的空的根节点,并将指向thisPage的指针放进去 if (thisHeader->flag & IXF_ROOT) { PF_PageHandle rootPage; if ((rc = _fileHandle.AllocatePage(rootPage))) return rc; char *rootData; if ((rc = rootPage.GetData(rootData))) return rc; IX_PageHeader *rootHeader = reinterpret_cast<IX_PageHeader *>(rootData); rootHeader->flag = IXF_ROOT; rootHeader->numKeys = 1; rootHeader->parent = rootHeader->next = rootHeader->prev = 0; char *thisFirstAttr; if (thisHeader->flag & IXF_LEAF) thisFirstAttr = IX_GetLeafAttr(IX_GetLeafKey(thisData, _attrLength, 0)); else thisFirstAttr = IX_GetInternalAttr(IX_GetInternalKey(thisData, _attrLength, 0)); char *rootFirstKey = IX_GetInternalKey(rootData, _attrLength, 0); IX_SetInternalChild(rootFirstKey, thisPageNum); memcpy(IX_GetInternalAttr(rootFirstKey), thisFirstAttr, _attrLength); if ((rc = rootPage.GetPageNum(_rootNum))) return rc; if ((rc = _fileHandle.MarkDirty(_rootNum))) return rc; if ((rc = _fileHandle.UnpinPage(_rootNum))) return rc; thisHeader->parent = _rootNum; thisHeader->flag &= ~IXF_ROOT; anotherHeader->parent = _rootNum; // 记得要修改INDEX的头部信息块 PF_PageHandle fileHeaderPage; if ((rc = _fileHandle.GetFirstPage(fileHeaderPage))) return rc; char *fileHeaderData; if ((rc = fileHeaderPage.GetData(fileHeaderData))) return rc; IX_FileHeader *fileHeader = reinterpret_cast<IX_FileHeader *>(fileHeaderData); fileHeader->rootNum = _rootNum; PageNum fileHeaderNum; if ((rc = fileHeaderPage.GetPageNum(fileHeaderNum))) return rc; if ((rc = _fileHandle.MarkDirty(fileHeaderNum))) return rc; if ((rc = _fileHandle.UnpinPage(fileHeaderNum))) return rc; } // 在父节点中插入一个新的key,key值为anotherPage的最小值。 static int magicint = 0; PF_PageHandle parentPage; if ((rc = _fileHandle.GetThisPage(thisHeader->parent, parentPage))) return rc; char *parentData; if ((rc = parentPage.GetData(parentData))) return rc; IX_PageHeader *parentHeader = reinterpret_cast<IX_PageHeader *>(parentData); char *anotherFirstAttr = IX_GetInternalAttr(IX_GetInternalKey(anotherData, _attrLength, 0)); unsigned iKey; for (iKey = 0; iKey < parentHeader->numKeys; iKey++) { char *pKey = IX_GetInternalKey(parentData, _attrLength, iKey); if (IX_GetInternalChild(pKey) == thisPageNum) break; } // 将iKey+1与其之后的key都向后移动一位,在空出的位置iKey+1上填入新的key for (unsigned temp = parentHeader->numKeys; temp > iKey+1; temp--) { char *keyNext = IX_GetInternalKey(parentData, _attrLength, temp); char *keyPrev = IX_GetInternalKey(parentData, _attrLength, temp-1); memcpy(IX_GetInternalAttr(keyNext), IX_GetInternalAttr(keyPrev), _attrLength); IX_SetInternalChild(keyNext, IX_GetInternalChild(keyPrev)); } parentHeader->numKeys++; char *pKey = IX_GetInternalKey(parentData, _attrLength, iKey+1); memcpy(IX_GetInternalAttr(pKey), anotherFirstAttr, _attrLength); IX_SetInternalChild(pKey, anotherPageNum); PageNum parentPageNum; if ((rc = parentPage.GetPageNum(parentPageNum))) return rc; if ((rc = _fileHandle.MarkDirty(parentPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(parentPageNum))) return rc; if ((rc = _fileHandle.MarkDirty(thisPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; if ((rc = _fileHandle.MarkDirty(anotherPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(anotherPageNum))) return rc; return SolveUpperOverflow(parentPageNum); }
RC IX_IndexHandle::InsertEntry(void *attr, const RID &rid) { RC rc; if (!_opened) return IX_INVALIDINDEXHANDLE; PF_PageHandle thisPage; if ((rc =_fileHandle.GetThisPage(_rootNum, thisPage))) return rc; char *pData; if ((rc = thisPage.GetData(pData))) return rc; IX_PageHeader *thisHeader = reinterpret_cast<IX_PageHeader *>(pData); if (thisHeader->numKeys == 0) { // 插入第一个元素的特殊情况 thisHeader->numKeys = 1; char *pKey = IX_GetLeafKey(pData, _attrLength, 0); IX_SetLeafRID(pKey, rid); char *thisAttr = IX_GetLeafAttr(pKey); memcpy(thisAttr, attr, _attrLength); if ((rc = _fileHandle.MarkDirty(_rootNum))) return rc; if ((rc = _fileHandle.UnpinPage(_rootNum))) return rc; return 0; } if ((rc = _fileHandle.UnpinPage(_rootNum))) return rc; if ((rc = IX_LocateAttr(*this, (char *)attr, thisPage))) return rc; if ((rc = thisPage.GetData(pData))) return rc; thisHeader = reinterpret_cast<IX_PageHeader *>(pData); unsigned iKey; for (iKey = 0; iKey < thisHeader->numKeys; iKey++) { char *pThisKey = IX_GetLeafKey(pData, _attrLength, iKey); if (IX_AttrEQ(IX_GetLeafAttr(pThisKey), (char *)attr, _attrType, _attrLength)) { if (IX_IsLeafDeleted(pThisKey)) break; else return IX_DUPLICATEENTRY; } if (IX_AttrGT(IX_GetLeafAttr(pThisKey), (char *)attr, _attrType, _attrLength)) break; } bool isDeleted = false; char *pThisKey = IX_GetLeafKey(pData, _attrLength, iKey); if (IX_IsLeafDeleted(pThisKey)) { // 不需要移动位置,直接替换前已经被标记为删除的。 isDeleted = true; } else { // 现在iKey指向应该插入新索引的位置,要首先将后面的索引向后移动一个位置, // 空出当前位置,将新索引放在这里。 for (unsigned temp = thisHeader->numKeys; temp > iKey; temp--) { char *pThisKey = IX_GetLeafKey(pData, _attrLength, temp); char *pPrevKey = IX_GetLeafKey(pData, _attrLength, temp-1); RID tempRid = IX_GetLeafRID(pPrevKey); IX_SetLeafRID(pThisKey, tempRid); memcpy(IX_GetLeafAttr(pThisKey), IX_GetLeafAttr(pPrevKey), _attrLength); } thisHeader->numKeys++; } pThisKey = IX_GetLeafKey(pData, _attrLength, iKey); IX_SetLeafRID(pThisKey, rid); IX_SetLeafDeleted(pThisKey, false); memcpy(IX_GetLeafAttr(pThisKey), attr, _attrLength); PageNum thisParentPageNum = thisHeader->parent; PageNum thisPageNum; if ((rc = thisPage.GetPageNum(thisPageNum))) return rc; if ((rc = _fileHandle.MarkDirty(thisPageNum))) return rc; if ((rc = _fileHandle.UnpinPage(thisPageNum))) return rc; // 如果更新的为最左键,则需要向上更新键值 if (iKey == 0 && thisParentPageNum != 0) UpdateKey(thisParentPageNum, (char *)attr); // 开始从该节点逐层向上检查是否溢出 rc = SolveUpperOverflow(thisPageNum); // PrintTree(_rootNum); return rc; }
RC RM_Manager::CreateFile (const char *fileName, int recordSize) { /* Determine the number of records that can be stored in a single * page. If this number is less than 1, return an error. */ int recordsPerPage; double x = (double)(PF_PAGE_SIZE - RM_PAGESUBHDR_SIZE) - 1.0; double y = (double)recordSize + 0.125; recordsPerPage = (int)(x/y); if (recordsPerPage < 1) { return RM_INVALIDRECSIZE; } if (DEBUG) { printf ("recordsPerPage = %d\n", recordsPerPage); } RC rc; /* Create file by using the paged file manager */ rc = pfm.CreateFile (fileName); if (rc != SUCCESS) { return rc; } PF_FileHandle pfFileHandle; /* Open the created file */ rc = pfm.OpenFile (fileName, pfFileHandle); if (rc != SUCCESS) { return rc; } PF_PageHandle pfPageHandle; /* Allocate a new page for the RM header page */ rc = pfFileHandle.AllocatePage (pfPageHandle); if (rc != SUCCESS) { return rc; } char *pData; PageNum pageNum; /* Get ptr to the contents (data) of the RM header page */ rc = pfPageHandle.GetData (pData); if (rc != SUCCESS) { return rc; } /* Get the page number of the RM header page */ rc = pfPageHandle.GetPageNum (pageNum); if (rc != SUCCESS) { return rc; } /* Construct the sub-header */ RM_FileSubHeader fileSubHeader = { 0,/* # of records currently stored in file */ recordSize, recordsPerPage, /* offset in bytes of the first record */ RM_PAGESUBHDR_SIZE+(recordsPerPage+8)/8 }; /* Copy the sub-header to the page */ memcpy (&pData[0], &fileSubHeader, RM_FILESUBHDR_SIZE); /* Initialise the rest of the page. The rest of the page is * reserved for a bitmap for NON_FULL, FULL data pages. NON_FULL * data pages are those pages that have some empty slots in them. * FULL data pages do not have empty slots and therefore cannot * store additional records. */ memset (&pData[RM_FILESUBHDR_SIZE], 0, PF_PAGE_SIZE-RM_FILESUBHDR_SIZE); /* Because we modified the RM header page, we write it to disk */ rc = pfFileHandle.ForcePage (pageNum); if (rc != SUCCESS) { return rc; } /* We now unpin the header page because we are done modifying it */ rc = pfFileHandle.UnpinPage (pageNum); if (rc != SUCCESS) { return rc; } return SUCCESS; }