Search in sources :

Example 1 with TransactionId

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

the class Scan method getNextRecordBackward.

/**
 *		Read the previous log record.
 *		Switching log to a previous log file if necessary,
 *		Resize the input stream byte array if necessary.
 *		@see StreamLogScan#getNextRecord
 *
 *		Side effects include:
 *				on a successful read, setting currentInstant.
 *				on a log file switch, setting currentLogFileNumber.
 *
 *		@return the previous LogRecord, or null if the end of the
 *		scan has been reached.
 */
private LogRecord getNextRecordBackward(ArrayInputStream input, TransactionId tranId, int groupmask) throws StandardException, IOException, ClassNotFoundException {
    if (SanityManager.DEBUG)
        SanityManager.ASSERT(scanDirection == BACKWARD, "can only called by backward scan");
    // scan is positioned just past the last byte of the record, or
    // right at the beginning of the file (end of the file header)
    // may need to switch log file
    boolean candidate;
    // if we have filtering, peek at the group and/or the transaction id,
    // do them in one read rather than 2 reads.
    int peekAmount = LogRecord.formatOverhead() + LogRecord.maxGroupStoredSize();
    if (tranId != null)
        peekAmount += LogRecord.maxTransactionIdStoredSize(tranId);
    // the number of bytes actually read
    int readAmount;
    LogRecord lr;
    long curpos = scan.getFilePointer();
    do {
        // this log record is a candidate unless proven otherwise
        candidate = true;
        lr = null;
        readAmount = -1;
        if (curpos == LogToFile.LOG_FILE_HEADER_SIZE) {
            // will have gone past stopAt
            if (stopAt != LogCounter.INVALID_LOG_INSTANT && LogCounter.getLogFileNumber(stopAt) == currentLogFileNumber) {
                if (SanityManager.DEBUG) {
                    if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) {
                        SanityManager.DEBUG(LogToFile.DBG_FLAG, "stopping at " + currentLogFileNumber);
                    }
                }
                // no more log record
                return null;
            }
            // figure out where the last log record is in the previous
            // log file
            scan.seek(LogToFile.LOG_FILE_HEADER_PREVIOUS_LOG_INSTANT_OFFSET);
            long previousLogInstant = scan.readLong();
            scan.close();
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT(previousLogInstant != LogCounter.INVALID_LOG_INSTANT, "scanning backward beyond the first log file");
                if (currentLogFileNumber != LogCounter.getLogFileNumber(previousLogInstant) + 1)
                    SanityManager.THROWASSERT("scanning backward but get incorrect log file number " + "expected " + (currentLogFileNumber - 1) + "get " + LogCounter.getLogFileNumber(previousLogInstant));
                SanityManager.ASSERT(LogCounter.getLogFilePosition(previousLogInstant) > LogToFile.LOG_FILE_HEADER_SIZE, "scanning backward encounter completely empty log file");
                SanityManager.DEBUG(LogToFile.DBG_FLAG, "scanning backwards from log file " + currentLogFileNumber + ", switch to (" + LogCounter.getLogFileNumber(previousLogInstant) + "," + LogCounter.getLogFilePosition(previousLogInstant) + ")");
            }
            // log file switch, set this.currentLogFileNumber
            currentLogFileNumber = LogCounter.getLogFileNumber(previousLogInstant);
            scan = logFactory.getLogFileAtPosition(previousLogInstant);
            // scan is located right past the last byte of the last log
            // record in the previous log file.  currentLogFileNumber is
            // set.  We asserted that the scan is not located right at the
            // end of the file header, in other words, there is at least
            // one log record in this log file.
            curpos = scan.getFilePointer();
            // happens to avoid any recovery issues.
            if (curpos == LogToFile.LOG_FILE_HEADER_SIZE)
                continue;
        }
        scan.seek(curpos - 4);
        // get the length after the log record
        int recordLength = scan.readInt();
        // calculate where this log record started.
        // include the eight bytes for the long log instant at the front
        // the four bytes of length in the front and the four bytes we just read
        long recordStartPosition = curpos - recordLength - LogToFile.LOG_RECORD_OVERHEAD;
        if (SanityManager.DEBUG) {
            if (recordStartPosition < LogToFile.LOG_FILE_HEADER_SIZE)
                SanityManager.THROWASSERT("next position " + recordStartPosition + " recordLength " + recordLength + " current file position " + scan.getFilePointer());
            scan.seek(recordStartPosition);
            // read the length before the log record and check it against the
            // length after the log record
            int checkLength = scan.readInt();
            if (checkLength != recordLength) {
                long inst = LogCounter.makeLogInstantAsLong(currentLogFileNumber, recordStartPosition);
                throw logFactory.markCorrupt(StandardException.newException(SQLState.LOG_RECORD_CORRUPTED, checkLength, recordLength, inst, currentLogFileNumber));
            }
        } else {
            // skip over the length in insane
            scan.seek(recordStartPosition + 4);
        }
        // scan is positioned just before the log instant
        // read the current log instant - this is the currentInstant if we have not
        // exceeded the scan limit
        currentInstant = scan.readLong();
        if (SanityManager.DEBUG) {
            // sanity check the current instant against the scan position
            if (LogCounter.getLogFileNumber(currentInstant) != currentLogFileNumber || LogCounter.getLogFilePosition(currentInstant) != recordStartPosition)
                SanityManager.THROWASSERT("Wrong LogInstant on log record " + LogCounter.toDebugString(currentInstant) + " version real position (" + currentLogFileNumber + "," + recordStartPosition + ")");
        }
        // nothing more can be read.  Else check scan limit
        if (currentInstant < stopAt && stopAt != LogCounter.INVALID_LOG_INSTANT) {
            currentInstant = LogCounter.INVALID_LOG_INSTANT;
            // we went past the stopAt
            return null;
        }
        byte[] data = input.getData();
        if (data.length < recordLength) {
            // make a new array of sufficient size and reset the arrary
            // in the input stream
            data = new byte[recordLength];
            input.setData(data);
        }
        // and decrypting the record.
        if (logFactory.databaseEncrypted()) {
            scan.readFully(data, 0, recordLength);
            int len = logFactory.decrypt(data, 0, recordLength, data, 0);
            if (SanityManager.DEBUG)
                SanityManager.ASSERT(len == recordLength);
            input.setLimit(0, recordLength);
        } else // no need to decrypt, only get the group and tid if we filter
        {
            if (groupmask == 0 && tranId == null) {
                // no filter, get the whole thing
                scan.readFully(data, 0, recordLength);
                input.setLimit(0, recordLength);
            } else {
                // Read only enough so that group and the tran id is in
                // the data buffer.  Group is stored as compressed int
                // and tran id is stored as who knows what.  read min
                // of peekAmount or recordLength
                readAmount = (recordLength > peekAmount) ? peekAmount : recordLength;
                // in the data buffer, we now have enough to peek
                scan.readFully(data, 0, readAmount);
                input.setLimit(0, readAmount);
            }
        }
        lr = (LogRecord) input.readObject();
        // during backward scans. They are used only in forwardscan during recovery.
        if (lr.isChecksum()) {
            candidate = false;
        } else if (groupmask != 0 || tranId != null) {
            // skip the checksum log records
            if (lr.isChecksum())
                candidate = false;
            if (candidate && groupmask != 0 && (groupmask & lr.group()) == 0)
                // no match, throw this log record out
                candidate = false;
            if (candidate && tranId != null) {
                TransactionId tid = lr.getTransactionId();
                if (// nomatch
                !tid.equals(tranId))
                    // throw this log record out
                    candidate = false;
            }
            // decryption.
            if (candidate && !logFactory.databaseEncrypted()) {
                // read the rest of the log into the buffer
                if (SanityManager.DEBUG)
                    SanityManager.ASSERT(readAmount > 0);
                if (readAmount < recordLength) {
                    // Need to remember where we are because the log
                    // record may have read part of it off the input
                    // stream already and that position is lost when we
                    // set limit again.
                    int inputPosition = input.getPosition();
                    scan.readFully(data, readAmount, recordLength - readAmount);
                    input.setLimit(0, recordLength);
                    input.setPosition(inputPosition);
                }
            }
        }
        // go back to the start of the log record so that the next time
        // this method is called, it is positioned right past the last byte
        // of the record.
        curpos = recordStartPosition;
        scan.seek(curpos);
    } while (candidate == false);
    return lr;
}
Also used : LogRecord(org.apache.derby.impl.store.raw.log.LogRecord) TransactionId(org.apache.derby.iapi.store.raw.xact.TransactionId)

