SimpleDB Lab3 DELETE

Lab3 DELETE

20201118

主要实现B+树的删除操作。

B+树中删除关键字

在 B+树中删除关键字时,有以下几种情况:
1、 找到存储有该关键字所在的结点时,由于该结点中关键字个数大于⌈M/2⌉,做删除操作不会破坏 B+树,则可以直接删除。

例如,在图 1 所示的 B+树中删除关键字 91,删除后的 B+树如图 5 所示:


图 5 删除91的B+树

2、 当删除某结点中最大或者最小的关键字,就会涉及到更改其双亲结点一直到根结点中所有索引值的更改。

例如,在图 1的 B+树中删除关键字 97,删除后的 B+树如图 6 所示:


图 6 删除97后的B+树

3、 当删除该关键字,导致当前结点中关键字个数小于⌈M/2⌉,若其兄弟结点中含有多余的关键字,可以从兄弟结点中借关键字完成删除操作。

例如,在图 1 的 B+树中删除关键字 51,由于其兄弟结点中含有 3 个关键字,所以可以选择借一个关键字,同时修改双亲结点中的索引值,删除之后的 B+树如图 7 所示:


图 7 删除关键字51后的B+树


4、 第 3 种情况中,如果其兄弟结点没有多余的关键字,则需要同其兄弟结点进行合并。

例如,在图 7 的 B+树种删除关键字 59,删除后的 B+树为:


图 8 删除关键字59后的B+树


5、 当进行合并时,可能会产生因合并使其双亲结点破坏 B+树的结构,需要依照以上规律处理其双亲结点。

例如,在图 6 的 B+树中删除关键字 63,当删除后该结点中只剩关键字 72,且其兄弟结点中只有 2 个关键字,无法实现借的操作,只能进行合并。但是合并后,合并后的效果图如图 9 所示:


图 9 合并操作后的效果图


如图 9 所示,其双亲结点中只有一个关键字,而其兄弟结点中有 3 个关键字,所以可以通过借的操作,来满足 B+树的性质,最终的 B+树如图 10 所示:


图 10 删除63后的B+树

