/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Nov 3, 2008
*/
package com.bigdata.journal;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.bigdata.btree.AbstractBTreeTestCase;
import com.bigdata.btree.BTree;
import com.bigdata.btree.BaseIndexStats;
import com.bigdata.btree.IndexMetadata;
import com.bigdata.btree.keys.KV;
/**
* Test suite for {@link WarmUpTask}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
*
* @see <a href="http://trac.bigdata.com/ticket/1050" > pre-heat the journal on
* startup </a>
*/
public class TestWarmupJournal extends ProxyTestCase<Journal> {
/**
*
*/
public TestWarmupJournal() {
}
/**
* @param name
*/
public TestWarmupJournal(String name) {
super(name);
}
/**
* Verify operation Ok when nothing has been written on the journal.
*
* @throws IOException
* @throws InterruptedException
* @throws ExecutionException
*/
public void test_emptyJournal() throws IOException, InterruptedException,
ExecutionException {
final File out = File.createTempFile(getName(), Options.JNL);
try {
final Journal src = getStore(getProperties());
try {
// create and submit task.
final Future<Map<String, BaseIndexStats>> f = src
.warmUp(null/* namespaces */);
// await future.
final Map<String, BaseIndexStats> map = f.get();
assertEquals(0, map.size());
} finally {
src.destroy();
}
} finally {
out.delete();
}
}
/**
* Test of a journal on which a single index has been register (and the
* journal committed) but no data was written onto the index.
*/
public void test_journal_oneIndexNoData() throws IOException,
InterruptedException, ExecutionException {
final File out = File.createTempFile(getName(), Options.JNL);
try {
final Journal src = getStore(getProperties());
try {
// register an index and commit the journal.
final String NAME = "testIndex";
src.registerIndex(new IndexMetadata(NAME, UUID.randomUUID()));
src.commit();
// create and submit task.
final Future<Map<String, BaseIndexStats>> f = src
.warmUp(null/* namespaces */);
// await future.
final Map<String, BaseIndexStats> map = f.get();
// verify state
assertEquals(1,map.size());
final BaseIndexStats stats = map.get(NAME);
assertNotNull(stats);
assertEquals(0, stats.height);
assertEquals(0, stats.nnodes);
assertEquals(1, stats.nleaves);
} finally {
src.destroy();
}
} finally {
out.delete();
}
}
/**
* Test with a journal on which a single index has been registered with
* random data on the index.
*/
public void test_journal_oneIndexRandomData() throws IOException,
InterruptedException, ExecutionException {
final File out = File.createTempFile(getName(), Options.JNL);
try {
final Journal src = getStore(getProperties());
try {
// register an index and commit the journal.
final String NAME = "testIndex";
int ntuples = 0;
src.registerIndex(new IndexMetadata(NAME, UUID.randomUUID()));
{
final BTree ndx = src.getIndex(NAME);
final KV[] a = AbstractBTreeTestCase
.getRandomKeyValues(1000/* ntuples */);
for (KV kv : a) {
if (ndx.insert(kv.key, kv.val) == null) {
// only count first time inserted (vs replaced).
ntuples++;
}
}
}
src.commit();
// create and submit task.
final Future<Map<String, BaseIndexStats>> f = src
.warmUp(null/* namespaces */);
// await future.
final Map<String, BaseIndexStats> map = f.get();
// verify state
assertEquals(1,map.size());
final BaseIndexStats stats = map.get(NAME);
assertNotNull(stats);
assertEquals(ntuples, stats.ntuples);
} finally {
src.destroy();
}
} finally {
out.delete();
}
}
/**
* Test with a journal on which many indices have been registered and
* populated with random data.
*/
public void test_journal_manyIndicesRandomData() throws IOException,
InterruptedException, ExecutionException {
final File out = File.createTempFile(getName(), Options.JNL);
try {
final Journal src = getStore(getProperties());
try {
final String PREFIX = "testIndex#";
final int NUM_INDICES = 20;
for (int i = 0; i < NUM_INDICES; i++) {
// register an index
final String name = PREFIX + i;
src.registerIndex(new IndexMetadata(name, UUID.randomUUID()));
{
// lookup the index.
final BTree ndx = src.getIndex(name);
// #of tuples to write.
final int ntuples = r.nextInt(10000);
// generate random data.
final KV[] a = AbstractBTreeTestCase
.getRandomKeyValues(ntuples);
// write tuples (in random order)
for (KV kv : a) {
ndx.insert(kv.key, kv.val);
if (r.nextInt(100) < 10) {
// randomly increment the counter (10% of the time).
ndx.getCounter().incrementAndGet();
}
}
}
}
// commit the journal (!)
src.commit();
{
// create and submit task.
final Future<Map<String, BaseIndexStats>> f = src
.warmUp(null/* namespaces */);
// await future.
final Map<String, BaseIndexStats> map = f.get();
assertEquals(NUM_INDICES, map.size());
// Exercise the logic to write out the statistics table.
{
final PrintWriter w = new PrintWriter(System.out);
BaseIndexStats.writeOn(w, map);
w.flush();
}
}
} finally {
src.destroy();
}
} finally {
out.delete();
}
}
/**
* Test with a journal on which many indices have been registered and
* populated with random data.
*
* @throws IOException
* @throws InterruptedException
* @throws ExecutionException
*/
public void test_journal_manyIndicesRandomData_concurrentWriter() throws IOException,
InterruptedException, ExecutionException {
final File out = File.createTempFile(getName(), Options.JNL);
try {
final Journal src = getStore(getProperties());
try {
final String PREFIX = "testIndex#";
final int NUM_INDICES = 20;
for (int i = 0; i < NUM_INDICES; i++) {
// register an index
final String name = PREFIX + i;
src.registerIndex(new IndexMetadata(name, UUID.randomUUID()));
{
// lookup the index.
final BTree ndx = src.getIndex(name);
// #of tuples to write.
final int ntuples = r.nextInt(10000);
// generate random data.
final KV[] a = AbstractBTreeTestCase
.getRandomKeyValues(ntuples);
// write tuples (in random order)
for (KV kv : a) {
ndx.insert(kv.key, kv.val);
if (r.nextInt(100) < 10) {
// randomly increment the counter (10% of the time).
ndx.getCounter().incrementAndGet();
}
}
}
}
// commit the journal (!)
src.commit();
/*
* Submit task for concurrent writes. Note that this task does not
* do a commit, but it does write modifications onto the live
* indices. Those changes should not be visible in the snapshot.
* Since the task does not do a commit, the snapshot should have
* exactly the same data that was in the journal as of the previous
* commit point. That commit point is restored (below) when we
* discard the write set.
*/
final Future<Void> f2 = src.getExecutorService().submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
for (int i = 0; i < NUM_INDICES; i++) {
final String name = PREFIX + i;
// lookup the index.
final BTree ndx = src.getIndex(name);
// #of tuples to write.
final int ntuples = r.nextInt(10000);
// generate random data.
final KV[] a = AbstractBTreeTestCase
.getRandomKeyValues(ntuples);
// write tuples (in random order)
for (KV kv : a) {
ndx.insert(kv.key, kv.val);
if (r.nextInt(100) < 10) {
// randomly increment the counter (10% of the time).
ndx.getCounter().incrementAndGet();
}
}
}
// Done.
return null;
}});
try {
// Run warmup while writer is running.
{
// create and submit task.
final Future<Map<String, BaseIndexStats>> f = src
.warmUp(null/* namespaces */);
// await future.
final Map<String, BaseIndexStats> map = f.get();
assertEquals(NUM_INDICES, map.size());
// Exercise the logic to write out the statistics table.
{
final PrintWriter w = new PrintWriter(System.out);
BaseIndexStats.writeOn(w, map);
w.flush();
}
}
// Await the success of the writer.
f2.get();
// Discard the write set.
src.abort();
} finally {
f2.cancel(true/* mayInterruptIfRunning */);
}
} finally {
src.destroy();
}
} finally {
out.delete();
}
}
}