Example 2 with TransactionId

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

the class FileLogger method logAndUndo.

/**
 *		Writes out a compensation log record to the log stream, and call its
 *		doMe method to undo the change of a previous log operation.
 *
 *		<P>MT - Not needed. A transaction must be single threaded thru undo, each
 *		RawTransaction has its own logger, therefore no need to synchronize.
 *		The RawTransaction must handle synchronizing with multiple threads
 *		during rollback.
 *
 *		@param xact the transaction logging the change
 *		@param compensation the compensation log operation
 *		@param undoInstant the log instant of the operation that is to be
 *		rolled back
 *		@param in optional data input for the compenastion doMe method
 *
 *		@return the instant in the log that can be used to identify the log
 *		record
 *
 *		@exception StandardException Derby Standard error policy
 */
public LogInstant logAndUndo(RawTransaction xact, Compensation compensation, LogInstant undoInstant, LimitObjectInput in) throws StandardException {
    boolean inUserCode = false;
    try {
        logOutputBuffer.reset();
        TransactionId transactionId = xact.getId();
        // write out the log header with the operation embedded
        logRecord.setValue(transactionId, compensation);
        inUserCode = true;
        logicalOut.writeObject(logRecord);
        inUserCode = false;
        // write out the undoInstant
        logicalOut.writeLong(((LogCounter) undoInstant).getValueAsLong());
        // in this implemetaion, there is no optional data for the
        // compensation operation.  Optional data for the rollback comes
        // from the undoable operation - and is passed into this call.
        int completeLength = logOutputBuffer.getPosition();
        long instant = 0;
        if (logFactory.databaseEncrypted()) {
            // we must pad the encryption data to be multiple of block
            // size, which is logFactory.getEncryptionBlockSize()
            int encryptedLength = completeLength;
            if ((encryptedLength % logFactory.getEncryptionBlockSize()) != 0)
                encryptedLength = encryptedLength + logFactory.getEncryptionBlockSize() - (encryptedLength % logFactory.getEncryptionBlockSize());
            if (encryptionBuffer == null || encryptionBuffer.length < encryptedLength)
                encryptionBuffer = new byte[encryptedLength];
            System.arraycopy(logOutputBuffer.getByteArray(), 0, encryptionBuffer, 0, completeLength);
            // do not bother to clear out the padding area
            int len = logFactory.encrypt(encryptionBuffer, 0, encryptedLength, encryptionBuffer, 0);
            if (SanityManager.DEBUG)
                SanityManager.ASSERT(len == encryptedLength, "encrypted log buffer length != log buffer len");
            instant = logFactory.appendLogRecord(encryptionBuffer, 0, encryptedLength, null, 0, 0);
        } else {
            instant = logFactory.appendLogRecord(logOutputBuffer.getByteArray(), 0, completeLength, null, 0, 0);
        }
        LogInstant logInstant = new LogCounter(instant);
        if (SanityManager.DEBUG) {
            if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) {
                SanityManager.DEBUG(LogToFile.DBG_FLAG, "Write CLR: Xact: " + transactionId.toString() + "clrinstant: " + logInstant.toString() + " undoinstant " + undoInstant + "\n");
            }
        }
        try {
            // in and dataLength contains optional data that was written
            // to the log during a previous call to logAndDo.
            compensation.doMe(xact, logInstant, in);
        } catch (StandardException se) {
            throw logFactory.markCorrupt(StandardException.newException(SQLState.LOG_DO_ME_FAIL, se, compensation));
        } catch (IOException ioe) {
            throw logFactory.markCorrupt(StandardException.newException(SQLState.LOG_DO_ME_FAIL, ioe, compensation));
        }
        return logInstant;
    } catch (IOException ioe) {
        if (inUserCode) {
            throw StandardException.newException(SQLState.LOG_WRITE_LOG_RECORD, ioe, compensation);
        } else {
            throw StandardException.newException(SQLState.LOG_BUFFER_FULL, ioe, compensation);
        }
    }
}
Also used : StandardException(org.apache.derby.shared.common.error.StandardException) LogInstant(org.apache.derby.iapi.store.raw.log.LogInstant) LogCounter(org.apache.derby.impl.store.raw.log.LogCounter) IOException(java.io.IOException) TransactionId(org.apache.derby.iapi.store.raw.xact.TransactionId)

