/**
* Copyright 2011-2012 Akiban Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.persistit;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import com.persistit.unit.UnitTestProperties;
public class BackupTaskTest extends PersistitUnitTestCase {
private final static int TRANSACTION_COUNT = 50000;
@Override
protected Properties getProperties(final boolean cleanup) {
return UnitTestProperties.getBiggerProperties(cleanup);
}
@Test
public void testSimpleBackup() throws Exception {
final PrintWriter writer = new PrintWriter(System.out);
final PersistitMap<Integer, String> pmap1 = new PersistitMap<Integer, String>(_persistit.getExchange(
"persistit", "BackupTest", true));
for (int index = 0; index < 50000; index++) {
pmap1.put(new Integer(index), "This is the record for index=" + index);
}
final TreeMap<Integer, String> tmap = new TreeMap<Integer, String>(pmap1);
final File file = File.createTempFile("backup", ".zip");
file.deleteOnExit();
final BackupTask backup1 = (BackupTask) CLI
.parseTask(_persistit, "backup -z -c file=" + file.getAbsolutePath());
backup1.setMessageWriter(writer);
backup1.setup(1, "backup file=" + file.getAbsolutePath(), "cli", 0, 5);
backup1.run();
final Configuration config = _persistit.getConfiguration();
_persistit.close();
final BackupTask backup2 = new BackupTask();
backup2.setMessageWriter(writer);
backup2.setPersistit(_persistit);
backup2.doRestore(file.getAbsolutePath());
_persistit = new Persistit(config);
_persistit.checkAllVolumes();
final PersistitMap<Integer, String> pmap2 = new PersistitMap<Integer, String>(_persistit.getExchange(
"persistit", "BackupTest", false));
final boolean comparison = pmap2.equals(tmap);
assertTrue(comparison);
}
@Test
public void testBackupWithConcurrentTransactions() throws Exception {
final PrintWriter writer = new PrintWriter(System.out);
final TransactionWriter tw = new TransactionWriter();
final Thread twThread = new Thread(tw, "BackupTest_TW");
twThread.start();
while (tw.counter.get() < TRANSACTION_COUNT) {
Thread.sleep(1000);
}
final File file = File.createTempFile("backup", ".zip");
file.deleteOnExit();
final BackupTask backup1 = (BackupTask) CLI
.parseTask(_persistit, "backup -y -c file=" + file.getAbsolutePath());
backup1.setMessageWriter(writer);
backup1.setPersistit(_persistit);
backup1.setup(1, "backup file=" + file.getAbsolutePath(), "cli", 0, 5);
tw.backupStarted.set(true);
backup1.run();
tw.stop.set(true);
twThread.join();
final Configuration config = _persistit.getConfiguration();
_persistit.crash();
UnitTestProperties.cleanUpDirectory(new File(UnitTestProperties.DATA_PATH));
final BackupTask backup2 = new BackupTask();
backup2.setMessageWriter(writer);
backup2.setPersistit(_persistit);
backup2.doRestore(file.getAbsolutePath());
config.setAppendOnly(true);
_persistit = new Persistit(config);
_persistit.checkAllVolumes();
final Exchange exchange = _persistit.getExchange("persistit", "BackupTest", false);
exchange.to(Key.BEFORE);
int extras = 0;
while (exchange.next()) {
final int key = exchange.getKey().reset().decodeInt();
final boolean found = tw.commitTransactions.remove(key);
if (!found) {
extras++;
}
}
assertTrue(tw.commitTransactions.isEmpty());
}
private class TransactionWriter implements Runnable {
final Set<Integer> commitTransactions = new HashSet<Integer>();
final AtomicInteger counter = new AtomicInteger();
final Random random = new Random(1);
final AtomicBoolean stop = new AtomicBoolean();
final AtomicBoolean backupStarted = new AtomicBoolean();
@Override
public void run() {
try {
final Exchange ex = _persistit.getExchange("persistit", "BackupTest", true);
final Transaction transaction = ex.getTransaction();
while (!stop.get()) {
final int key = random.nextInt();
transaction.begin();
ex.to(key);
ex.getValue().put("Record for key=" + key);
ex.store();
transaction.commit();
if (!backupStarted.get()) {
commitTransactions.add(key);
}
final int count = counter.incrementAndGet();
transaction.end();
// Once the counter has advanced to TRANSACTION_COUNT,
// throttle this
// thread back to a more "realistic" rate and let the backup
// thread proceed.
if (count > TRANSACTION_COUNT) {
Thread.sleep(10);
}
}
} catch (final Exception e) {
e.printStackTrace();
}
}
}
@Override
public void runAllTests() throws Exception {
testSimpleBackup();
testBackupWithConcurrentTransactions();
}
}