Search in sources :

Example 36 with RawTransaction

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

the class InsertOperation method undoMe.

/*
	 * PageOperation methods
	 */
/**
 *		Undo the insert by simply marking the just inserted record as deleted.
 *		All logical undo logic has already been taken care of by generateUndo.
 *
 *		@exception IOException Can be thrown by any of the methods of ObjectInput.
 *		@exception StandardException Standard Derby policy.
 *
 *		@see LogicalPageOperation#undoMe
 */
public void undoMe(Transaction xact, BasePage undoPage, int undoRecordId, LogInstant CLRInstant, LimitObjectInput in) throws StandardException, IOException {
    int slot = undoPage.findRecordById(undoRecordId, Page.FIRST_SLOT_NUMBER);
    if (SanityManager.DEBUG) {
        // page number and recordId
        if (undoRecordId != this.recordId)
            if (undoPage.getPageNumber() == getPageId().getPageNumber())
                SanityManager.THROWASSERT("recordId changed from " + this.recordId + " to " + undoRecordId + " but page number did not change " + undoPage.getPageNumber());
        if (slot == -1)
            SanityManager.THROWASSERT("recordId " + undoRecordId + " not found on page " + undoPage.getPageNumber());
    }
    RawTransaction rxact = (RawTransaction) xact;
    if ((insertFlag & Page.INSERT_UNDO_WITH_PURGE) != 0) {
        undoPage.purgeRecord(CLRInstant, slot, undoRecordId);
        // stream.
        if (rxact.handlesPostTerminationWork() && undoPage.isOverflowPage() && undoPage.recordCount() == 0) {
            ReclaimSpace work = new ReclaimSpace(ReclaimSpace.PAGE, (PageKey) undoPage.getIdentity(), rxact.getDataFactory(), true);
            rxact.addPostTerminationWork(work);
        }
    } else {
        undoPage.setDeleteStatus(CLRInstant, slot, true);
        if (rxact.handlesPostTerminationWork() && !undoPage.isOverflowPage()) {
            if (undoPage.shouldReclaimSpace(undoPage.getPageNumber() == 1 ? 1 : 0, slot)) {
                ((BaseDataFileFactory) rxact.getDataFactory()).insertUndoNotify(rxact, undoPage.getPageKey());
            }
        }
    }
    undoPage.setAuxObject(null);
}
Also used : RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction)

Example 37 with RawTransaction

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

the class LogicalPageOperation method generateUndo.

/**
 *		Undoable method
 */
/**
 *		Generate a Compensation (PageUndoOperation) that will rollback the
 *		changes of this page operation. If this Page operation cannot or need not
 *		be rolled back (redo only), overwrite this function to return null.
 *
 *		@see LogicalUndo
 *		@exception StandardException Standard Derby policy.
 *		@exception IOException Method may read from ObjectInput
 */
public Compensation generateUndo(Transaction xact, LimitObjectInput in) throws StandardException, IOException {
    // if logical undo is not necessary, use normal physical undo
    if (undo == null) {
        BasePage undoPage = findpage(xact);
        // Needs to pre-dirty this page so that if a checkpoint is taken
        // any time after the CLR is sent to the log stream, it will wait
        // for the actual undo to happen on the page.  We need this to
        // preserve the integrity of the redoLWM.
        undoPage.preDirty();
        return new LogicalUndoOperation(undoPage, recordId, this);
    } else {
        if (SanityManager.DEBUG) {
            // Sanity check to make sure logical undo is not called inside
            // internal transaction
            RawTransaction rtran = (RawTransaction) xact;
            rtran.checkLogicalOperationOk();
        }
        BasePage logicalUndoPage = findLogicalPage(xact, undo, in);
        // Needs to pre-dirty this page so that if a checkpoint is taken
        // any time after the CLR is sent to the log stream, it will wait
        // for the actual undo to happen on the page.  We need this to
        // preserve the integrity of the redoLWM.
        logicalUndoPage.preDirty();
        // undo.findUndo is not called.
        return new LogicalUndoOperation(logicalUndoPage, recordId, this);
    }
}
Also used : RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction)

