📄 leafcontrolrow.java
字号:
} byte insertFlag = Page.INSERT_INITIAL; insertFlag |= Page.INSERT_DEFAULT; insertFlag |= Page.INSERT_UNDO_WITH_PURGE; if (parent_page.page.insertAtSlot( sp.resultSlot + 1, branchrow.getRow(), (FormatableBitSet) null, (LogicalUndo)null, insertFlag, AccessFactoryGlobals.BTREE_OVERFLOW_THRESHOLD) == null) { throw StandardException.newException( SQLState.BTREE_NO_SPACE_FOR_KEY); } // branchrow is only valid while split_leaf_row remains unchanged. branchrow = null; // RESOLVE (mikem) - this case breaks the btree currently - as the // abort of the insert leaves a logical delete in the tree. // // Test fail after parent page has been updated. if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_abort4")) { throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("enableBtreeConsistencyCheck")) { this.checkConsistency(open_btree, parent_page, false); newleaf.checkConsistency(open_btree, parent_page, false); parent_page.checkConsistency(open_btree, null, false); } } // At this point a unit of work in the split down the tree has // been performed in an internal transaction. This work must // be committed before any latches are released. open_btree.getXactMgr().commit(); parent_page.release(); this.release(); // XXX (nat) Not good form to unlatch self. long new_leaf_pageno = newleaf.page.getPageNumber(); newleaf.release(); // Because we are at the leaf level and have completed the split // there is no more work, no latches should be held, and control // is returned up the recursive stack, to the insert causing the // split. Because latches are released, the inserter must recheck // that there is now space available as some other thread of control // could get in before he latches the page again. return(new_leaf_pageno); } /** ** Grow a new root page from a leaf page. Slightly ** tricky because we want to retain page 0 as the root. ** <P> ** On entry, the current leaf root page is expected ** to be latched. On exit, all latches will have been ** released. ** <P> ** The caller cannot not assume success. If we have to release latches ** this routine just returns and assumes the caller will retry the ** grow root if necessary. **/ private static void growRoot( OpenBTree open_btree, DataValueDescriptor[] template, LeafControlRow leafroot) throws StandardException { BranchControlRow branchroot = null; LeafControlRow newleaf = null; // Before moving the rows on the page, while having the latch on the // page, notify btree scans that the rows on this page may be moving // onto another page. // open_btree.init_open_user_scans.saveScanPositions( open_btree.getConglomerate(), leafroot.page); // Get exclusive RECORD_ID_PROTECTION_HANDLE lock to make sure that // we wait for scans in other transactions to move off of this page // before we grow root. If we don't wait, scanners in other // transactions may be positioned on the leaf page which we are // about to make into a branch page. if (!open_btree.getLockingPolicy().lockScan( leafroot, (ControlRow) null, true /* for update */, ConglomerateController.LOCK_UPD)) { // We had to give up latches on leafroot to get the // split lock. Redo the whole split pass as we have lost our // latches - which may mean that the root has grown when we gave // up the latch. Just returning is ok, as the caller can not assume // that grow root has succeeded in making space. Note that at this // point in the split no write work has been done in the current // internal transaction, so giving up here is fairly cheap. return; } // Allocate a new leaf page under the existing leaf root. newleaf = LeafControlRow.Allocate(open_btree, leafroot); // Test fail after allocation if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_growRoot1")) { throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } // Copy all the index rows from the root to the new leaf, do not // copy the control row. This routine will purge all the copied // rows and maintain the deleted status of the moved rows. if (SanityManager.DEBUG) SanityManager.ASSERT((leafroot.page.recordCount() - 1) > 0); leafroot.page.copyAndPurge( newleaf.page, 1, leafroot.page.recordCount() - 1, 1); // Test fail after row copy if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_growRoot2")) { throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } // Test fail after purge if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_growRoot3")) { // Make sure tree is very trashed and logical recovery will // not work. leafroot.setLevel(42); leafroot.setParent(42); throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } // Put a branch control row on the root page, making the new leaf // the left child. All leaf splits result in level-1 branch pages. // This will be a branch-root page. // Construction of the BranchControlRow will set it as the aux // object for the page, this in turn invalidates the previous aux // object which is leafroot. Thus leafroot must not be used once // the constructor returns. branchroot = new BranchControlRow( open_btree, leafroot.page, 1, null, true, newleaf.page.getPageNumber()); leafroot = null; // Replace the old leaf root control row with the new branch root // control row. branchroot.page.updateAtSlot( 0, branchroot.getRow(), (FormatableBitSet) null); // Test fail after purge if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_growRoot4")) { throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("enableBtreeConsistencyCheck")) { newleaf.checkConsistency(open_btree, branchroot, false); branchroot.checkConsistency(open_btree, null, false); } } // At this point a unit of work in the split down the tree has // been performed in an internal transaction. This work must // be committed before any latches are released. open_btree.getXactMgr().commit(); // Test fail after commit of split if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("leaf_split_growRoot5")) { throw StandardException.newException( SQLState.BTREE_ABORT_THROUGH_TRACE); } } // The variable 'branchroot' refers to a page that was latched by // leafroot. After a growRoot() from a leaf there will be no pages // latched. It is up to the callers to reget the root page latched // and continue their work. // if (branchroot != null) branchroot.release(); if (leafroot != null) leafroot.release(); if (newleaf != null) newleaf.release(); } /** * Return the left child pointer for the page. * <p> * Leaf pages don't have children, so they override this and return null. * * @return The page which is the leftmost child of this page. * * @param btree The open btree to associate latches/locks with. * * @exception StandardException Standard exception policy. **/ protected ControlRow getLeftChild(OpenBTree btree) throws StandardException { return(null); } /** * Return the right child pointer for the page. * <p> * Leaf pages don't have children, so they override this and return null. * * @return The page which is the rightmost child of this page. * * @param btree The open btree to associate latches/locks with. * * @exception StandardException Standard exception policy. **/ protected ControlRow getRightChild(OpenBTree btree) throws StandardException { return(null); } /* ** Debug/consistency check Methods of ControlRow: */ /** ** Perform consistency checks on a leaf page. ** ** Check consistency of the page and its children, ** returning the number of pages seen, and throwing ** errors if inconsistencies are found. ** The checks specific to a leaf page are: ** <menu> ** <li> Page is at level 0. ** <li> Version is a valid leaf page version. ** <li> Control row has right number of columns for leaf. ** </menu> ** This method also performs the consistency checks that ** are common to both leaf and branch pages. ** @see ControlRow#checkGeneric ** ** @exception StandardException Standard exception policy. **/ public int checkConsistency( OpenBTree btree, ControlRow parent, boolean check_other_pages ) throws StandardException { // Do the consistency checks that are common to all // types of pages. checkGeneric(btree, parent, check_other_pages); // Leaf specific, control row checks if (SanityManager.DEBUG) { SanityManager.ASSERT(this.getLevel() == 0, "leaf not at level 0"); // RESOLVE (mikem) - how to sanity check correct version? /* if (this.getVersion() != CURRENT_LEAF_VERSION) SanityManager.THROWASSERT( "Expected leaf version:(" + CURRENT_LEAF_VERSION + ") but got (" + this.getVersion()); */ SanityManager.ASSERT( this.page.fetchNumFieldsAtSlot(CR_SLOT) == ControlRow.CR_NCOLUMNS); // The remaining checks are specific to leaf pages. // Check that every row has at least as many columns // as the number of key fields in the b-tree. int numslots = this.page.recordCount(); for (int slot = 1; slot < numslots; slot++) { if (this.page.fetchNumFieldsAtSlot(slot) < btree.getConglomerate().nKeyFields) SanityManager.THROWASSERT( "row[" + slot + "]" + " has " + this.page.fetchNumFieldsAtSlot(slot) + " columns, should have at least" + btree.getConglomerate().nKeyFields); // RESOLVE - the generic btree code should know nothing about // the secondaryindex row location column, but put this here for // now because I can't figure how to get a call out to the // secondary index code at the page level consistency checking // level. } } // We checked one page (this one). return 1; } /** ** Recursively print the tree starting at current node in tree. ** This is a leaf so return. @exception StandardException Standard exception policy. **/ public void printTree( OpenBTree btree) throws StandardException { if (SanityManager.DEBUG) { SanityManager.DEBUG_PRINT("p_tree", this.debugPage(btree)); return; } } /* * Methods of TypedFormat: */ /** Return my format identifier. @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId */ public int getTypeFormatId() { return StoredFormatIds.ACCESS_BTREE_LEAFCONTROLROW_V1_ID; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -