Search in sources :

Example 6 with FetchDescriptor

use of org.apache.derby.iapi.store.raw.FetchDescriptor in project derby by apache.

the class GenericConglomerateController method fetch.

/**
 * @see ConglomerateController#fetch
 */
public boolean fetch(RowLocation loc, DataValueDescriptor[] row, FormatableBitSet validColumns, boolean waitForLock) throws StandardException {
    if (open_conglom.isClosed()) {
        if (open_conglom.getHold()) {
            if (open_conglom.isClosed())
                open_conglom.reopen();
        } else {
            throw (StandardException.newException(SQLState.HEAP_IS_CLOSED, open_conglom.getConglomerate().getId()));
        }
    }
    if (SanityManager.DEBUG) {
        // Make sure valid columns are in the list.  The RowUtil
        // call is too expensive to make in a released system for
        // every fetch.
        int invalidColumn = RowUtil.columnOutOfRange(row, validColumns, open_conglom.getFormatIds().length);
        if (invalidColumn >= 0) {
            throw (StandardException.newException(SQLState.HEAP_TEMPLATE_MISMATCH, invalidColumn, open_conglom.getFormatIds().length));
        }
    }
    // Get the record handle out of its wrapper.
    RowPosition pos = open_conglom.getRuntimeMem().get_scratch_row_position();
    getRowPositionFromRowLocation(loc, pos);
    if (!open_conglom.latchPage(pos)) {
        return false;
    }
    if (open_conglom.isForUpdate()) {
        open_conglom.lockPositionForWrite(pos, waitForLock);
    } else {
        open_conglom.lockPositionForRead(pos, (RowPosition) null, false, waitForLock);
    }
    if (pos.current_page == null) {
        // false to indicate that the row is no longer valid. (DERBY-4676)
        return false;
    }
    // Fetch the row.
    // RESOLVE (STO061) - don't know whether the fetch is for update or not.
    // 
    // 
    // RESOLVE (mikem) - get rid of new here.
    boolean ret_val = (pos.current_page.fetchFromSlot(pos.current_rh, pos.current_slot, row, new FetchDescriptor(row.length, validColumns, (Qualifier[][]) null), false) != null);
    // and just always make the unlock call.
    if (!open_conglom.isForUpdate())
        open_conglom.unlockPositionAfterRead(pos);
    pos.current_page.unlatch();
    return (ret_val);
}
Also used : FetchDescriptor(org.apache.derby.iapi.store.raw.FetchDescriptor) Qualifier(org.apache.derby.iapi.store.access.Qualifier)

Example 7 with FetchDescriptor

use of org.apache.derby.iapi.store.raw.FetchDescriptor in project derby by apache.

the class GenericScanController method positionAtInitScan.

/**
 ************************************************************************
 * Protected methods implementing mechanics of scanning rows:
 *
 *     positionAtInitScan()             - move scan state to SCAN_INIT
 *     positionAtStartForForwardScan()  - SCAN_INIT -> SCAN_INPROGRESS
 *     positionAtResumeScan()           - reposition after losing scan latch
 *     fetchRows()                      - move scan while in SCAN_INPROGRESS
 *     positionAtNextPage()             - move page while in SCAN_INPROGRESS
 *     positionAtDoneScan()             - SCAN_INPROGRESS -> SCAN_DONE
 *
 **************************************************************************
 */
/**
 * Move scan to the the SCAN_INIT state.
 * <p>
 * This routine is called to move the scan to the SCAN_INIT state.
 * It is used both for initialization of the ScanController and
 * by reopenScan().
 */
