/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.store;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.TreeMap;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
/**
* Tests the MVStore.
*/
public class TestRandomMapOps extends TestBase {
private static final boolean LOG = false;
private int op;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase test = TestBase.createCaller().init();
test.config.big = true;
test.test();
}
@Override
public void test() throws Exception {
testMap("memFS:randomOps.h3");
FileUtils.delete("memFS:randomOps.h3");
}
private void testMap(String fileName) {
int best = Integer.MAX_VALUE;
int bestSeed = 0;
Throwable failException = null;
int size = getSize(100, 1000);
for (int seed = 0; seed < 100; seed++) {
FileUtils.delete(fileName);
Throwable ex = null;
try {
testOps(fileName, size, seed);
continue;
} catch (Exception e) {
ex = e;
} catch (AssertionError e) {
ex = e;
}
if (op < best) {
trace(seed);
bestSeed = seed;
best = op;
size = best;
failException = ex;
// System.out.println("seed:" + seed + " op:" + op + " " + ex);
}
}
if (failException != null) {
throw (AssertionError) new AssertionError("seed = " + bestSeed
+ " op = " + best).initCause(failException);
}
}
private void testOps(String fileName, int size, int seed) {
FileUtils.delete(fileName);
MVStore s = openStore(fileName);
MVMap<Integer, byte[]> m = s.openMap("data");
Random r = new Random(seed);
op = 0;
TreeMap<Integer, byte[]> map = new TreeMap<Integer, byte[]>();
for (; op < size; op++) {
int k = r.nextInt(100);
byte[] v = new byte[r.nextInt(10) * 10];
int type = r.nextInt(12);
switch (type) {
case 0:
case 1:
case 2:
case 3:
log(op, k, v, "m.put({0}, {1})");
m.put(k, v);
map.put(k, v);
break;
case 4:
case 5:
log(op, k, v, "m.remove({0})");
m.remove(k);
map.remove(k);
break;
case 6:
log(op, k, v, "s.compact(90, 1024)");
s.compact(90, 1024);
break;
case 7:
log(op, k, v, "m.clear()");
m.clear();
map.clear();
break;
case 8:
log(op, k, v, "s.commit()");
s.commit();
break;
case 9:
log(op, k, v, "s.commit()");
s.commit();
log(op, k, v, "s.close()");
s.close();
log(op, k, v, "s = openStore(fileName)");
s = openStore(fileName);
log(op, k, v, "m = s.openMap(\"data\")");
m = s.openMap("data");
break;
case 10:
log(op, k, v, "s.commit()");
s.commit();
log(op, k, v, "s.compactMoveChunks()");
s.compactMoveChunks();
break;
case 11:
log(op, k, v, "m.getKeyIndex({0})");
ArrayList<Integer> keyList = new ArrayList<Integer>(map.keySet());
int index = Collections.binarySearch(keyList, k, null);
int index2 = (int) m.getKeyIndex(k);
assertEquals(index, index2);
if (index >= 0) {
int k2 = m.getKey(index);
assertEquals(k2, k);
}
break;
}
assertEqualsMapValues(map.get(k), m.get(k));
assertEquals(map.ceilingKey(k), m.ceilingKey(k));
assertEquals(map.floorKey(k), m.floorKey(k));
assertEquals(map.higherKey(k), m.higherKey(k));
assertEquals(map.lowerKey(k), m.lowerKey(k));
assertEquals(map.isEmpty(), m.isEmpty());
assertEquals(map.size(), m.size());
if (!map.isEmpty()) {
assertEquals(map.firstKey(), m.firstKey());
assertEquals(map.lastKey(), m.lastKey());
}
}
s.close();
}
private static MVStore openStore(String fileName) {
MVStore s = new MVStore.Builder().fileName(fileName).
pageSplitSize(50).autoCommitDisabled().open();
s.setRetentionTime(1000);
return s;
}
private void assertEqualsMapValues(byte[] x, byte[] y) {
if (x == null || y == null) {
if (x != y) {
assertTrue(x == y);
}
} else {
assertEquals(x.length, y.length);
}
}
/**
* Log the operation
*
* @param op the operation id
* @param k the key
* @param v the value
* @param msg the message
*/
private static void log(int op, int k, byte[] v, String msg) {
if (LOG) {
msg = MessageFormat.format(msg, k,
v == null ? null : "new byte[" + v.length + "]");
System.out.println(msg + "; // op " + op);
}
}
}