in core/src/main/java/com/jetbrains/youtrackdb/internal/core/storage/disk/DiskStorage.java [995:1142]
private String incrementalBackup(
final java.io.File backupDirectory, final CallableFunction<Void, Void> started) {
var fileName = "";
if (!backupDirectory.exists()) {
if (!backupDirectory.mkdirs()) {
throw new StorageException(name,
"Backup directory "
+ backupDirectory.getAbsolutePath()
+ " does not exist and can not be created");
}
}
checkNoBackupInStorageDir(backupDirectory);
final var fileLockPath = backupDirectory.toPath().resolve(INCREMENTAL_BACKUP_LOCK);
try (final var lockChannel =
FileChannel.open(fileLockPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
try (@SuppressWarnings("unused") final var fileLock = lockChannel.lock()) {
RandomAccessFile rndIBUFile = null;
try {
final var files = fetchIBUFiles(backupDirectory);
final LogSequenceNumber lastLsn;
long nextIndex;
final UUID backupUUID;
if (files.length == 0) {
lastLsn = null;
nextIndex = 0;
} else {
lastLsn = extractIBULsn(backupDirectory, files[files.length - 1]);
nextIndex = extractIndexFromIBUFile(backupDirectory, files[files.length - 1]) + 1;
backupUUID =
extractDbInstanceUUID(backupDirectory, files[0], configuration.getCharset());
checkDatabaseInstanceId(backupUUID);
}
final var dateFormat = new SimpleDateFormat(INCREMENTAL_BACKUP_DATEFORMAT);
if (lastLsn != null) {
fileName =
getName()
+ "_"
+ dateFormat.format(new Date())
+ "_"
+ nextIndex
+ IBU_EXTENSION_V3;
} else {
fileName =
getName()
+ "_"
+ dateFormat.format(new Date())
+ "_"
+ nextIndex
+ "_full"
+ IBU_EXTENSION_V3;
}
final var ibuFile = new java.io.File(backupDirectory, fileName);
if (started != null) {
started.call(null);
}
rndIBUFile = new RandomAccessFile(ibuFile, "rw");
try {
final var ibuChannel = rndIBUFile.getChannel();
final var versionBuffer = ByteBuffer.allocate(IntegerSerializer.INT_SIZE);
versionBuffer.putInt(INCREMENTAL_BACKUP_VERSION);
versionBuffer.rewind();
IOUtils.writeByteBuffer(versionBuffer, ibuChannel, 0);
ibuChannel.position(
2 * IntegerSerializer.INT_SIZE
+ 2 * LongSerializer.LONG_SIZE
+ ByteSerializer.BYTE_SIZE);
LogSequenceNumber maxLsn;
try (var stream = Channels.newOutputStream(ibuChannel)) {
maxLsn = incrementalBackup(stream, lastLsn, true);
final var dataBuffer =
ByteBuffer.allocate(
IntegerSerializer.INT_SIZE
+ 2 * LongSerializer.LONG_SIZE
+ ByteSerializer.BYTE_SIZE);
dataBuffer.putLong(nextIndex);
dataBuffer.putLong(maxLsn.getSegment());
dataBuffer.putInt(maxLsn.getPosition());
if (lastLsn == null) {
dataBuffer.put((byte) 1);
} else {
dataBuffer.put((byte) 0);
}
dataBuffer.rewind();
ibuChannel.write(dataBuffer);
IOUtils.writeByteBuffer(dataBuffer, ibuChannel, IntegerSerializer.INT_SIZE);
}
} catch (RuntimeException e) {
rndIBUFile.close();
if (!ibuFile.delete()) {
LogManager.instance()
.error(
this, ibuFile.getAbsolutePath() + " is closed but can not be deleted", null);
}
throw e;
}
} catch (IOException e) {
throw BaseException.wrapException(
new StorageException(name, "Error during incremental backup"), e, name);
} finally {
try {
if (rndIBUFile != null) {
rndIBUFile.close();
}
} catch (IOException e) {
LogManager.instance().error(this, "Can not close %s file", e, fileName);
}
}
}
} catch (final OverlappingFileLockException e) {
LogManager.instance()
.error(
this,
"Another incremental backup process is in progress, please wait till it will be"
+ " finished",
null);
} catch (final IOException e) {
throw BaseException.wrapException(
new StorageException(name, "Error during incremental backup"),
e, name);
}
try {
Files.deleteIfExists(fileLockPath);
} catch (IOException e) {
throw BaseException.wrapException(
new StorageException(name, "Error during incremental backup"),
e, name);
}
return fileName;
}