protected void positionAtInitScan(DataValueDescriptor[] startKeyValue, int startSearchOperator, Qualifier[][] qualifier, DataValueDescriptor[] stopKeyValue, int stopSearchOperator, RowPosition pos) throws StandardException {
    // startKeyValue init.
    this.init_startKeyValue = startKeyValue;
    if (RowUtil.isRowEmpty(this.init_startKeyValue))
        this.init_startKeyValue = null;
    // startSearchOperator init.
    this.init_startSearchOperator = startSearchOperator;
    // qualifier init.
    if ((qualifier != null) && (qualifier.length == 0))
        qualifier = null;
    this.init_qualifier = qualifier;
    // TODO (mikem) - this could be more efficient, by writing
    // code to figure out length of row, but scratch row is cached
    // so allocating it here is probably not that bad.
    init_fetchDesc = new FetchDescriptor((open_conglom.getRuntimeMem().get_scratch_row(open_conglom.getRawTran())).length, init_scanColumnList, init_qualifier);
    // stopKeyValue init.
    this.init_stopKeyValue = stopKeyValue;
    if (RowUtil.isRowEmpty(this.init_stopKeyValue))
        this.init_stopKeyValue = null;
    // stopSearchOperator init.
    this.init_stopSearchOperator = stopSearchOperator;
    // reset the "current" position to starting condition.
    pos.init();
    // scanColumnList.
    if (SanityManager.DEBUG) {
        if (init_scanColumnList != null) {
            // verify that all columns specified in qualifiers, start
            // and stop positions are specified in the scanColumnList.
            FormatableBitSet required_cols;
            if (qualifier != null)
                required_cols = RowUtil.getQualifierBitSet(qualifier);
            else
                required_cols = new FormatableBitSet(0);
            // add in start columns
            if (this.init_startKeyValue != null) {
                required_cols.grow(this.init_startKeyValue.length);
                for (int i = 0; i < this.init_startKeyValue.length; i++) required_cols.set(i);
            }
            if (this.init_stopKeyValue != null) {
                required_cols.grow(this.init_stopKeyValue.length);
                for (int i = 0; i < this.init_stopKeyValue.length; i++) required_cols.set(i);
            }
            FormatableBitSet required_cols_and_scan_list = (FormatableBitSet) required_cols.clone();
            required_cols_and_scan_list.and(init_scanColumnList);
            // FormatableBitSet equals requires the two FormatableBitSets to be of same
            // length.
            required_cols.grow(init_scanColumnList.size());
            if (!required_cols_and_scan_list.equals(required_cols)) {
                SanityManager.THROWASSERT("Some column specified in a Btree " + " qualifier/start/stop list is " + "not represented in the scanColumnList." + "\n:required_cols_and_scan_list = " + required_cols_and_scan_list + "\n;required_cols = " + required_cols + "\n;init_scanColumnList = " + init_scanColumnList);
            }
        }
    }
    // Scan is fully initialized and ready to go.
    scan_state = SCAN_INIT;
}
Also used : FetchDescriptor(org.apache.derby.iapi.store.raw.FetchDescriptor) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet)

Example 8 with FetchDescriptor

use of org.apache.derby.iapi.store.raw.FetchDescriptor in project derby by apache.

the class BTreeRowPosition method getFetchDescriptorForSaveKey.

/**
 * Get a fetch descriptor that can be used to fetch the missing columns
 * in a partial key. The fetch descriptor is only created on the first
 * call to this method. The returned descriptor will be cached, so
 * subsequent calls will return the same descriptor and the arguments
 * to this method should be the same between invokations.
 *
 * @param vcols an array which tells which columns the partial key contains
 * (valid columns have non-zero values in the array)
 * @param fullLength the length of the full key to create a fetch
 * descriptor for (may be greater than {@code vcols.length})
 * @return a fetch descriptor
 */
