📄 b2irowlocking3.java
字号:
throws StandardException { boolean latches_released = false; LeafControlRow prev_leaf; LeafControlRow prev_prev_leaf; try { // Move left in tree, page latch will be requested nowait, // and WaitError will be thrown if latch not granted. prev_leaf = (LeafControlRow) current_leaf.getLeftSibling(open_btree); } catch (WaitError e) { long previous_pageno = current_leaf.getleftSiblingPageNumber(); // error going from mainpage to first left page. Release // current page latch and continue the search. current_leaf.release(); current_leaf = null; // wait on the left page, which we could not get before. prev_leaf = (LeafControlRow) ControlRow.Get(open_btree, previous_pageno); latches_released = true; } while (true) { try { // loop searching left in the btree until you either find // a record to lock, or you reach the leftmost empty leaf. if (prev_leaf.getPage().recordCount() > 1) { // lock the last row on the page, which is the previous // record to the first row on the next page. boolean ret_status = lockRowOnPage( b2i, prev_leaf, current_leaf, prev_leaf.getPage().recordCount() - 1, false, lock_fetch_desc, lock_template, lock_row_loc, lock_operation, lock_duration); if (!ret_status) { prev_leaf = null; current_leaf = null; latches_released = true; } break; } else if (prev_leaf.isLeftmostLeaf()) { // Table's first row, lock the key that represents the // key previous to first key of the table. boolean ret_status = lockPreviousToFirstKey( prev_leaf, current_leaf, lock_operation, lock_duration); if (!ret_status) { prev_leaf = null; current_leaf = null; latches_released = true; } break; } // Move left in tree, page latch will be requested nowait, // and WaitError will be thrown if latch not granted. // Release latches on pages between "current_leaf" and // where the search leads, so that at most 3 latched pages // (current_leaf, prev_leaf, prev_prev_leaf) are held during // the search. Do left ladder locking as you walk left, // but be ready to release l prev_prev_leaf = (LeafControlRow) prev_leaf.getLeftSibling(open_btree); prev_leaf.release(); prev_leaf = prev_prev_leaf; prev_prev_leaf = null; } catch (WaitError e) { long previous_pageno = prev_leaf.getleftSiblingPageNumber(); // error going left. Release current page latch and // original page latch continue the search. current_leaf.release(); current_leaf = null; prev_leaf.release(); prev_leaf = null; // wait on the left page, which we could not get before. prev_leaf = (LeafControlRow) ControlRow.Get(open_btree, previous_pageno); latches_released = true; } } if (prev_leaf != null) prev_leaf.release(); return(!latches_released); } /************************************************************************** * Protected methods of This class: ************************************************************************** */ /** * Lock a row as part of doing the scan. * <p> * Lock the row at the given slot (or the previous row if slot is 0). * Get the scan lock on the page if "request_scan_lock" is true. * <p> * If this routine returns true all locks were acquired while maintaining * the latch on leaf. If this routine returns false, locks may or may * not have been acquired, and the routine should be called again after * the client has researched the tree to reget the latch on the * appropriate page. * (p> * As a sided effect stores the value of the record handle of the current * scan lock. * * @return Whether locks were acquired without releasing latch on leaf. * * @param open_btree The open_btree to associate latches with - * used if routine has to scan backward. * @param btree the conglomerate info. * @param pos The position of the row to lock. * @param request_row_lock Whether to request the row lock, should * only be requested once per page in the scan. * @param request_scan_lock Whether to request the page scan lock, should * only be requested once per page in the scan. * @param lock_fetch_desc The fetch descriptor to use to fetch the * row location for the lock request. * @param lock_template A scratch area to use to read in rows. * @param previous_key_lock Is this a previous key lock call? * @param forUpdate Is the scan for update or for read only. * * @exception StandardException Standard exception policy. **/ protected boolean _lockScanRow( OpenBTree open_btree, BTree btree, BTreeRowPosition pos, boolean request_row_lock, boolean request_scan_lock, FetchDescriptor lock_fetch_desc, DataValueDescriptor[] lock_template, RowLocation lock_row_loc, boolean previous_key_lock, boolean forUpdate, int lock_operation) throws StandardException { boolean latch_released = false; B2I b2i = (B2I) btree; if (request_row_lock) { // In order to implement a serialized scan based on previous // key locking, this method acquires a row lock on // the base table's row from the index row at [startpage/startslot]. // This will be the 'previous key'. if (pos.current_slot == 0) { // this call will take care of searching left in the btree // to find the previous row to lock, 0 is the control row and // not a valid thing to lock as a previous key. // it is ok to call the non-scan as this is just a special // case of a previous key lock call. The only scan code that // will call this routine with slot == 0 will retry if this // routine returns that a latch was released. latch_released = !lockNonScanPreviousRow( btree, pos.current_leaf, 1 /* lock row previous to row at slot 1 */, lock_fetch_desc, lock_template, lock_row_loc, open_btree, lock_operation, TransactionManager.LOCK_COMMIT_DURATION); // special test to see if latch release code works if (SanityManager.DEBUG) { latch_released = OpenBTree.test_errors( open_btree, "B2iRowLocking3_1_lockScanRow", false, this, pos.current_leaf, latch_released); } } else { // Just lock the row at "slot" latch_released = !lockRowOnPage( btree, pos.current_leaf, (LeafControlRow) null /* no other latch currently */, pos.current_slot, true, lock_fetch_desc, lock_template, lock_row_loc, lock_operation, TransactionManager.LOCK_COMMIT_DURATION); // special test to see if latch release code works if (SanityManager.DEBUG) { latch_released = OpenBTree.test_errors( open_btree, "B2iRowLocking3_2_lockScanRow", false, this, pos.current_leaf, latch_released); } } } if (request_scan_lock && !latch_released) { // Get the scan lock on the start page. // Get shared RECORD_ID_PROTECTION_HANDLE lock to make sure that // we wait for scans in other transactions to move off of this page // before we split. latch_released = !lockScan( pos.current_leaf, (LeafControlRow) null, // no other latch currently false, ConglomerateController.LOCK_READ);// read scan lock position // special test to see if latch release code works if (SanityManager.DEBUG) { /* RESOLVE - need to get a container here */ latch_released = OpenBTree.test_errors( open_btree, "B2iRowLocking3_3_lockScanRow", true, this, pos.current_leaf, latch_released); } } return(!latch_released); } /************************************************************************** * Public Methods of This class: ************************************************************************** */ /************************************************************************** * Abstract Protected lockScan*() locking methods of BTree: * lockScan - lock the scan page * lockScanForReclaimSpace - lock page for reclaiming deleted rows. * lockScanRow - lock row and possibly the scan page * unlockScan - unlock the scan page * unlockScanRecordAfterRead- unlock the scan record ************************************************************************** */ /** * Lock a control row page for scan. * <p> * Scanners get shared lock on the page while positioned on a row within * the page, splitter/purgers/mergers get exclusive lock on the page. * * See BTree.lockScan() for more info. * * @exception StandardException Standard exception policy. **/ public boolean lockScan( LeafControlRow current_leaf, ControlRow aux_control_row, boolean forUpdate, int lock_operation) throws StandardException { // The scan page lock is implemented as a row lock on the reserved // row id on the page (RecordHandle.RECORD_ID_PROTECTION_HANDLE). RecordHandle scan_lock_rh = current_leaf.getPage().makeRecordHandle( RecordHandle.RECORD_ID_PROTECTION_HANDLE); // First try to get the lock NOWAIT, while latch is held. boolean ret_status = _lockScan(scan_lock_rh, forUpdate, false /* NOWAIT */); if (!ret_status) { current_leaf.release(); current_leaf = null; if (aux_control_row != null) { aux_control_row.release(); aux_control_row = null; } // Could not get the lock NOWAIT, release latch and wait // for the lock. _lockScan(scan_lock_rh, forUpdate, true /* WAIT */); // once we get the lock, give it up as we need to get the lock // while we have the latch. When the lock manager gives us the // ability to do instantaneous locks do that. We just wait on the // lock to give the split a chance to finish before we interfere. if (!forUpdate) { scan_locking_policy.unlockRecordAfterRead( rawtran, open_btree.getContainerHandle(), scan_lock_rh, false, true); } else { // RESOLVE - need instantaneous locks as there is no way // currently to release a write lock. This lock will only // be requested by split, and will be released by internal // transaction. }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -