Search in sources :

Example 11 with StorageRandomAccessFile

use of org.apache.derby.io.StorageRandomAccessFile in project derby by apache.

the class LogToFile method initializeReplicationSlaveRole.

/**
 * Initializes logOut so that log received from the replication
 * master can be appended to the log file.
 *
 * Normally, logOut (the file log records are appended to) is set
 * up as part of the recovery process. When the database is booted
 * in replication slave mode, however, recovery will not get to
 * the point where logOut is initialized until this database is no
 * longer in slave mode. Since logOut is needed to append log
 * records received from the master, logOut needs to be set up for
 * replication slave mode.
 *
 * This method finds the last log record in the log file with the
 * highest number. logOut is set up so that log records will be
 * appended to the end of that file, and the endPosition and
 * lastFlush variables are set to point to the end of the same
 * file. All this is normally done as part of recovery.
 *
 * After the first log file switch resulting from applying log
 * received from the master, recovery will be allowed to read up
 * to, but not including, the current log file which is the file
 * numbered logFileNumber.
 *
 * Note that this method must not be called until LogToFile#boot()
 * has completed. Currently, this is ensured because RawStore#boot
 * starts the SlaveFactory (in turn calling this method) after
 * LogFactory.boot() has completed. Race conditions for
 * logFileNumber may occur if this is changed.
 *
 * @exception StandardException Standard Derby error policy
 */
public void initializeReplicationSlaveRole() throws StandardException {
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(inReplicationSlaveMode, "This method should only be used when" + " in slave replication mode");
    }
    try {
        // Find the log file with the highest file number on disk
        while (getLogFileAtBeginning(logFileNumber + 1) != null) {
            logFileNumber++;
        }
        // Scan the highest log file to find it's end.
        long startInstant = LogCounter.makeLogInstantAsLong(logFileNumber, LOG_FILE_HEADER_SIZE);
        long logEndInstant = LOG_FILE_HEADER_SIZE;
        StreamLogScan scanOfHighestLogFile = (StreamLogScan) openForwardsScan(startInstant, (LogInstant) null);
        ArrayInputStream scanInputStream = new ArrayInputStream();
        while (scanOfHighestLogFile.getNextRecord(scanInputStream, null, 0) != null) {
            logEndInstant = scanOfHighestLogFile.getLogRecordEnd();
        }
        setEndPosition(LogCounter.getLogFilePosition(logEndInstant));
        // endPosition and logFileNumber now point to the end of the
        // highest log file. This is where a new log record should be
        // appended.
        /*
             * Open the highest log file and make sure log records are
             * appended at the end of it
             */
        StorageRandomAccessFile logFile = null;
        if (isWriteSynced) {
            logFile = openLogFileInWriteMode(getLogFileName(logFileNumber));
        } else {
            logFile = privRandomAccessFile(getLogFileName(logFileNumber), "rw");
        }
        logOut = new LogAccessFile(this, logFile, logBufferSize);
        lastFlush = endPosition;
        // append log records at the end of
        logFile.seek(endPosition);
    // the file
    } catch (IOException ioe) {
        throw StandardException.newException(SQLState.REPLICATION_UNEXPECTED_EXCEPTION, ioe);
    }
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) LogInstant(org.apache.derby.iapi.store.raw.log.LogInstant) ByteArrayInputStream(java.io.ByteArrayInputStream) ArrayInputStream(org.apache.derby.iapi.services.io.ArrayInputStream) IOException(java.io.IOException)

Example 12 with StorageRandomAccessFile

use of org.apache.derby.io.StorageRandomAccessFile in project derby by apache.

the class LogToFile method writeControlFile.

/**
 *		Carefully write out this value to the control file.
 *        We do safe write of this data by writing the data
 *        into two files every time we write the control data.
 *        we write checksum at the end of the file, so if by
 *        chance system crashes while writing into the file,
 *        using the checksum we find that the control file
 *        is hosed then we  use the mirror file, which will have
 *        the control data written at last check point.
 *
 *		see comment at beginning of file for log control file format.
 *
 *		<P> MT- synchronized by caller
 */