FetchDescriptor getFetchDescriptorForSaveKey(int[] vcols, int fullLength) {
    if (savedFetchDescriptor == null) {
        FormatableBitSet columns = new FormatableBitSet(fullLength);
        for (int i = 0; i < vcols.length; i++) {
            if (vcols[i] == 0) {
                // partial key does not have a valid value for this
                // column, add it to the set of columns to fetch
                columns.set(i);
            }
        }
        // also fetch the columns behind the ones in the partial key
        for (int i = vcols.length; i < fullLength; i++) {
            columns.set(i);
        }
        savedFetchDescriptor = new FetchDescriptor(fullLength, columns, null);
    }
    // as when the descriptor was created and cached).
    if (SanityManager.DEBUG) {
        FormatableBitSet fetchCols = savedFetchDescriptor.getValidColumns();
        SanityManager.ASSERT(fullLength == fetchCols.size());
        for (int i = 0; i < vcols.length; i++) {
            SanityManager.ASSERT((vcols[i] == 0) == fetchCols.get(i));
        }
        for (int i = vcols.length; i < fullLength; i++) {
            SanityManager.ASSERT(fetchCols.get(i));
        }
    }
    return savedFetchDescriptor;
}
Also used : FetchDescriptor(org.apache.derby.iapi.store.raw.FetchDescriptor) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet)

Example 9 with FetchDescriptor

use of org.apache.derby.iapi.store.raw.FetchDescriptor in project derby by apache.

the class BTreeController method doIns.

/**
 *    Insert a row into the conglomerate.
 *
 *    @param rowToInsert The row to insert into the conglomerate.  The stored
 *	representations of the row's columns are copied into a new row
 *	somewhere in the conglomerate.
 *
 *	@return Returns 0 if insert succeeded.  Returns
 *    ConglomerateController.ROWISDUPLICATE if conglomerate supports uniqueness
 *    checks and has been created to disallow duplicates, and the row inserted
 *    had key columns which were duplicate of a row already in the table.  Other
 *    insert failures will raise StandardException's.
 *
 *	@exception StandardException Standard exception policy.
 */
