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::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;
}
Exemple #4
0
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;
}