Example 38 with RawTransaction

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

the class XactFactory method rollbackAllTransactions.

/**
 *		Rollback all active transactions that has updated the raw store.
 *		Use the recovery Transaction that is passed in to do all the work.
 *		Used in recovery only.
 *
 *		<P>
 *		Transactions are rolled back in the following order:
 *		<OL>
 *		<LI>internal transactions in reversed beginXact chronological order,
 *		<LI>all other transactions in reversed beginXact chronological order,
 *		</NL>
 *
 *		@param recoveryTransaction use this transaction to do all the user
 *                                   transaction work
 *
 *		@exception StandardException any exception thrown during rollback
 */
public void rollbackAllTransactions(RawTransaction recoveryTransaction, RawStoreFactory rsf) throws StandardException {
    if (SanityManager.DEBUG) {
        if (rawStoreFactory != null)
            SanityManager.ASSERT(rawStoreFactory == rsf, "raw store factory different");
        SanityManager.ASSERT(recoveryTransaction != null, "recovery transaction null");
    }
    int irbcount = 0;
    // First undo internal transactions if there is any
    if (ttab.hasRollbackFirstTransaction()) {
        RawTransaction internalTransaction = startInternalTransaction(rsf, recoveryTransaction.getContextManager());
        // make this transaction be aware that it is being used by recovery
        internalTransaction.recoveryTransaction();
        if (SanityManager.DEBUG)
            SanityManager.ASSERT(internalTransaction.handlesPostTerminationWork() == false, "internal recovery xact handles post termination work");
        while (ttab.getMostRecentRollbackFirstTransaction(internalTransaction)) {
            irbcount++;
            internalTransaction.abort();
        }
        internalTransaction.close();
    }
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(ttab.hasRollbackFirstTransaction() == false, "cant rollback user xacts with existing active internal xacts");
    }
    int rbcount = 0;
    // recoveryTransacion assumes the identity of the most recent xact
    while (ttab.getMostRecentTransactionForRollback(recoveryTransaction)) {
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(recoveryTransaction.handlesPostTerminationWork() == false, "recovery transaction handles post termination work");
        }
        rbcount++;
        recoveryTransaction.abort();
    }
    if (SanityManager.DEBUG) {
        if (rbcount > 0 || irbcount > 0) {
        // RESOLVE: put this in the log trace
        // System.out.println(
        // "Recovery rolled back " + irbcount +
        // " internal transactions,"
        // + rbcount + " user transactions");
        }
    }
}
Also used : RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction)

Example 39 with RawTransaction

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

the class StoredPage method logRecordDataPortion.