private int doIns(DataValueDescriptor[] rowToInsert) throws StandardException {
    LeafControlRow targetleaf = null;
    LeafControlRow save_targetleaf = null;
    int insert_slot = 0;
    int result_slot = 0;
    int ret_val = 0;
    boolean reclaim_deleted_rows_attempted = false;
    if (scratch_template == null) {
        scratch_template = runtime_mem.get_template(getRawTran());
    }
    if (SanityManager.DEBUG)
        this.isIndexableRowConsistent(rowToInsert);
    // Create the objects needed for the insert.
    // RESOLVE (mikem) - should we cache this in the controller?
    SearchParameters sp = new SearchParameters(rowToInsert, SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH, scratch_template, this, false);
    // RowLocation column is in last column of template.
    FetchDescriptor lock_fetch_desc = RowUtil.getFetchDescriptorConstant(scratch_template.length - 1);
    RowLocation lock_row_loc = (RowLocation) scratch_template[scratch_template.length - 1];
    if (get_insert_row_lock) {
        // I don't hold any latch yet so I can wait on this lock, so I
        // don't care about return value from this call.  This
        // lock can only wait if the base table row was inserted in a
        // separate transaction which never happens in sql tables, but
        // does happen in the sparse indexes that synchronization builds.
        this.getLockingPolicy().lockNonScanRow(this.getConglomerate(), (LeafControlRow) null, (LeafControlRow) null, rowToInsert, (ConglomerateController.LOCK_INS | ConglomerateController.LOCK_UPD));
    }
    while (true) {
        // Search the location at which the new row should be inserted.
        if (SanityManager.DEBUG)
            SanityManager.ASSERT(this.container != null);
        targetleaf = (LeafControlRow) ControlRow.get(this, BTree.ROOTPAGEID).search(sp);
        // Row locking - first lock row previous to row being inserted:
        // o if (sp.resultExact) then the row must be deleted and
        // we will be replacing it with the new row, lock
        // the row before the slot as the previous key.
        // o else
        // we will be inserting after the current slot so
        // lock the current slot as the previous key.
        // 
        int slot_after_previous = (sp.resultExact ? sp.resultSlot : sp.resultSlot + 1);
        boolean latch_released = false;
        latch_released = !this.getLockingPolicy().lockNonScanPreviousRow(targetleaf, slot_after_previous, lock_fetch_desc, scratch_template, lock_row_loc, this, (ConglomerateController.LOCK_INS_PREVKEY | ConglomerateController.LOCK_UPD), TransactionManager.LOCK_INSTANT_DURATION);
        // special test to see if latch release code works
        if (SanityManager.DEBUG) {
            latch_released = test_errors(this, "BTreeController_doIns", null, this.getLockingPolicy(), targetleaf, latch_released);
        }
        if (latch_released) {
            // Had to release latch in order to get the lock, probably
            // because of a forward scanner, research tree, and try again.
            targetleaf = null;
            continue;
        }
        // deleted row).
        if (sp.resultExact) {
            result_slot = insert_slot = sp.resultSlot;
            if (this.getConglomerate().nKeyFields != this.getConglomerate().nUniqueColumns) {
                // The key fields match, but not the row location.  We
                // must wait on the lock on the other row location before
                // preceding, so as to serialize behind any work being done
                // to the row as part of another transaction.
                latch_released = !this.getLockingPolicy().lockNonScanRowOnPage(targetleaf, insert_slot, lock_fetch_desc, scratch_template, lock_row_loc, ConglomerateController.LOCK_UPD);
                if (latch_released) {
                    // Had to release latch in order to get the lock,
                    // probably to wait for deleting xact to commit or
                    // abort.  Research tree, and try again.
                    targetleaf = null;
                    continue;
                }
            }
            if (!(targetleaf.page.isDeletedAtSlot(insert_slot))) {
                // attempt to insert a duplicate into the index.
                ret_val = ConglomerateController.ROWISDUPLICATE;
                break;
            } else {
                if (this.getConglomerate().nKeyFields == this.getConglomerate().nUniqueColumns) {
                    // The row that we found deleted is exactly the new row.
                    targetleaf.page.deleteAtSlot(insert_slot, false, this.btree_undo);
                    break;
                } else if (this.getConglomerate().nUniqueColumns == (this.getConglomerate().nKeyFields - 1)) {
                    // The row that we found deleted has matching keys
                    // which form the unique key fields,
                    // but the nonkey fields may differ (for now the
                    // heap rowlocation is the only nonkey field
                    // allowed).
                    // RESOLVE BT39 (mikem) - when/if heap row location
                    // is not fixed we must handle update failing for
                    // out of space and split if it does.  For now
                    // if the update fails because of lack of space
                    // an exception is thrown and the statement is
                    // backed out.  Should not happen very often.
                    targetleaf.page.deleteAtSlot(insert_slot, false, this.btree_undo);
                    boolean update_succeeded = true;
                    try {
                        if (runtime_mem.hasCollatedTypes()) {
                            // See DERBY-5367.
                            // There are types in the BTree with a
                            // collation different than UCS BASIC, we
                            // update all fields to make sure they hold
                            // the correct values.
                            // NOTE: We could optimize here by only
                            // updating the fields that actually hold
                            // collated types.
                            int rowsToUpdate = getConglomerate().nKeyFields;
                            for (int i = 0; i < rowsToUpdate; i++) {
                                targetleaf.page.updateFieldAtSlot(insert_slot, i, (DataValueDescriptor) RowUtil.getColumn(rowToInsert, (FormatableBitSet) null, i), this.btree_undo);
                            }
                        } else {
                            // There are no collated types in the BTree,
                            // which means that the values currently
                            // stored in the undeleted row are correct.
                            // We simply update the row location to point
                            // to the correct row in the heap.
                            int rowloc_index = this.getConglomerate().nKeyFields - 1;
                            targetleaf.page.updateFieldAtSlot(insert_slot, rowloc_index, (DataValueDescriptor) RowUtil.getColumn(rowToInsert, (FormatableBitSet) null, rowloc_index), this.btree_undo);
                        }
                    } catch (StandardException se) {
                        // check if the exception is for out of space
                        if (!se.getMessageId().equals(SQLState.DATA_NO_SPACE_FOR_RECORD)) {
                            throw se;
                        }
                        // The statement exception is
                        // because the update failed for out of
                        // space (ie. the field got longer and there
                        // is no room on the page for the expanded
                        // field).  Address this error by falling
                        // through the code and doing a split.
                        // update failed.
                        update_succeeded = false;
                        targetleaf.page.deleteAtSlot(insert_slot, true, this.btree_undo);
                    }
                    if (update_succeeded)
                        break;
                } else {
                    // Can only happen with non key fields in the btree.
                    throw (StandardException.newException(SQLState.BTREE_UNIMPLEMENTED_FEATURE));
                }
            }
        } else if (targetleaf.page.recordCount() - 1 < BTree.maxRowsPerPage) {
            // The row wasn't there, so try to insert it
            // on the page returned by the search.
            insert_slot = sp.resultSlot + 1;
            result_slot = insert_slot + 1;
            if (getConglomerate().isUniqueWithDuplicateNulls()) {
                int ret = compareLeftAndRightSiblings(rowToInsert, insert_slot, targetleaf);
                if (ret == MATCH_FOUND) {
                    ret_val = ConglomerateController.ROWISDUPLICATE;
                    break;
                }
                if (ret == RESCAN_REQUIRED)
                    continue;
            }
            if (targetleaf.page.insertAtSlot(insert_slot, rowToInsert, (FormatableBitSet) null, this.btree_undo, Page.INSERT_DEFAULT, AccessFactoryGlobals.BTREE_OVERFLOW_THRESHOLD) != null) {
                break;
            }
            if (targetleaf.page.recordCount() <= 2) {
                throw StandardException.newException(SQLState.BTREE_NO_SPACE_FOR_KEY);
            }
        // start splitting ...
        }
        if (getConglomerate().isUniqueWithDuplicateNulls()) {
            int ret = compareLeftAndRightSiblings(rowToInsert, insert_slot, targetleaf);
            if (ret == MATCH_FOUND) {
                ret_val = ConglomerateController.ROWISDUPLICATE;
                break;
            }
            if (ret == RESCAN_REQUIRED)
                continue;
        }
        // Create some space by splitting pages.
        // determine where in page/table row causing split would go
        int flag = 0;
        if (insert_slot == 1) {
            flag |= ControlRow.SPLIT_FLAG_FIRST_ON_PAGE;
            if (targetleaf.isLeftmostLeaf())
                flag |= ControlRow.SPLIT_FLAG_FIRST_IN_TABLE;
        } else if (insert_slot == targetleaf.page.recordCount()) {
            flag |= ControlRow.SPLIT_FLAG_LAST_ON_PAGE;
            if (targetleaf.isRightmostLeaf())
                flag |= ControlRow.SPLIT_FLAG_LAST_IN_TABLE;
        }
        long targetleaf_pageno = targetleaf.page.getPageNumber();
        if ((targetleaf.page.recordCount() - targetleaf.page.nonDeletedRecordCount()) <= 0) {
            // Don't do reclaim work if there are no deleted records.
            reclaim_deleted_rows_attempted = true;
        }
        BranchRow branchrow = BranchRow.createBranchRowFromOldLeafRow(rowToInsert, targetleaf_pageno);
        // Release the target page because (a) it may change as a
        // result of the split, (b) the latch ordering requires us
        // to acquire latches from top to bottom, and (c) this
        // loop should be done in a system transaction.
        targetleaf.release();
        targetleaf = null;
        start_xact_and_dosplit(!reclaim_deleted_rows_attempted, targetleaf_pageno, scratch_template, branchrow.getRow(), flag);
        // only attempt to reclaim deleted rows once, otherwise the
        // split loop could loop forever, trying to reclaim a deleted
        // row that was not committed.
        reclaim_deleted_rows_attempted = true;
    // RESOLVE (mikem) possible optimization could be to save
    // split location and look there first, if this has
    // already caused a split.  Or even return a latched page
    // from splitFor().  For now just execute the loop again
    // searching the tree for somewhere to put the row.
    }
    // set in-memory hint of where last row on page was inserted.
    targetleaf.last_search_result = result_slot;
    // Check that page just updated is consistent.
    if (SanityManager.DEBUG) {
        if (SanityManager.DEBUG_ON("enableBtreeConsistencyCheck")) {
            targetleaf.checkConsistency(this, null, true);
        }
    }
    // Done with the target page.
    targetleaf.release();
    targetleaf = null;
    // return the status about insert - 0 is ok, or duplicate status.
    return (ret_val);
}
Also used : StandardException(org.apache.derby.shared.common.error.StandardException) FetchDescriptor(org.apache.derby.iapi.store.raw.FetchDescriptor) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 10 with FetchDescriptor

