/**
* Copyright 2005-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.
*/
import java.util.Properties;
import java.util.Random;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.Value;
import com.persistit.Persistit;
/**
* <p>
* A simple demonstration of Persistit™'s insert and retrieval and
* performance. This class performs the following operations:
* <ol>
* <li>Initializes {@link com.persistit.Persistit} using stock properties file.</li>
* <li>Creates an {@link com.persistit.Exchange} with which to store and fetch
* data to and from a tree.</li>
* <li>Removes any data formerly stored in the tree.</li>
* <li>Inserts numerous String values, indexed by small integers.</li>
* <li>Traverses all keys in forward sequential order.</li>
* <li>Traverses all keys in reverse sequential order.</li>
* <li>Modifies records by random key value</li>
* <li>Lengthens all records </liL
* <li>Fetches records by random key value.</li>
* </ol>
* By default, <tt>SimpleBench</tt> performs this cycle ten times, inserting
* 500,000 records. You can specify different iteration and cycle counts on the
* command line.
* </p>
* <p>
* Note that if you run this program using a Sun HotSpot™ Server JVM, you
* will observe a substantial performance improvement over multiple cycles as
* the optimizing compiler fully analyzes and optimizes heavily-used code paths.
* </p>
*
* @version 1.0
*/
public class SimpleBench {
public static void main(String[] args) throws Exception {
w("");
w("SimpleBench");
w("");
w("This simple benchmark demonstrates Persistit's ability to");
w("modify its in-memory data structures fast. The buffer pool has");
w("been carefully sized to ensure that once the buffers are");
w("\"warmed up\", no disk I/O is needed to complete the store,");
w("traverse, and fetch operations being performed.");
w("");
w("Although real applications do not perform entirely in this");
w("manner, they typically do exhibit strong locality of reference");
w("within the keyspace, which is why disk caching is effective,");
w("and why it is important to examine in-memory performance.");
w("");
w("Truly meaningful performance comparisons can best be made by");
w("measuring actual application performance.");
w("");
//
// Initializes buffer pool, loads Volume(s)
// and sets up PrewriteJournal.
//
System.out.println("Initializing Persistit");
// Note: you can override datapath and logpath properties as follows:
//
// java -Dcom.persistit.datapath=... -Dcom.persistit.logpath=...
// SimpleBench
//
Properties props = new Properties();
props.setProperty("datapath", ".");
props.setProperty("logpath", ".");
props.setProperty("logfile", "${logpath}/sbdemo_${timestamp}.log");
props.setProperty("buffer.count.16384", "8K");
props.setProperty("volume.1", "${datapath}/sbdemo,create,pageSize:16K,"
+ "initialSize:50M,extensionSize:1M,maximumSize:10G");
props.setProperty("journalpath", "${datapath}/sbdemo_journal");
Persistit persistit = new Persistit();
persistit.initialize(props);
try {
doBench(persistit, args);
} finally {
persistit.close();
}
}
private static void w(String s) {
System.out.println(s);
}
public static void doBench(Persistit persistit, String[] args) throws Exception {
//
// Source of random key values. Initialized with a constant seed
// value so that results are reproducible.
//
Random random = new Random(1);
//
// An Exchange provides all the methods you use to manipulate data.
// This constructs a Exchange in volume "sbdemo" and either opens
// or creates within that volume a Tree called "BenchTree".
//
Exchange exchange = new Exchange(persistit, "sbdemo", "BenchTree", true);
long time;
int iterations = 1000000;
int cycles = 10;
if (args.length > 0)
iterations = Integer.parseInt(args[0]);
if (args.length > 1)
cycles = Integer.parseInt(args[1]);
long time0 = System.currentTimeMillis();
for (int cycle = 1; cycle <= cycles; cycle++) {
System.out.println();
System.out.println();
System.out.println("Starting cycle #" + cycle + " of " + cycles);
System.out.println();
//
// Remove all records everything.
//
exchange.removeAll();
//
// Set up a stock 30-character value to store.
//
exchange.getValue().putString("ABCDEFGHIJABCDEFGHIJABCDEFGHIJ");
//
// INSERTION
// Inserts numerous String values, indexed by small integers.
//
System.out.print("Inserting " + iterations + " records in forward sequential key order ");
time = System.currentTimeMillis();
for (int index = 0; index < iterations; index++) {
exchange.to(index).store();
if ((index % 50000) == 0)
System.out.print(".");
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
//
// TRAVERSAL
// Traverses all keys in forward-sequential order.
//
System.out.print("Traversing " + iterations + " keys in forward order ");
exchange.to(Key.BEFORE);
time = System.currentTimeMillis();
for (int index = 0; exchange.next(); index++) {
if ((index % 50000) == 0)
System.out.print(".");
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
//
// TRAVERSAL
// Traverses all keys in reverse-sequential order.
//
System.out.print("Traversing " + iterations + " keys in reverse order ");
exchange.to(Key.AFTER);
time = System.currentTimeMillis();
for (int index = 0; exchange.previous(); index++) {
if ((index % 50000) == 0)
System.out.print(".");
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
//
// UPDATE
// Updates numerous String values with equal length using random
// keys.
//
exchange.getValue().putString("abcdefghijabcdefghijabcdefghij");
System.out.print("Modifying " + iterations + " values by random key ");
time = System.currentTimeMillis();
for (int index = 0; index < iterations; index++) {
if ((index % 50000) == 0)
System.out.print(".");
int randomKeyInt = random.nextInt(iterations);
exchange.to(randomKeyInt).store();
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
//
// LENGTHEN
// Lengthens all String values in forward-seqential key order.
//
exchange.getValue().putString("ABCDEFGHIJABCDEFGHIJABCDEFGHIJ0123456789");
System.out.print("Lengthening " + iterations + " values by 10 chars in forward-sequential order");
time = System.currentTimeMillis();
for (int index = 0; index < iterations; index++) {
if ((index % 50000) == 0)
System.out.print(".");
exchange.to(index).store();
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
//
// RETRIEVE ALL VALUES IN PSEUDO-RANDOM ORDER
//
StringBuilder sb = new StringBuilder();
System.out.print("Retrieving " + iterations + " values in random order");
time = System.currentTimeMillis();
for (int index = 0; index < iterations; index++) {
if ((index % 50000) == 0)
System.out.print(".");
int randomKeyInt = random.nextInt(iterations);
exchange.to(randomKeyInt).fetch();
exchange.getValue().getString(sb);
if (sb.length() != 40) {
throw new RuntimeException("Wrong value " + exchange.getValue() + " at " + randomKeyInt);
}
sb.setLength(0);
}
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
System.out.print("Flushing all pending updates to the OS");
time = System.currentTimeMillis();
persistit.flush();
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
System.out.print("Synching all pending I/O to disk");
time = System.currentTimeMillis();
persistit.force();
time = System.currentTimeMillis() - time;
System.out.println(" -- took " + time + "ms");
}
time0 = System.currentTimeMillis() - time0;
System.out.println("Total time: " + time0);
persistit.close();
}
}