blob: 1caae5098edc49d61e0aa345db4947609c5924d9 [file] [log] [blame]
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
package org.rocksdb;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class BackupEngineTest {
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Rule
public TemporaryFolder backupFolder = new TemporaryFolder();
@Test
public void backupDb() throws RocksDBException {
// Open empty database.
try(final Options opt = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath())) {
// Fill database with some test values
prepareDatabase(db);
// Create two backups
try(final BackupableDBOptions bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
final BackupEngine be = BackupEngine.open(opt.getEnv(), bopt)) {
be.createNewBackup(db, false);
be.createNewBackup(db, true);
verifyNumberOfValidBackups(be, 2);
}
}
}
@Test
public void deleteBackup() throws RocksDBException {
// Open empty database.
try(final Options opt = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath())) {
// Fill database with some test values
prepareDatabase(db);
// Create two backups
try(final BackupableDBOptions bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
final BackupEngine be = BackupEngine.open(opt.getEnv(), bopt)) {
be.createNewBackup(db, false);
be.createNewBackup(db, true);
final List<BackupInfo> backupInfo =
verifyNumberOfValidBackups(be, 2);
// Delete the first backup
be.deleteBackup(backupInfo.get(0).backupId());
final List<BackupInfo> newBackupInfo =
verifyNumberOfValidBackups(be, 1);
// The second backup must remain.
assertThat(newBackupInfo.get(0).backupId()).
isEqualTo(backupInfo.get(1).backupId());
}
}
}
@Test
public void purgeOldBackups() throws RocksDBException {
// Open empty database.
try(final Options opt = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath())) {
// Fill database with some test values
prepareDatabase(db);
// Create four backups
try(final BackupableDBOptions bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
final BackupEngine be = BackupEngine.open(opt.getEnv(), bopt)) {
be.createNewBackup(db, false);
be.createNewBackup(db, true);
be.createNewBackup(db, true);
be.createNewBackup(db, true);
final List<BackupInfo> backupInfo =
verifyNumberOfValidBackups(be, 4);
// Delete everything except the latest backup
be.purgeOldBackups(1);
final List<BackupInfo> newBackupInfo =
verifyNumberOfValidBackups(be, 1);
// The latest backup must remain.
assertThat(newBackupInfo.get(0).backupId()).
isEqualTo(backupInfo.get(3).backupId());
}
}
}
@Test
public void restoreLatestBackup() throws RocksDBException {
try(final Options opt = new Options().setCreateIfMissing(true)) {
// Open empty database.
RocksDB db = null;
try {
db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(db);
try (final BackupableDBOptions bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
final BackupEngine be = BackupEngine.open(opt.getEnv(), bopt)) {
be.createNewBackup(db, true);
verifyNumberOfValidBackups(be, 1);
db.put("key1".getBytes(), "valueV2".getBytes());
db.put("key2".getBytes(), "valueV2".getBytes());
be.createNewBackup(db, true);
verifyNumberOfValidBackups(be, 2);
db.put("key1".getBytes(), "valueV3".getBytes());
db.put("key2".getBytes(), "valueV3".getBytes());
assertThat(new String(db.get("key1".getBytes()))).endsWith("V3");
assertThat(new String(db.get("key2".getBytes()))).endsWith("V3");
db.close();
db = null;
verifyNumberOfValidBackups(be, 2);
// restore db from latest backup
try(final RestoreOptions ropts = new RestoreOptions(false)) {
be.restoreDbFromLatestBackup(dbFolder.getRoot().getAbsolutePath(),
dbFolder.getRoot().getAbsolutePath(), ropts);
}
// Open database again.
db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath());
// Values must have suffix V2 because of restoring latest backup.
assertThat(new String(db.get("key1".getBytes()))).endsWith("V2");
assertThat(new String(db.get("key2".getBytes()))).endsWith("V2");
}
} finally {
if(db != null) {
db.close();
}
}
}
}
@Test
public void restoreFromBackup()
throws RocksDBException {
try(final Options opt = new Options().setCreateIfMissing(true)) {
RocksDB db = null;
try {
// Open empty database.
db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(db);
try (final BackupableDBOptions bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
final BackupEngine be = BackupEngine.open(opt.getEnv(), bopt)) {
be.createNewBackup(db, true);
verifyNumberOfValidBackups(be, 1);
db.put("key1".getBytes(), "valueV2".getBytes());
db.put("key2".getBytes(), "valueV2".getBytes());
be.createNewBackup(db, true);
verifyNumberOfValidBackups(be, 2);
db.put("key1".getBytes(), "valueV3".getBytes());
db.put("key2".getBytes(), "valueV3".getBytes());
assertThat(new String(db.get("key1".getBytes()))).endsWith("V3");
assertThat(new String(db.get("key2".getBytes()))).endsWith("V3");
//close the database
db.close();
db = null;
//restore the backup
final List<BackupInfo> backupInfo = verifyNumberOfValidBackups(be, 2);
// restore db from first backup
be.restoreDbFromBackup(backupInfo.get(0).backupId(),
dbFolder.getRoot().getAbsolutePath(),
dbFolder.getRoot().getAbsolutePath(),
new RestoreOptions(false));
// Open database again.
db = RocksDB.open(opt,
dbFolder.getRoot().getAbsolutePath());
// Values must have suffix V2 because of restoring latest backup.
assertThat(new String(db.get("key1".getBytes()))).endsWith("V1");
assertThat(new String(db.get("key2".getBytes()))).endsWith("V1");
}
} finally {
if(db != null) {
db.close();
}
}
}
}
/**
* Verify backups.
*
* @param be {@link BackupEngine} instance.
* @param expectedNumberOfBackups numerical value
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
private List<BackupInfo> verifyNumberOfValidBackups(final BackupEngine be,
final int expectedNumberOfBackups) throws RocksDBException {
// Verify that backups exist
assertThat(be.getCorruptedBackups().length).
isEqualTo(0);
be.garbageCollect();
final List<BackupInfo> backupInfo = be.getBackupInfo();
assertThat(backupInfo.size()).
isEqualTo(expectedNumberOfBackups);
return backupInfo;
}
/**
* Fill database with some test values.
*
* @param db {@link RocksDB} instance.
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
private void prepareDatabase(final RocksDB db)
throws RocksDBException {
db.put("key1".getBytes(), "valueV1".getBytes());
db.put("key2".getBytes(), "valueV1".getBytes());
}
}