use of org.apache.derby.iapi.store.raw.FetchDescriptor in project derby by apache.

the class BTreeController method compareRowsForInsert.

/**
 * Compares two rows for insert. If the two rows are not equal,
 * {@link #NO_MATCH} is returned. Otherwise, it tries to get a lock on
 * the row in the tree. If the lock is obtained without waiting,
 * {@link #MATCH_FOUND} is returned (even if the row has been deleted).
 * Otherwise, {@link #RESCAN_REQUIRED} is returned to indicate that the
 * latches have been released and the B-tree must be rescanned.
 *
 * If {@code MATCH_FOUND} is returned, the caller should check whether
 * the row has been deleted. If so, it may have to move to check the
 * adjacent rows to be sure that there is no non-deleted duplicate row.
 *
 * If {@code MATCH_FOUND} or {@code RESCAN_REQUIRED} is returned, the
 * transaction will hold an update lock on the specified record when
 * the method returns.
 *
 * <b>Note!</b> This method should only be called when the index is almost
 * unique (that is, a non-unique index backing a unique constraint).
 *
 * @param originalRow row from the tree
 * @param newRow row to be inserted
 * @param leaf leaf where originalRow resides
 * @param slot slot where originalRow
 * @return  {@code NO_MATCH} if no duplicate is found,
 *          {@code MATCH_FOUND} if a duplicate is found, or
 *          {@code RESCAN_REQUIRED} if the B-tree must be rescanned
 */