private void logRecordDataPortion(int slot, int flag, StoredRecordHeader recordHeader, FormatableBitSet validColumns, OutputStream out, RecordHandle headRowHandle) throws StandardException, IOException {
    int offset = getRecordOffset(slot);
    // now skip over the original header before writing the data
    int oldHeaderLength = recordHeader.size();
    offset += oldHeaderLength;
    // write out the record data (FH+data+...) from the page data
    int startField = recordHeader.getFirstField();
    int endField = startField + recordHeader.getNumberFields();
    int validColumnsSize = (validColumns == null) ? 0 : validColumns.getLength();
    for (int fieldId = startField; fieldId < endField; fieldId++) {
        rawDataIn.setPosition(offset);
        // get the field header information from the page
        int fieldStatus = StoredFieldHeader.readStatus(rawDataIn);
        int fieldDataLength = StoredFieldHeader.readFieldDataLength(rawDataIn, fieldStatus, slotFieldSize);
        // for purges unless the field is  overflow pointer for a long column.
        if (((validColumns != null) && !(validColumnsSize > fieldId && validColumns.isSet(fieldId))) || ((flag & BasePage.LOG_RECORD_FOR_PURGE) != 0 && !StoredFieldHeader.isOverflow(fieldStatus))) {
            // nope, move page offset along
            offset += StoredFieldHeader.size(fieldStatus, fieldDataLength, slotFieldSize);
            offset += fieldDataLength;
            // write a non-existent field
            fieldStatus = StoredFieldHeader.setInitial();
            fieldStatus = StoredFieldHeader.setNonexistent(fieldStatus);
            StoredFieldHeader.write(out, fieldStatus, 0, slotFieldSize);
            continue;
        }
        // If temp container, don't do anything.
        if (((flag & BasePage.LOG_RECORD_FOR_UPDATE) != 0) && headRowHandle != null && StoredFieldHeader.isOverflow(fieldStatus) && owner.isTemporaryContainer() == false) {
            // remember the page offset
            int saveOffset = rawDataIn.getPosition();
            long overflowPage = CompressedNumber.readLong((InputStream) rawDataIn);
            int overflowId = CompressedNumber.readInt((InputStream) rawDataIn);
            // Remember the time stamp on the first page of the column
            // chain.  This is to prevent the case where the post commit
            // work gets fired twice, in that case, the second time it is
            // fired, this overflow page may not part of this row chain
            // that is being updated.
            Page firstPageOnColumnChain = getOverflowPage(overflowPage);
            PageTimeStamp ts = firstPageOnColumnChain.currentTimeStamp();
            firstPageOnColumnChain.unlatch();
            RawTransaction rxact = (RawTransaction) owner.getTransaction();
            ReclaimSpace work = new ReclaimSpace(ReclaimSpace.COLUMN_CHAIN, headRowHandle, // long column about to be orphaned by update
            fieldId, // page where the long column starts
            overflowPage, // record Id of the beginning of the long column
            overflowId, ts, rxact.getDataFactory(), true);
            rxact.addPostCommitWork(work);
            // Just to be safe, reset data stream
            rawDataIn.setPosition(saveOffset);
        }
        // write the field header for the log
        offset += StoredFieldHeader.write(out, fieldStatus, fieldDataLength, slotFieldSize);
        if (fieldDataLength != 0) {
            // write the actual data
            out.write(pageData, offset, fieldDataLength);
            offset += fieldDataLength;
        }
    }
}
Also used : PageTimeStamp(org.apache.derby.iapi.store.raw.PageTimeStamp) RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction) Page(org.apache.derby.iapi.store.raw.Page)

Example 40 with RawTransaction

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

the class StoredPage method doUpdateAtSlot.

/**
 *        Perform an update.
 *
 *        @exception StandardException Standard Derby policy
 */
