{
boolean backupCompleted = false;
File backupFile = null;
RandomAccessFile backupRaf = null;
boolean isStub = false;
BasePage page = null;
while(!backupCompleted) {
try {
synchronized (this) {
// wait if some one is removing the
// container because of a drop.
while (inRemove)
{
try {
wait();
}
catch (InterruptedException ie)
{
throw StandardException.interrupt(ie);
}
}
if (getCommittedDropState())
isStub = true;
inBackup = true;
}
// create container at the backup location.
if (isStub) {
// get the stub ( it is a committted drop table container )
StorageFile file = privGetFileName((ContainerKey)getIdentity(),
true, false, true);
backupFile = new File(backupLocation, file.getName());
// directly copy the stub to the backup
if(!FileUtil.copyFile(dataFactory.getStorageFactory(),
file, backupFile))
{
throw StandardException.newException(
SQLState.RAWSTORE_ERROR_COPYING_FILE,
file, backupFile);
}
}else {
// regular container file
long lastPageNumber= getLastPageNumber(handle);
if (lastPageNumber == ContainerHandle.INVALID_PAGE_NUMBER) {
// last page number is invalid if there are no pages in
// the container yet. No need to backup this container,
// this container creation is yet to complete.The reason
// backup is getting called on such a container is
// because container handle appears in the cache after
// the file is created on the disk but before it's
// first page is allocated.
return;
}
StorageFile file =
privGetFileName(
(ContainerKey)getIdentity(), false, false, true);
backupFile = new File(backupLocation , file.getName());
backupRaf = new RandomAccessFile(backupFile, "rw");
byte[] encryptionBuf = null;
if (dataFactory.databaseEncrypted()) {
// Backup uses seperate encryption buffer to encrypt the
// page instead of encryption buffer used by the regular
// conatiner writes. Otherwise writes to the backup
// has to be synchronized with regualar database writes
// because backup can run in parallel to container
// writes.
encryptionBuf = new byte[pageSize];
}
// copy all the pages of the container from the database
// to the backup location by reading through the page cache.
for (long pageNumber = FIRST_ALLOC_PAGE_NUMBER;
pageNumber <= lastPageNumber; pageNumber++) {
page = getLatchedPage(handle, pageNumber);
// update the page array before writing to the disk
// with container header and encrypt it if the database
// is encrypted.
byte[] dataToWrite = updatePageArray(pageNumber,
page.getPageArray(),
encryptionBuf, false);
backupRaf.write(dataToWrite, 0, pageSize);
// unlatch releases page from cache, see
// StoredPage.releaseExclusive()
page.unlatch();
page = null;
// check if some one wants to commit drop the table while
// conatiner is being written to the backup. If so,
// abort the backup and restart it once the drop
// is complete.
synchronized (this)
{
if (inRemove) {
break;
}
}
}
}
// sync and close the backup conatiner. Incase of a stub,
// it is already synced and closed while doing the copy.
if(!isStub) {
backupRaf.getFD().sync();
backupRaf.close();
backupRaf = null;
}
// backup of the conatiner is complete.
backupCompleted = true;
}catch (IOException ioe) {
throw StandardException.newException(
SQLState.BACKUP_FILE_IO_ERROR,
ioe,
backupFile);
} finally {
synchronized (this) {
inBackup = false;
notifyAll();
}
if (page != null) {
page.unlatch();
page = null;
}
// if backup of container is not complete, close the file
// handles and remove the container file from the backup