private int compareRowsForInsert(DataValueDescriptor[] originalRow, DataValueDescriptor[] newRow, LeafControlRow leaf, int slot) throws StandardException {
    for (int i = 0; i < originalRow.length - 1; i++) {
        if (!originalRow[i].equals(newRow[i]))
            return NO_MATCH;
    }
    // It might be a deleted record try getting a lock on it
    DataValueDescriptor[] template = runtime_mem.get_template(getRawTran());
    FetchDescriptor lock_fetch_desc = RowUtil.getFetchDescriptorConstant(template.length - 1);
    RowLocation lock_row_loc = (RowLocation) scratch_template[scratch_template.length - 1];
    boolean latch_released = !getLockingPolicy().lockNonScanRowOnPage(leaf, slot, lock_fetch_desc, template, lock_row_loc, ConglomerateController.LOCK_UPD);
    // record and might have changed the tree by now
    if (latch_released)
        return RESCAN_REQUIRED;
    return MATCH_FOUND;
}
Also used : FetchDescriptor(org.apache.derby.iapi.store.raw.FetchDescriptor) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Aggregations

FetchDescriptor (org.apache.derby.iapi.store.raw.FetchDescriptor)16 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)9 Page (org.apache.derby.iapi.store.raw.Page)5 Qualifier (org.apache.derby.iapi.store.access.Qualifier)4 RecordHandle (org.apache.derby.iapi.store.raw.RecordHandle)4 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)3 AuxObject (org.apache.derby.iapi.store.raw.AuxObject)2 RowLocation (org.apache.derby.iapi.types.RowLocation)2 CounterOutputStream (org.apache.derby.iapi.services.io.CounterOutputStream)1 NullOutputStream (org.apache.derby.iapi.services.io.NullOutputStream)1 SQLLongint (org.apache.derby.iapi.types.SQLLongint)1 StorableFormatId (org.apache.derby.impl.store.access.StorableFormatId)1 StandardException (org.apache.derby.shared.common.error.StandardException)1