// When changing this code, also update the comment at the beginning of
// this class, the ControlFileReader of DERBY-5195, and the description
// on the web page in http://db.apache.org/derby/papers/logformats.html
boolean writeControlFile(StorageFile logControlFileName, long value) throws IOException, StandardException {
    StorageRandomAccessFile logControlFile = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
    DataOutputStream daos = new DataOutputStream(baos);
    daos.writeInt(fid);
    // so that when this db is booted by 1.1x and 1.2x JBMS, a IOException
    // stack trace rather than some error message that tells
    // the user to delete the database will show up.
    daos.writeInt(OBSOLETE_LOG_VERSION_NUMBER);
    daos.writeLong(value);
    if (onDiskMajorVersion == 0) {
        onDiskMajorVersion = jbmsVersion.getMajorVersion();
        onDiskMinorVersion = jbmsVersion.getMinorVersion();
        onDiskBeta = jbmsVersion.isBeta();
    }
    // previous to 1.3, that's all we wrote.
    // from 1.3 and onward, also write out the JBMSVersion
    daos.writeInt(onDiskMajorVersion);
    daos.writeInt(onDiskMinorVersion);
    // For 2.0 beta we added the build number and the isBeta indication.
    // (5 bytes from our first spare long)
    daos.writeInt(jbmsVersion.getBuildNumberAsInt());
    byte flags = 0;
    if (onDiskBeta)
        flags |= IS_BETA_FLAG;
    // previously booted at any time in this mode
    if (logNotSynced || wasDBInDurabilityTestModeNoSync)
        flags |= IS_DURABILITY_TESTMODE_NO_SYNC_FLAG;
    daos.writeByte(flags);
    // 
    // write some spare bytes after 2.0 we have 3 + 2(8) spare bytes.
    long spare = 0;
    daos.writeByte(0);
    daos.writeByte(0);
    daos.writeByte(0);
    daos.writeLong(spare);
    daos.flush();
    // write the checksum for the control data written
    checksum.reset();
    checksum.update(baos.toByteArray(), 0, baos.size());
    daos.writeLong(checksum.getValue());
    daos.flush();
    try {
        checkCorrupt();
        try {
            logControlFile = privRandomAccessFile(logControlFileName, "rw");
        } catch (IOException ioe) {
            logControlFile = null;
            return false;
        }
        if (!privCanWrite(logControlFileName))
            return false;
        if (SanityManager.DEBUG) {
            if (SanityManager.DEBUG_ON(TEST_LOG_FULL))
                testLogFull();
        }
        logControlFile.seek(0);
        logControlFile.write(baos.toByteArray());
        syncFile(logControlFile);
        logControlFile.close();
        // write the same data to mirror control file
        try {
            logControlFile = privRandomAccessFile(getMirrorControlFileName(), "rw");
        } catch (IOException ioe) {
            logControlFile = null;
            return false;
        }
        logControlFile.seek(0);
        logControlFile.write(baos.toByteArray());
        syncFile(logControlFile);
    } finally {
        if (logControlFile != null)
            logControlFile.close();
    }
    return true;
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) DataOutputStream(java.io.DataOutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException)

Example 13 with StorageRandomAccessFile

use of org.apache.derby.io.StorageRandomAccessFile in project derby by apache.

the class LogToFile method verifyLogFormat.

/*
	 * Private methods that helps to implement methods of LogFactory
	 */
/**
 *		Verify that we the log file is of the right format and of the right
 *		version and log file number.
 *
 *		<P>MT - not needed, no global variables used
 *
 *		@param logFileName the name of the log file
 *		@param number the log file number
 *		@return true if the log file is of the current version and of the
 *		correct format
 *
 *		@exception StandardException Standard Derby error policy
 */
private boolean verifyLogFormat(StorageFile logFileName, long number) throws StandardException {
    boolean ret = false;
    try {
        StorageRandomAccessFile log = privRandomAccessFile(logFileName, "r");
        ret = verifyLogFormat(log, number);
        log.close();
    } catch (IOException ioe) {
    }
    return ret;
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) IOException(java.io.IOException)