Example 3 with TransactionId

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

the class TransactionTable method getMostRecentPreparedRecoveredXact.

/**
 *		Get the most recently added transaction that says it is prepared during
 *        recovery the transaction table and make the passed in transaction
 *        assume its identity. This routine turns off the isRecovery() state
 *		<B> Should only be used in recovery handle prepare after undo !! </B>
 *
 *		<P>MT - unsafe, caller is recovery, which is single threaded.
 */
/**
 * Get the most recent recovered prepared transaction.
 * <p>
 * Get the most recently added transaction that says it is prepared during
 * recovery the transaction table and make the passed in transaction
 * assume its identity.
 * <p>
 * This routine, unlike the redo and rollback getMostRecent*() routines
 * expects a brand new transaction to be passed in.  If a candidate
 * transaction is found, then upon return the transaction table will
 * be altered such that the old entry no longer exists, and a new entry
 * will exist pointing to the transaction passed in.  The new entry will
 * look the same as if the prepared transaction had been created during
 * runtime rather than recovery.
 *
 * <B> Should only be used in recovery handle prepare after undo !! </B>
 *
 * <P>MT - unsafe, caller is recovery, which is single threaded.
 *
 * @return true if a candidate transaction has been found.  false if no
 *         prepared/recovery transactions found in the table.
 *
 * @param tran   Newly allocated transaction to add to link to a entry.
 */