总之,在 B+树中做删除关键字的操作,采取如下的步骤:

  1. 删除该关键字,如果不破坏 B+树本身的性质,直接完成操作;
  2. 如果删除操作导致其该结点中最大(或最小)值改变,则应相应改动其父结点中的索引值;
  3. 在删除关键字后,如果导致其结点中关键字个数不足,有两种方法:一种是向兄弟结点去借,另外一种是同兄弟结点合并。(注意这两种方式有时需要更改其父结点中的索引值。

摘自:http://data.biancheng.net/view/61.html


2020/11/22

首先是merge函数:

	protected void mergeLeafPages(TransactionId tid, HashMap<PageId, Page> dirtypages,
			BTreeLeafPage leftPage, BTreeLeafPage rightPage, BTreeInternalPage parent, BTreeEntry parentEntry)
					throws DbException, IOException, TransactionAbortedException {

		// some code goes here
        //
		// Move all the tuples from the right page to the left page, update
		// the sibling pointers, and make the right page available for reuse.
		// Delete the entry in the parent corresponding to the two pages that are merging -
		// deleteParentEntry() will be useful here
        Iterator<Tuple> rightIterator = rightPage.iterator();
        while (rightIterator.hasNext()) {
            Tuple tuple = rightIterator.next();
            rightPage.deleteTuple(tuple);
            leftPage.insertTuple(tuple);
        }

        dirtypages.put(leftPage.getId(), leftPage);
        dirtypages.put(parent.getId(), parent);
        dirtypages.put(rightPage.getId(), rightPage);

        setEmptyPage(tid, dirtypages, rightPage.getId().getPageNumber());

        if(rightPage.getRightSiblingId() != null) {
            BTreePageId newRightLeafPageId = rightPage.getRightSiblingId();
            BTreeLeafPage newRightPage = (BTreeLeafPage) getPage(tid, dirtypages, newRightLeafPageId, Permissions.READ_WRITE);

            leftPage.setRightSiblingId(newRightLeafPageId);
            newRightPage.setLeftSiblingId(leftPage.getId());
        }else{
            leftPage.setRightSiblingId(null);
        }

        deleteParentEntry(tid, dirtypages, leftPage, parent, parentEntry);
	}
	protected void mergeInternalPages(TransactionId tid, HashMap<PageId, Page> dirtypages,
			BTreeInternalPage leftPage, BTreeInternalPage rightPage, BTreeInternalPage parent, BTreeEntry parentEntry)
					throws DbException, IOException, TransactionAbortedException {

		// some code goes here
        //
        // Move all the entries from the right page to the left page, update
		// the parent pointers of the children in the entries that were moved,
		// and make the right page available for reuse
		// Delete the entry in the parent corresponding to the two pages that are merging -
		// deleteParentEntry() will be useful here

        Iterator<BTreeEntry> entryIterator = rightPage.iterator();
        BTreeInternalPageReverseIterator reverseIterator = (BTreeInternalPageReverseIterator) leftPage.reverseIterator();

        deleteParentEntry(tid, dirtypages, leftPage, parent, parentEntry);
        int index = 0;
        while (entryIterator.hasNext()) {
            BTreeEntry entry = entryIterator.next();
            if(index == 0) {
                // parentEntry下沉到子节点
                parentEntry.setLeftChild(reverseIterator.next().getRightChild());
                parentEntry.setRightChild(entry.getLeftChild());
                leftPage.insertEntry(parentEntry);
            }

			rightPage.deleteKeyAndLeftChild(entry);
			leftPage.insertEntry(entry);
            index++;
        }
		// System.out.println(index);
        // 更新指针
        updateParentPointers(tid, dirtypages, leftPage);
        // 放入脏页
        dirtypages.put(rightPage.getId(), rightPage);
        dirtypages.put(leftPage.getId(), leftPage);
        dirtypages.put(parent.getId(), parent);

        setEmptyPage(tid, dirtypages, rightPage.getId().getPageNumber());
	}

stealFromLeaf:

protected void stealFromLeafPage(BTreeLeafPage page, BTreeLeafPage sibling,
			BTreeInternalPage parent, BTreeEntry entry, boolean isRightSibling) throws DbException {
		// some code goes here
        //
        // Move some of the tuples from the sibling to the page so
		// that the tuples are evenly distributed. Be sure to update
		// the corresponding parent entry.
        int pageTuples = page.getNumTuples();
        int siblingTuples = sibling.getNumTuples();
        while(pageTuples < siblingTuples) {
            Tuple stealTuple;
            if (isRightSibling) {
                stealTuple = sibling.iterator().next();
            } else {
                stealTuple = sibling.reverseIterator().next();
            }

            sibling.deleteTuple(stealTuple);
            page.insertTuple(stealTuple);
            entry.setKey(stealTuple.getField(keyField));
            parent.updateEntry(entry);

            pageTuples = page.getNumTuples();
            siblingTuples = sibling.getNumTuples();
        }
	}

stealFromLeftInternal:

protected void stealFromLeftInternalPage(TransactionId tid, HashMap<PageId, Page> dirtypages,
			BTreeInternalPage page, BTreeInternalPage leftSibling, BTreeInternalPage parent,
			BTreeEntry parentEntry) throws DbException, IOException, TransactionAbortedException {
		// some code goes here
        // Move some of the entries from the left sibling to the page so
		// that the entries are evenly distributed. Be sure to update
		// the corresponding parent entry. Be sure to update the parent
		// pointers of all children in the entries that were moved.
        int leftSiblingNumEntries = leftSibling.getNumEntries();
        int pageEntries = page.getNumEntries();


        while(leftSiblingNumEntries > pageEntries) {
            BTreeEntry leftSiblingEntry = leftSibling.reverseIterator().next();
            BTreeEntry rightFirstEntry = page.iterator().next();

            BTreeEntry entry = new BTreeEntry(
                    parentEntry.getKey(),
                    leftSiblingEntry.getRightChild(),
                    rightFirstEntry.getLeftChild());

            page.insertEntry(entry);

            parentEntry.setKey(leftSiblingEntry.getKey());
            parent.updateEntry(parentEntry);

            leftSibling.deleteKeyAndRightChild(leftSiblingEntry);

            dirtypages.put(page.getId(), page);
            dirtypages.put(parent.getId(), parent);
            dirtypages.put(leftSibling.getId(), leftSibling);

            updateParentPointers(tid, dirtypages, page);
            //updateParentPointers(tid, dirtypages, parent);

            pageEntries = page.getNumEntries();
            leftSiblingNumEntries = leftSibling.getNumEntries();
        }
}

stealFromRightInternal:

protected void stealFromRightInternalPage(TransactionId tid, HashMap<PageId, Page> dirtypages,
			BTreeInternalPage page, BTreeInternalPage rightSibling, BTreeInternalPage parent,
			BTreeEntry parentEntry) throws DbException, IOException, TransactionAbortedException {
		// some code goes here
        // Move some of the entries from the right sibling to the page so
		// that the entries are evenly distributed. Be sure to update
		// the corresponding parent entry. Be sure to update the parent
		// pointers of all children in the entries that were moved.

        int rightSiblingNumEntries = rightSibling.getNumEntries();
        int pageEntries = page.getNumEntries();


        while(rightSiblingNumEntries > pageEntries) {
            BTreeEntry rightFirstEntry = rightSibling.iterator().next();
            BTreeEntry leftSiblingEntry = page.reverseIterator().next();

            BTreeEntry entry = new BTreeEntry(
                    parentEntry.getKey(),
                    leftSiblingEntry.getRightChild(),
                    rightFirstEntry.getLeftChild());

            page.insertEntry(entry);

            parentEntry.setKey(rightFirstEntry.getKey());
            parent.updateEntry(parentEntry);

            rightSibling.deleteKeyAndLeftChild(rightFirstEntry);

            dirtypages.put(page.getId(), page);
            dirtypages.put(parent.getId(), parent);
            dirtypages.put(rightSibling.getId(), rightSibling);

            updateParentPointers(tid, dirtypages, page);
            //updateParentPointers(tid, dirtypages, parent);

            pageEntries = page.getNumEntries();
            rightSiblingNumEntries = rightSibling.getNumEntries();
        }
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值