Example 14 with StorageRandomAccessFile

use of org.apache.derby.io.StorageRandomAccessFile in project derby by apache.

the class LogToFile method getLogFileAtPosition.

/**
 *        Get a read-only handle to the log file positioned at the stated position
 *
 *        <P> MT- read only
 *
 *        @return null if file does not exist or of the wrong format
 *        @exception IOException cannot access the log at the new position.
 *        @exception StandardException Standard Derby error policy
 */
protected StorageRandomAccessFile getLogFileAtPosition(long logInstant) throws IOException, StandardException {
    checkCorrupt();
    long filenum = LogCounter.getLogFileNumber(logInstant);
    long filepos = LogCounter.getLogFilePosition(logInstant);
    StorageFile fileName = getLogFileName(filenum);
    if (!privExists(fileName)) {
        if (SanityManager.DEBUG) {
            if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))
                SanityManager.DEBUG(LogToFile.DBG_FLAG, fileName.getPath() + " does not exist");
        }
        return null;
    }
    StorageRandomAccessFile log = null;
    try {
        log = privRandomAccessFile(fileName, "r");
        // verify that the log file is of the right format
        if (!verifyLogFormat(log, filenum)) {
            if (SanityManager.DEBUG) {
                if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))
                    SanityManager.DEBUG(LogToFile.DBG_FLAG, fileName.getPath() + " format mismatch");
            }
            log.close();
            log = null;
        } else {
            log.seek(filepos);
        }
    } catch (IOException ioe) {
        try {
            if (log != null) {
                log.close();
                log = null;
            }
            if (SanityManager.DEBUG) {
                SanityManager.THROWASSERT("cannot get to position " + filepos + " for log file " + fileName.getPath(), ioe);
            }
        } catch (IOException ioe2) {
        }
        throw ioe;
    }
    return log;
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) StorageFile(org.apache.derby.io.StorageFile) IOException(java.io.IOException)

Example 15 with StorageRandomAccessFile

use of org.apache.derby.io.StorageRandomAccessFile in project derby by apache.

the class JCECipherFactory method verifyKey.

/**
 *	    The database can be encrypted with an encryption key given in connection url.
 *	    For security reasons, this key is not made persistent in the database.
 *
 *	    But it is necessary to verify the encryption key when booting the database if it is similar
 *	    to the one used when creating the database
 *	    This needs to happen before we access the data/logs to avoid the risk of corrupting the
 *	    database because of a wrong encryption key.
 *
 *	    This method performs the steps necessary to verify the encryption key if an external
 *	    encryption key is given.
 *
 *	    At database creation, 4k of random data is generated using SecureRandom and MD5 is used
 *	    to compute the checksum for the random data thus generated.  This 4k page of random data
 *	    is then encrypted using the encryption key. The checksum of unencrypted data and
 *	    encrypted data is made persistent in the database in file by name given by
 *	    Attribute.CRYPTO_EXTERNAL_KEY_VERIFYFILE (verifyKey.dat). This file exists directly under the
 *	    database root directory.
 *
 *	    When trying to boot an existing encrypted database, the given encryption key is used to decrypt
 *	    the data in the verifyKey.dat and the checksum is calculated and compared against the original
 *	    stored checksum. If these checksums dont match an exception is thrown.
 *
 *	    Please note, this process of verifying the key  does not provide any added security but only is
 *	    intended to allow to fail gracefully if a wrong encryption key is used
 *
 *	    StandardException is thrown if there are any problems during the process of verification
 *	    		of the encryption key or if there is any mismatch of the encryption key.
 */