public boolean getMostRecentPreparedRecoveredXact(RawTransaction tran) {
    TransactionTableEntry found_ent = null;
    if (!trans.isEmpty()) {
        TransactionId id = null;
        GlobalTransactionId gid = null;
        for (TransactionTableEntry ent : trans.values()) {
            if (ent != null && ent.isRecovery() && ent.isPrepared()) {
                // try to locate the most recent one
                if (id == null || XactId.compare(id, ent.getXid()) < 0) {
                    found_ent = ent;
                    id = ent.getXid();
                    gid = ent.getGid();
                }
            }
        }
        if (SanityManager.DEBUG) {
            if (found_ent == null) {
                // be non-recover, prepared global transactions.
                for (TransactionTableEntry ent : trans.values()) {
                    if (XactId.compare(ent.getXid(), tran.getId()) != 0) {
                        SanityManager.ASSERT(!ent.isRecovery() && ent.isPrepared());
                        SanityManager.ASSERT(ent.getGid() != null);
                    }
                }
            }
        }
        if (found_ent != null) {
            // At this point there are 2 tt entries of interest:
            // new_ent - the read only transaction entry that was
            // created when we allocated a new transaction.
            // We will just throw this one away after
            // assuming the identity of the global xact.
            // found_ent
            // - the entry of the transaction that we are going
            // to take over.
            TransactionTableEntry new_ent = trans.remove(tran.getId());
            // At this point only the found_ent should be in the table.
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT(findTransactionEntry(id) == found_ent);
            }
            ((Xact) tran).assumeGlobalXactIdentity(found_ent);
            // transform this recovery entry, into a runtime entry.
            found_ent.unsetRecoveryStatus();
        }
    }
    return (found_ent != null);
}
Also used : GlobalTransactionId(org.apache.derby.iapi.store.raw.GlobalTransactionId) GlobalTransactionId(org.apache.derby.iapi.store.raw.GlobalTransactionId) TransactionId(org.apache.derby.iapi.store.raw.xact.TransactionId)

Example 4 with TransactionId

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

the class TransactionTable method add.

void add(Xact xact, boolean exclude) {
    TransactionId id = xact.getId();
    TransactionTableEntry newEntry = new TransactionTableEntry(xact, id, 0, exclude ? TransactionTableEntry.EXCLUDE : 0);
    synchronized (this) {
        Object oldEntry = trans.put(id, newEntry);
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(oldEntry == null, "Trying to add a transaction that's already " + "in the transaction table");
            if (SanityManager.DEBUG_ON("TranTrace")) {
                SanityManager.DEBUG("TranTrace", "adding transaction " + id);
                SanityManager.showTrace(new Throwable("TranTrace"));
            }
        }
    }
    if (SanityManager.DEBUG) {
        if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
            if (trans.size() > 50)
                System.out.println("memoryLeakTrace:TransactionTable " + trans.size());
        }
    }
}
Also used : GlobalTransactionId(org.apache.derby.iapi.store.raw.GlobalTransactionId) TransactionId(org.apache.derby.iapi.store.raw.xact.TransactionId)

Example 5 with TransactionId

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

the class TransactionTableEntry method getTransactionIdString.

/**
 *		Methods of TransactionInfo
 */
public String getTransactionIdString() {
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(!recovery, "trying to display recovery transaction");
        SanityManager.ASSERT(myxact != null, "my xact is null");
        SanityManager.ASSERT(isClone, "Should only call method on a clone");
    }
    TransactionId t = myxact.getIdNoCheck();
    return (t == null) ? "CLOSED" : t.toString();
}
Also used : GlobalTransactionId(org.apache.derby.iapi.store.raw.GlobalTransactionId) TransactionId(org.apache.derby.iapi.store.raw.xact.TransactionId)

Aggregations

TransactionId (org.apache.derby.iapi.store.raw.xact.TransactionId)9 LogRecord (org.apache.derby.impl.store.raw.log.LogRecord)4 IOException (java.io.IOException)3 GlobalTransactionId (org.apache.derby.iapi.store.raw.GlobalTransactionId)3 LogCounter (org.apache.derby.impl.store.raw.log.LogCounter)3 StandardException (org.apache.derby.shared.common.error.StandardException)3 Loggable (org.apache.derby.iapi.store.raw.Loggable)2 LogInstant (org.apache.derby.iapi.store.raw.log.LogInstant)2 Compensation (org.apache.derby.iapi.store.raw.Compensation)1 Undoable (org.apache.derby.iapi.store.raw.Undoable)1 ByteArray (org.apache.derby.iapi.util.ByteArray)1 StreamLogScan (org.apache.derby.impl.store.raw.log.StreamLogScan)1