public void doUpdateAtSlot(RawTransaction t, int slot, int id, Object[] row, FormatableBitSet validColumns) throws StandardException {
    // If this is a head page, the recordHandle is the head row handle.
    // If this is not a head page, we are calling updateAtSlot inside some
    // convoluted loop that updates an overflow chain.  There is nothing we
    // can doing about it anyway.
    RecordHandle headRowHandle = isOverflowPage() ? null : getRecordHandleAtSlot(slot);
    // RESOLVE: djd/yyz what does a null row means? (sku)
    if (row == null) {
        owner.getActionSet().actionUpdate(t, this, slot, id, row, validColumns, -1, (DynamicByteArrayOutputStream) null, -1, headRowHandle);
        return;
    }
    // startColumn is the first column to be updated.
    int startColumn = RowUtil.nextColumn(row, validColumns, 0);
    if (startColumn == -1)
        return;
    if (SanityManager.DEBUG) {
        // exactly N columns are passed in via the row array.
        if (!isOverflowPage() && validColumns != null) {
            if (RowUtil.getNumberOfColumns(-1, validColumns) > row.length)
                SanityManager.THROWASSERT("updating slot " + slot + " on page " + getIdentity() + " " + RowUtil.getNumberOfColumns(-1, validColumns) + " bits are set in validColumns but only " + row.length + " columns in row[]");
        }
    }
    // Keep track of row shrinkage in the head row piece.  If any row piece
    // shrinks, file a post commit work to clear all reserved space for the
    // entire row chain.
    boolean rowHasReservedSpace = false;
    StoredPage curPage = this;
    for (; ; ) {
        StoredRecordHeader rh = curPage.getHeaderAtSlot(slot);
        int startField = rh.getFirstField();
        int endFieldExclusive = startField + rh.getNumberFields();
        // curPage contains column[startField] to column[endFieldExclusive-1]
        // Need to cope with an update that is increasing the number of
        // columns.  If this occurs we want to make sure that we perform a
        // single update to the last portion of a record, and not an update
        // of the current columns and then an update to append a column.
        long nextPage = -1;
        int realStartColumn = -1;
        int realSpaceOnPage = -1;
        if (!rh.hasOverflow() || ((startColumn >= startField) && (startColumn < endFieldExclusive))) {
            boolean hitLongColumn;
            int nextColumn = -1;
            Object[] savedFields = null;
            DynamicByteArrayOutputStream logBuffer = null;
            do {
                try {
                    // Update this portion of the record.
                    // Pass in headRowHandle in case we are to update any
                    // long column and they need to be cleaned up by post
                    // commit processing.  We don't want to purge the
                    // columns right now because in order to reclaim the
                    // page, we need to remove them.  But it would be bad
                    // to remove them now because the transaction may not
                    // commit for a long time.  We can do both purging of
                    // the long column and page removal together in the
                    // post commit.
                    nextColumn = owner.getActionSet().actionUpdate(t, curPage, slot, id, row, validColumns, realStartColumn, logBuffer, realSpaceOnPage, headRowHandle);
                    hitLongColumn = false;
                } catch (LongColumnException lce) {
                    if (lce.getRealSpaceOnPage() == -1) {
                        // an update that has caused the row to increase
                        // in size *and* push some fields off the page
                        // that need to be inserted in an overflow page
                        // no need to make a copy as we are going to use
                        // this buffer right away
                        logBuffer = lce.getLogBuffer();
                        savedFields = (Object[]) lce.getColumn();
                        realStartColumn = lce.getNextColumn();
                        realSpaceOnPage = -1;
                        hitLongColumn = true;
                        continue;
                    }
                    // we caught a real long column exception
                    // three things should happen here:
                    // 1. insert the long column into overflow pages.
                    // 2. append the overflow field header in the main chain.
                    // 3. continue the update in the main data chain.
                    logBuffer = new DynamicByteArrayOutputStream(lce.getLogBuffer());
                    // step 1: insert the long column ... if this update
                    // operation rolls back, purge the after image column
                    // chain and reclaim the overflow page because the
                    // whole chain will be orphaned anyway.
                    RecordHandle longColumnHandle = insertLongColumn(curPage, lce, Page.INSERT_UNDO_WITH_PURGE);
                    // step 2: append overflow field header to log buffer
                    int overflowFieldLen = 0;
                    try {
                        overflowFieldLen += appendOverflowFieldHeader(logBuffer, longColumnHandle);
                    } catch (IOException ioe) {
                        throw StandardException.newException(SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);
                    }
                    // step 3: continue the insert in the main data chain
                    // need to pass the log buffer, and start column to the
                    // next insert.
                    realStartColumn = lce.getNextColumn() + 1;
                    realSpaceOnPage = lce.getRealSpaceOnPage() - overflowFieldLen;
                    hitLongColumn = true;
                } catch (NoSpaceOnPage nsop) {
                    throw StandardException.newException(SQLState.DATA_UNEXPECTED_NO_SPACE_ON_PAGE, nsop, ((PageKey) curPage.getIdentity()).toString(), getPageDumpString(), slot, id, validColumns.toString(), realStartColumn, 0, headRowHandle);
                }
            } while (hitLongColumn);
            // See if we completed all the columns that are on this page.
            int validColumnsSize = (validColumns == null) ? 0 : validColumns.getLength();
            if (nextColumn != -1) {
                if (SanityManager.DEBUG) {
                    if ((nextColumn < startField) || (rh.hasOverflow() && (nextColumn >= endFieldExclusive))) {
                        SanityManager.THROWASSERT("nextColumn out of range = " + nextColumn + " expected between " + startField + " and " + endFieldExclusive);
                    }
                }
                // Need to insert rows from nextColumn to endFieldExclusive
                // onto a new overflow page.
                // If the column is not being updated we
                // pick it up from the current page. If it is being updated
                // we take it from the new value.
                int possibleLastFieldExclusive = endFieldExclusive;
                if (!rh.hasOverflow()) {
                    // we might be adding a field here
                    if (validColumns == null) {
                        if (row.length > possibleLastFieldExclusive)
                            possibleLastFieldExclusive = row.length;
                    } else {
                        if (validColumnsSize > possibleLastFieldExclusive)
                            possibleLastFieldExclusive = validColumnsSize;
                    }
                }
                // use a sparse row
                Object[] newRow = new Object[possibleLastFieldExclusive];
                FormatableBitSet newColumnList = new FormatableBitSet(possibleLastFieldExclusive);
                ByteArrayOutputStream fieldStream = null;
                for (int i = nextColumn; i < possibleLastFieldExclusive; i++) {
                    if ((validColumns == null) || (validColumnsSize > i && validColumns.isSet(i))) {
                        newColumnList.set(i);
                        // use the new value
                        newRow[i] = RowUtil.getColumn(row, validColumns, i);
                    } else if (i < endFieldExclusive) {
                        newColumnList.set(i);
                        // use the old value
                        newRow[i] = savedFields[i - nextColumn];
                    }
                }
                RecordHandle handle = curPage.getRecordHandleAtSlot(slot);
                // there cannot be any updates to do.
                if (rh.hasOverflow()) {
                    // We have to carry across the overflow information
                    // from the current record, if any.
                    nextPage = rh.getOverflowPage();
                    id = rh.getOverflowId();
                    // find the next starting column before unlatching page
                    startColumn = RowUtil.nextColumn(row, validColumns, endFieldExclusive);
                } else {
                    startColumn = -1;
                    nextPage = 0;
                }
                // Don't bother with temp container.
                if (!rowHasReservedSpace && headRowHandle != null && curPage != null && !owner.isTemporaryContainer()) {
                    rowHasReservedSpace = curPage.checkRowReservedSpace(slot);
                }
                // insert the record portion on a new overflow page at slot
                // 0 this will automatically handle any overflows in
                // this new portion
                // BasePage op = getNewOverflowPage();
                BasePage op = curPage.getOverflowPageForInsert(slot, newRow, newColumnList, nextColumn);
                // We have all the information from this page so unlatch it
                if (curPage != this) {
                    curPage.unlatch();
                    curPage = null;
                }
                byte mode = Page.INSERT_OVERFLOW;
                if (nextPage != 0)
                    mode |= Page.INSERT_FOR_SPLIT;
                RecordHandle nextPortionHandle = nextPage == 0 ? null : owner.makeRecordHandle(nextPage, id);
                // RESOLVED (sku):  even though we would like to roll back
                // these inserts with PURGE rather than with delete,
                // we have to delete because if we purge the last row
                // from an overflow page, the purge will queue a post
                // commit to remove the page.
                // While this is OK with long columns, we cannot do this
                // for long rows because long row overflow pages can be
                // shared by more than one long rows, and thus it is unsafe
                // to remove the page without first latching the head page.
                // However, the insert log record do not have the head
                // row's page number so the rollback cannot put that
                // information into the post commit work.
                RecordHandle portionHandle;
                try {
                    portionHandle = op.insertAllowOverflow(0, newRow, newColumnList, nextColumn, mode, 100, nextPortionHandle);
                } catch (NoSpaceOnPage nsop) {
                    throw StandardException.newException(SQLState.DATA_UNEXPECTED_NO_SPACE_ON_PAGE, nsop, ((PageKey) op.getIdentity()).toString(), getPageDumpString(), slot, id, newColumnList.toString(), nextColumn, mode, nextPortionHandle);
                }
                // Update the previous record header to point to new portion
                if (curPage == this)
                    updateOverflowDetails(this, handle, portionHandle);
                else
                    updateOverflowDetails(handle, portionHandle);
                op.unlatch();
            } else {
                // See earlier comments on checking row reserved space.
                if (!rowHasReservedSpace && headRowHandle != null && curPage != null && !owner.isTemporaryContainer()) {
                    rowHasReservedSpace = curPage.checkRowReservedSpace(slot);
                }
                // find the next starting column before we unlatch the page
                startColumn = rh.hasOverflow() ? RowUtil.nextColumn(row, validColumns, endFieldExclusive) : -1;
            }
            // have we completed this update?
            if (startColumn == -1) {
                if ((curPage != this) && (curPage != null))
                    curPage.unlatch();
                // break out of the for loop
                break;
            }
        }
        if (nextPage == -1) {
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT(curPage != null, "Current page is null be no overflow information has been obtained");
            }
            // Get the next page info while we still have the page
            // latched.
            nextPage = rh.getOverflowPage();
            id = rh.getOverflowId();
        }
        if ((curPage != this) && (curPage != null))
            curPage.unlatch();
        // get the next portion page and find the correct slot
        curPage = (StoredPage) owner.getPage(nextPage);
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(curPage.isOverflowPage(), "following row chain gets a non-overflow page");
        }
        slot = curPage.findRecordById(id, FIRST_SLOT_NUMBER);
    }
    // row post commit.
    if (rowHasReservedSpace) {
        RawTransaction rxact = (RawTransaction) owner.getTransaction();
        ReclaimSpace work = new ReclaimSpace(ReclaimSpace.ROW_RESERVE, headRowHandle, rxact.getDataFactory(), true);
        rxact.addPostCommitWork(work);
    }
}
Also used : PageKey(org.apache.derby.iapi.store.raw.PageKey) DynamicByteArrayOutputStream(org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream) RecordHandle(org.apache.derby.iapi.store.raw.RecordHandle) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) DynamicByteArrayOutputStream(org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream) RawTransaction(org.apache.derby.iapi.store.raw.xact.RawTransaction) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet)

Aggregations

RawTransaction (org.apache.derby.iapi.store.raw.xact.RawTransaction)40 RecordHandle (org.apache.derby.iapi.store.raw.RecordHandle)10 LockingPolicy (org.apache.derby.iapi.store.raw.LockingPolicy)6 PageKey (org.apache.derby.iapi.store.raw.PageKey)6 StandardException (org.apache.derby.shared.common.error.StandardException)6 ContextManager (org.apache.derby.iapi.services.context.ContextManager)5 StorageFile (org.apache.derby.io.StorageFile)5 IOException (java.io.IOException)4 DynamicByteArrayOutputStream (org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream)3 RawContainerHandle (org.apache.derby.iapi.store.raw.data.RawContainerHandle)3 Serviceable (org.apache.derby.iapi.services.daemon.Serviceable)2 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)2 CompatibilitySpace (org.apache.derby.iapi.services.locks.CompatibilitySpace)2 LogicalUndo (org.apache.derby.iapi.store.access.conglomerate.LogicalUndo)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 File (java.io.File)1 OutputStream (java.io.OutputStream)1 MalformedURLException (java.net.MalformedURLException)1 URL (java.net.URL)1 Properties (java.util.Properties)1