public void verifyKey(boolean create, StorageFactory sf, Properties properties) throws StandardException {
    if (properties.getProperty(Attribute.CRYPTO_EXTERNAL_KEY) == null)
        return;
    // if firstTime ( ie during creation of database, initial key used )
    // In order to allow for verifying the external key for future database boot,
    // generate random 4k of data and store the encrypted random data and the checksum
    // using MD5 of the unencrypted data. That way, on next database boot a check is performed
    // to verify if the key is the same as used when the database was created
    InputStream verifyKeyInputStream = null;
    StorageRandomAccessFile verifyKeyFile = null;
    byte[] data = new byte[VERIFYKEY_DATALEN];
    try {
        if (create) {
            getSecureRandom().nextBytes(data);
            // get the checksum
            byte[] checksum = getMD5Checksum(data);
            CipherProvider tmpCipherProvider = createNewCipher(ENCRYPT, mainSecretKey, mainIV);
            tmpCipherProvider.encrypt(data, 0, data.length, data, 0);
            // openFileForWrite
            verifyKeyFile = privAccessFile(sf, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE, "rw");
            // write the checksum length as int, and then the checksum and then the encrypted data
            verifyKeyFile.writeInt(checksum.length);
            verifyKeyFile.write(checksum);
            verifyKeyFile.write(data);
            verifyKeyFile.sync();
        } else {
            // Read from verifyKey.dat as an InputStream. This allows for
            // reading the information from verifyKey.dat successfully even when using the jar
            // subprotocol to boot derby. (DERBY-1373)
            verifyKeyInputStream = privAccessGetInputStream(sf, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
            DataInputStream dis = new DataInputStream(verifyKeyInputStream);
            // then read the checksum length
            int checksumLen = dis.readInt();
            byte[] originalChecksum = new byte[checksumLen];
            dis.readFully(originalChecksum);
            dis.readFully(data);
            // decrypt data with key
            CipherProvider tmpCipherProvider = createNewCipher(DECRYPT, mainSecretKey, mainIV);
            tmpCipherProvider.decrypt(data, 0, data.length, data, 0);
            byte[] verifyChecksum = getMD5Checksum(data);
            if (!MessageDigest.isEqual(originalChecksum, verifyChecksum)) {
                throw StandardException.newException(SQLState.ENCRYPTION_BAD_EXTERNAL_KEY);
            }
        }
    } catch (IOException ioe) {
        throw StandardException.newException(SQLState.ENCRYPTION_UNABLE_KEY_VERIFICATION, ioe);
    } finally {
        try {
            if (verifyKeyFile != null)
                verifyKeyFile.close();
            if (verifyKeyInputStream != null)
                verifyKeyInputStream.close();
        } catch (IOException ioee) {
            throw StandardException.newException(SQLState.ENCRYPTION_UNABLE_KEY_VERIFICATION, ioee);
        }
    }
    return;
}
Also used : StorageRandomAccessFile(org.apache.derby.io.StorageRandomAccessFile) DataInputStream(java.io.DataInputStream) InputStream(java.io.InputStream) CipherProvider(org.apache.derby.iapi.services.crypto.CipherProvider) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream)

Aggregations

StorageRandomAccessFile (org.apache.derby.io.StorageRandomAccessFile)15 IOException (java.io.IOException)10 StorageFile (org.apache.derby.io.StorageFile)6 ByteArrayInputStream (java.io.ByteArrayInputStream)2 DataInputStream (java.io.DataInputStream)2 FileNotFoundException (java.io.FileNotFoundException)2 DataStore (org.apache.derby.impl.io.vfmem.DataStore)2 VirtualFile (org.apache.derby.impl.io.vfmem.VirtualFile)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 DataOutputStream (java.io.DataOutputStream)1 InputStream (java.io.InputStream)1 CipherProvider (org.apache.derby.iapi.services.crypto.CipherProvider)1 ArrayInputStream (org.apache.derby.iapi.services.io.ArrayInputStream)1 Formatable (org.apache.derby.iapi.services.io.Formatable)1 LogInstant (org.apache.derby.iapi.store.raw.log.LogInstant)1 RawTransaction (org.apache.derby.iapi.store.raw.xact.RawTransaction)1 StandardException (org.apache.derby.shared.common.error.StandardException)1