/*************************************************************************************************
* Java binding of Kyoto Cabinet.
* Copyright (C) 2009-2011 FAL Labs
* This file is part of Kyoto Cabinet.
* 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, either version
* 3 of the License, or any later version.
* 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, see <http://www.gnu.org/licenses/>.
*************************************************************************************************/
package kyotocabinet;
import java.util.*;
import java.io.*;
import java.net.*;
/**
* Test cases.
*/
public class Test {
//----------------------------------------------------------------
// public static methods
//----------------------------------------------------------------
/** main routine of the test command */
public static void main(String[] args) {
if (args.length < 1) usage();
int rv = 0;
if (args[0].equals("order")) {
rv = runorder(args);
} else if (args[0].equals("wicked")) {
rv = runwicked(args);
} else if (args[0].equals("misc")) {
rv = runmisc(args);
} else if (args[0].equals("memsize")) {
rv = runmemsize(args);
} else {
usage();
}
System.gc();
System.exit(rv);
}
//----------------------------------------------------------------
// private static methods
//----------------------------------------------------------------
/** print the usage and exit */
private static void usage() {
STDERR.printf("test cases of the Java binding\n");
STDERR.printf("\n");
STDERR.printf("synopsis:\n");
STDERR.printf(" java %s arguments...\n", Test.class.getName());
STDERR.printf("\n");
STDERR.printf("arguments:\n");
STDERR.printf(" order [-th num] [-rnd] [-etc] path rnum\n");
STDERR.printf(" wicked [-th num] [-it num] path rnum\n");
STDERR.printf(" misc path\n");
STDERR.printf(" memsize [rnum [path]]\n");
STDERR.printf("\n");
System.exit(1);
}
/** print the error message of the database */
private static void dberrprint(DB db, String func) {
Error err = db.error();
printf("%s: %s: %d: %s: %s\n",
Test.class.getName(), func, err.code(), err.name(), err.message());
}
/** print members of a database */
private static void dbmetaprint(DB db, boolean verbose) {
if (verbose) {
Map<String, String> status = db.status();
if (status != null) {
for (Map.Entry<String, String> rec : status.entrySet()) {
printf("%s: %s\n", rec.getKey(), rec.getValue());
}
}
} else {
printf("count: %d\n", db.count());
printf("size: %d\n", db.size());
}
}
/** parse arguments of order command */
private static int runorder(String[] args) {
String path = null;
String rstr = null;
int thnum = 1;
boolean rnd = false;
boolean etc = false;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (path == null && arg.startsWith("-")) {
if (arg.equals("-th")) {
if (++i >= args.length) usage();
thnum = (int)Utility.atoix(args[i]);
} else if (arg.equals("-rnd")) {
rnd = true;
} else if (arg.equals("-etc")) {
etc = true;
} else {
usage();
}
} else if (path == null) {
path = arg;
} else if (rstr == null) {
rstr = arg;
} else {
usage();
}
}
if (path == null || rstr == null) usage();
long rnum = Utility.atoix(rstr);
if (rnum < 1 || thnum < 1) usage();
int rv = procorder(path, rnum, thnum, rnd, etc);
return rv;
}
/** parse arguments of wicked command */
private static int runwicked(String[] args) {
String path = null;
String rstr = null;
int thnum = 1;
int itnum = 1;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (path == null && arg.startsWith("-")) {
if (arg.equals("-th")) {
if (++i >= args.length) usage();
thnum = (int)Utility.atoix(args[i]);
} else if (arg.equals("-it")) {
if (++i >= args.length) usage();
itnum = (int)Utility.atoix(args[i]);
} else {
usage();
}
} else if (path == null) {
path = arg;
} else if (rstr == null) {
rstr = arg;
} else {
usage();
}
}
if (path == null || rstr == null) usage();
long rnum = Utility.atoix(rstr);
if (rnum < 1 || thnum < 1 || itnum < 1) usage();
int rv = procwicked(path, rnum, thnum, itnum);
return rv;
}
/** parse arguments of misc command */
private static int runmisc(String[] args) {
String path = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (path == null && arg.startsWith("-")) {
usage();
} else if (path == null) {
path = arg;
} else {
usage();
}
}
if (path == null) usage();
int rv = procmisc(path);
return rv;
}
/** parse arguments of memsize command */
private static int runmemsize(String[] args) {
String rstr = null;
String path = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (path == null && arg.startsWith("-")) {
usage();
} else if (rstr == null) {
rstr = arg;
} else if (path == null) {
path = arg;
} else {
usage();
}
}
long rnum = rstr != null ? Utility.atoix(rstr) : 1000000;
if (rnum < 1) usage();
int rv = procmemsize(rnum, path);
return rv;
}
/** perform order command */
private static int procorder(String path, long rnum, int thnum, boolean rnd, boolean etc) {
printf("<In-order Test>\n path=%s rnum=%d thnum=%d rnd=%s etc=%s\n\n",
path, rnum, thnum, rnd, etc);
boolean err = false;
printf("calling utility functions:\n");
Utility.atoi("123.456mikio");
Utility.atoix("123.456mikio");
Utility.atof("123.456mikio");
Utility.hash_murmur(path.getBytes());
Utility.hash_fnv(path.getBytes());
DB db = new DB();
int[] codes = { Error.SUCCESS, Error.NOIMPL, Error.MISC };
db.tune_exception_rule(codes);
db.tune_encoding("UTF-8");
printf("opening the database:\n");
double stime = Utility.time();
if (!db.open(path, DB.OWRITER | DB.OCREATE | DB.OTRUNCATE)) {
dberrprint(db, "DB::open");
err = true;
}
double etime = Utility.time();
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
printf("setting records:\n");
stime = Utility.time();
class Setter extends Thread {
public Setter(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (!db_.set(key, key)) {
dberrprint(db_, "DB::set");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Setter[] setters = new Setter[thnum];
for (int i = 0; i < thnum; i++) {
setters[i] = new Setter(i, rnum, thnum, rnd, db);
setters[i].setDefaultUncaughtExceptionHandler(EXH);
setters[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
setters[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (setters[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
if (etc) {
printf("adding records:\n");
stime = Utility.time();
class Adder extends Thread {
public Adder(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (!db_.add(key, key) && db_.error().code() != Error.DUPREC) {
dberrprint(db_, "DB::add");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Adder[] adders = new Adder[thnum];
for (int i = 0; i < thnum; i++) {
adders[i] = new Adder(i, rnum, thnum, rnd, db);
adders[i].setDefaultUncaughtExceptionHandler(EXH);
adders[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
adders[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (adders[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
if (etc) {
printf("appending records:\n");
stime = Utility.time();
class Appender extends Thread {
public Appender(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (!db_.append(key, key)) {
dberrprint(db_, "DB::append");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Appender[] appenders = new Appender[thnum];
for (int i = 0; i < thnum; i++) {
appenders[i] = new Appender(i, rnum, thnum, rnd, db);
appenders[i].setDefaultUncaughtExceptionHandler(EXH);
appenders[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
appenders[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (appenders[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
if (etc) {
printf("accepting records:\n");
stime = Utility.time();
class Accepter extends Thread {
public Accepter(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
class VisitorImpl implements Visitor {
public VisitorImpl(boolean rnd) {
rnd_ = rnd;
cnt_ = 0;
}
public byte[] visit_full(byte[] key, byte[] value) {
cnt_++;
if (cnt_ % 100 == 0) Thread.yield();
byte[] rv = NOP;
if (rnd_) {
switch ((int)rand(7)) {
case 0: {
rv = String.format("%d", cnt_).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
}
return rv;
}
public byte[] visit_empty(byte[] key) {
return visit_full(key, key);
}
private boolean rnd_;
private long cnt_;
}
Visitor visitor = new VisitorImpl(rnd_);
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (!db_.accept(key.getBytes(), visitor, rnd_)) {
dberrprint(db_, "DB::accept");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Accepter[] accepters = new Accepter[thnum];
for (int i = 0; i < thnum; i++) {
accepters[i] = new Accepter(i, rnum, thnum, rnd, db);
accepters[i].setDefaultUncaughtExceptionHandler(EXH);
accepters[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
accepters[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (accepters[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
printf("getting records:\n");
stime = Utility.time();
class Getter extends Thread {
public Getter(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (db_.get(key) == null && db_.error().code() != Error.NOREC) {
dberrprint(db_, "DB::get");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Getter[] getters = new Getter[thnum];
for (int i = 0; i < thnum; i++) {
getters[i] = new Getter(i, rnum, thnum, rnd, db);
getters[i].setDefaultUncaughtExceptionHandler(EXH);
getters[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
getters[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (getters[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
if (etc) {
printf("traversing the database by the inner iterator:\n");
stime = Utility.time();
class InnerTraverser extends Thread {
public InnerTraverser(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
class VisitorImpl implements Visitor {
public VisitorImpl(int id, boolean rnd) {
id_ = id;
rnd_ = rnd;
cnt_ = 0;
}
public byte[] visit_full(byte[] key, byte[] value) {
cnt_++;
if (cnt_ % 100 == 0) Thread.yield();
byte[] rv = NOP;
if (rnd_) {
switch ((int)rand(7)) {
case 0: {
rv = String.format("%d%d", cnt_, cnt_).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
}
if (id_ < 1 && rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) {
printf(".");
if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) printf(" (%08d)\n", cnt_);
}
return rv;
}
public byte[] visit_empty(byte[] key) {
return NOP;
}
private int id_;
private boolean rnd_;
private long cnt_;
}
Visitor visitor = new VisitorImpl(id_, rnd_);
if (!db_.iterate(visitor, rnd_)) {
dberrprint(db_, "DB::iterate");
err_ = true;
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
InnerTraverser[] itraversers = new InnerTraverser[thnum];
for (int i = 0; i < thnum; i++) {
itraversers[i] = new InnerTraverser(i, rnum, thnum, rnd, db);
itraversers[i].setDefaultUncaughtExceptionHandler(EXH);
itraversers[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
itraversers[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (itraversers[i].error()) err = true;
}
if (rnd) printf(" (end)\n");
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
if (etc) {
printf("traversing the database by the outer cursor:\n");
stime = Utility.time();
class OuterTraverser extends Thread {
public OuterTraverser(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
class VisitorImpl implements Visitor {
public VisitorImpl(int id, long rnum, boolean rnd) {
id_ = id;
rnum_ = rnum;
rnd_ = rnd;
cnt_ = 0;
}
public byte[] visit_full(byte[] key, byte[] value) {
cnt_++;
if (cnt_ % 100 == 0) Thread.yield();
byte[] rv = NOP;
if (rnd_) {
switch ((int)rand(7)) {
case 0: {
rv = String.format("%d%d", cnt_, cnt_).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
}
if (id_ < 1 && rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) {
printf(".");
if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) printf(" (%08d)\n", cnt_);
}
return rv;
}
public byte[] visit_empty(byte[] key) {
return NOP;
}
private int id_;
private long rnum_;
private boolean rnd_;
private long cnt_;
}
Visitor visitor = new VisitorImpl(id_, rnum_, rnd_);
Cursor cur = db_.cursor();
if (!cur.jump() && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::jump");
err_ = true;
}
while (cur.accept(visitor, rnd_, false)) {
if (!cur.step() && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::step");
err_ = true;
}
}
if (db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::jump");
err_ = true;
}
if (!rnd_ || rand(2) == 0) cur.disable();
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
OuterTraverser[] otraversers = new OuterTraverser[thnum];
for (int i = 0; i < thnum; i++) {
otraversers[i] = new OuterTraverser(i, rnum, thnum, rnd, db);
otraversers[i].setDefaultUncaughtExceptionHandler(EXH);
otraversers[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
otraversers[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (otraversers[i].error()) err = true;
}
printf(" (end)\n");
etime = Utility.time();
dbmetaprint(db, false);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
printf("removing records:\n");
stime = Utility.time();
class Remover extends Thread {
public Remover(int id, long rnum, int thnum, boolean rnd, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
rnd_ = rnd;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
long base = id_ * rnum_;
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
String key = String.format("%08d", rnd_ ? rand(range) + 1 : base + i);
if (!db_.remove(key) && db_.error().code() != Error.NOREC) {
dberrprint(db_, "DB::remove");
err_ = true;
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
}
private int id_;
private long rnum_;
private int thnum_;
private boolean rnd_;
private DB db_;
private boolean err_;
}
Remover[] removers = new Remover[thnum];
for (int i = 0; i < thnum; i++) {
removers[i] = new Remover(i, rnum, thnum, rnd, db);
removers[i].setDefaultUncaughtExceptionHandler(EXH);
removers[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
removers[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (removers[i].error()) err = true;
}
etime = Utility.time();
dbmetaprint(db, true);
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
printf("closing the database:\n");
stime = Utility.time();
if (!db.close()) {
dberrprint(db, "DB::close");
err = true;
}
etime = Utility.time();
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
printf("%s\n\n", err ? "error" : "ok");
return err ? 1 : 0;
}
/** perform wicked command */
private static int procwicked(String path, long rnum, int thnum, int itnum) {
printf("<Wicked Test>\n path=%s rnum=%d thnum=%d itnum=%d\n\n",
path, rnum, thnum, itnum);
boolean err = false;
DB db = new DB();
int[] codes = { Error.SUCCESS, Error.NOIMPL, Error.MISC };
db.tune_exception_rule(codes);
db.tune_encoding("UTF-8");
for (int itcnt = 1; itcnt <= itnum; itcnt++) {
if (itnum > 1) printf("iteration %d:\n", itcnt);
double stime = Utility.time();
int omode = DB.OWRITER | DB.OCREATE;
if (itcnt == 1) omode |= DB.OTRUNCATE;
if (!db.open(path, omode)) {
dberrprint(db, "DB::open");
err = true;
}
class Operator extends Thread {
public Operator(int id, long rnum, int thnum, DB db) {
id_ = id;
rnum_ = rnum;
thnum_ = thnum;
db_ = db;
err_ = false;
}
public boolean error() {
return err_;
}
public void run() {
class VisitorImpl implements Visitor {
public VisitorImpl() {
cnt_ = 0;
}
public byte[] visit_full(byte[] key, byte[] value) {
cnt_++;
if (cnt_ % 100 == 0) Thread.yield();
byte[] rv = NOP;
switch ((int)rand(7)) {
case 0: {
rv = String.format("%d", cnt_).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
return rv;
}
public byte[] visit_empty(byte[] key) {
return visit_full(key, key);
}
private long cnt_;
}
Visitor visitor = new VisitorImpl();
Cursor cur = db_.cursor();
long range = rnum_ * thnum_;
for (long i = 1; !err_ && i <= rnum_; i++) {
boolean tran = rand(100) == 0;
if (tran && !db_.begin_transaction(rand(rnum_) == 0)) {
dberrprint(db_, "DB::begin_transaction");
tran = false;
err_ = true;
}
String key = String.format("%08d", rand(range) + 1);
switch ((int)rand(12)) {
case 0: {
if (!db_.set(key, key)) {
dberrprint(db_, "DB::set");
err_ = true;
}
break;
}
case 1: {
if (!db_.add(key, key) && db_.error().code() != Error.DUPREC) {
dberrprint(db_, "DB::add");
err_ = true;
}
break;
}
case 2: {
if (!db_.replace(key, key) && db_.error().code() != Error.NOREC) {
dberrprint(db_, "DB::replace");
err_ = true;
}
break;
}
case 3: {
if (!db_.append(key, key)) {
dberrprint(db_, "DB::append");
err_ = true;
}
break;
}
case 4: {
if (rand(2) == 0) {
if (db_.increment(key, rand(10), 0) == Long.MIN_VALUE &&
db_.error().code() != Error.LOGIC) {
dberrprint(db_, "DB::increment");
err_ = true;
}
} else {
if (Double.isNaN(db_.increment_double(key, rand(1000) / 100.0, 0)) &&
db_.error().code() != Error.LOGIC) {
dberrprint(db_, "DB::increment_double");
err_ = true;
}
}
break;
}
case 5: {
if (!db_.cas(key, key, key) && db_.error().code() != Error.LOGIC) {
dberrprint(db_, "DB::cas");
err_ = true;
}
break;
}
case 6: {
if (!db_.remove(key) && db_.error().code() != Error.NOREC) {
dberrprint(db_, "DB::remove");
err_ = true;
}
break;
}
case 7: {
if (!db_.accept(key.getBytes(), visitor, true)) {
dberrprint(db_, "DB::accept");
err_ = true;
}
break;
}
case 8: {
if (rand(10) == 0) {
if (rand(4) == 0) {
try {
if (!cur.jump_back(key) && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::jump_back");
err_ = true;
}
} catch (Error.XNOIMPL e) {}
} else {
if (!cur.jump(key) && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::jump");
err_ = true;
}
}
} else {
switch ((int)rand(6)) {
case 0: {
if (cur.get_key_str(false) == null &&
db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::get_key");
err_ = true;
}
break;
}
case 1: {
if (cur.get_value_str(false) == null &&
db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::get_value");
err_ = true;
}
break;
}
case 2: {
if (cur.get_str(false) == null &&
db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::get");
err_ = true;
}
break;
}
case 3: {
if (!cur.remove() && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::remove");
err_ = true;
}
break;
}
default: {
if (!cur.accept(visitor, true, rand(2) == 0) &&
db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::accept");
err_ = true;
}
break;
}
}
}
if (rand(2) == 0) {
if (!cur.step() && db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::step");
err_ = true;
}
}
if (rand(rnum_ / 50 + 1) == 0) {
String prefix = key.substring(0, key.length() - 1);
if (db_.match_prefix(prefix, rand(10)) == null) {
dberrprint(db_, "DB::match_prefix");
err_ = true;
}
}
if (rand(rnum_ / 50 + 1) == 0) {
String regex = key.substring(0, key.length() - 1);
if (db_.match_regex(regex, rand(10)) == null &&
db_.error().code() != Error.LOGIC) {
dberrprint(db_, "DB::match_regex");
err_ = true;
}
}
if (rand(10) == 0) {
Cursor paracur = db_.cursor();
paracur.jump(key);
if (!paracur.accept(visitor, true, rand(2) == 0) &&
db_.error().code() != Error.NOREC) {
dberrprint(db_, "Cursor::accept");
err_ = true;
}
paracur.disable();
}
break;
}
default: {
if (db_.get(key) == null && db_.error().code() != Error.NOREC) {
dberrprint(db_, "DB::get");
err_ = true;
}
break;
}
}
if (tran) {
if (rand(10) == 0) Thread.yield();
if (!db_.end_transaction(rand(10) > 0)) {
dberrprint(db_, "DB::end_transaction");
err_ = true;
}
}
if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
printf(".");
if (i == rnum_ || i % (rnum_ / 10) == 0) printf(" (%08d)\n", i);
}
}
if (rand(2) == 0) cur.disable();
}
private int id_;
private long rnum_;
private int thnum_;
private DB db_;
private boolean err_;
}
Operator[] operators = new Operator[thnum];
for (int i = 0; i < thnum; i++) {
operators[i] = new Operator(i, rnum, thnum, db);
operators[i].setDefaultUncaughtExceptionHandler(EXH);
operators[i].start();
}
for (int i = 0; i < thnum; i++) {
try {
operators[i].join();
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
err = true;
}
if (operators[i].error()) err = true;
}
dbmetaprint(db, itcnt == itnum);
if (!db.close()) {
dberrprint(db, "DB::close");
err = true;
}
double etime = Utility.time();
printf("time: %.3f\n", etime - stime);
printf("memory: %.3f\n", memusage() / 1024.0 / 1024.0);
}
printf("%s\n\n", err ? "error" : "ok");
return err ? 1 : 0;
}
/** perform order command */
private static int procmisc(String path) {
printf("<Miscellaneous Test>\n path=%s\n\n", path);
boolean err = false;
Utility.atoi("123.456abc");
Utility.atoix("123.456abc");
Utility.atof("123.456abc");
Utility.hash_murmur(path.getBytes());
Utility.hash_fnv(path.getBytes());
List<Cursor> dcurs = new ArrayList<Cursor>();
printf("opening the database:\n");
DB db = new DB();
try {
if (!db.open(path, DB.OWRITER | DB.OCREATE | DB.OTRUNCATE)) {
dberrprint(db, "DB::open");
err = true;
}
int[] codes = { Error.SUCCESS, Error.NOIMPL, Error.MISC };
db.tune_exception_rule(codes);
db.tune_encoding("UTF-8");
db.toString();
long rnum = 10000;
printf("setting records:\n");
for (long i = 0; i < rnum; i++) {
String key = String.format("%d", i);
db.set(key, key);
}
if (db.count() != rnum) {
dberrprint(db, "DB::count");
err = true;
}
printf("deploying cursors:\n");
for (int i = 1; i < 100; i++) {
Cursor cur = db.cursor();
String key = String.format("%d", i);
if (!cur.jump(key)) {
dberrprint(db, "Cursor::jump");
err = true;
}
switch (i % 3) {
case 0: {
dcurs.add(cur);
break;
}
case 1: {
cur.disable();
break;
}
}
cur.toString();
}
printf("getting records:\n");
for (Cursor cur : dcurs) {
if (cur.get_key(false) == null) {
dberrprint(db, "Cursor::get_key");
err = true;
}
}
printf("accepting visitor:\n");
class VisitorImpl implements Visitor {
public byte[] visit_full(byte[] key, byte[] value) {
byte[] rv = NOP;
String kstr = new String(key);
switch (Integer.parseInt(kstr) % 3) {
case 0: {
rv = String.format("full:%s", kstr).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
return rv;
}
public byte[] visit_empty(byte[] key) {
byte[] rv = NOP;
String kstr = new String(key);
switch (Integer.parseInt(kstr) % 3) {
case 0: {
rv = String.format("empty:%s", kstr).getBytes();
break;
}
case 1: {
rv = REMOVE;
break;
}
}
return rv;
}
}
VisitorImpl visitor = new VisitorImpl();
long end = rnum * 2;
for (long i = 0; i < end; i++) {
byte[] key = String.format("%d", i).getBytes();
if (!db.accept(key, visitor, true)) {
dberrprint(db, "DB::accept");
err = true;
}
}
printf("accepting visitor with a cursor:\n");
Cursor cur = db.cursor();
try {
if (!cur.jump_back()) {
dberrprint(db, "Cursor::jump");
err = true;
}
while (cur.accept(visitor, true, false)) {
cur.step_back();
}
} catch (Error.XNOIMPL e) {
if (!cur.jump()) {
dberrprint(db, "Cursor::jump");
err = true;
}
while (cur.accept(visitor, true, false)) {
cur.step();
}
}
printf("accepting visitor in bulk:\n");
byte[][] keys = new byte[10][];
for (int i = 0; i < keys.length; i++) {
keys[i] = String.format("%d", i).getBytes();
}
if (!db.accept_bulk(keys, visitor, true)) {
dberrprint(db, "DB::accept_bulk");
err = true;
}
byte[][] recs = new byte[20][];
for (int i = 0; i < recs.length; i++) {
recs[i] = String.format("%d", i).getBytes();
}
if (db.set_bulk(recs, true) != recs.length / 2) {
dberrprint(db, "DB::set_bulk");
err = true;
}
if (db.get_bulk(keys, true) == null) {
dberrprint(db, "DB::get_bulk");
err = true;
}
if (db.remove_bulk(keys, true) < 0) {
dberrprint(db, "DB::remove_bulk");
err = true;
}
Map<String, String> recmap = new HashMap<String, String>();
recmap.put("one", "first");
recmap.put("two", "second");
if (db.set_bulk(recmap, false) != recmap.size()) {
dberrprint(db, "DB::set_bulk");
err = true;
}
List<String> keylist = new ArrayList<String>();
keylist.add("one");
keylist.add("two");
recmap = db.get_bulk(keylist, false);
if (recmap == null || recmap.size() != keylist.size()) {
dberrprint(db, "DB::get_bulk");
err = true;
}
if (db.remove_bulk(keylist, false) != keylist.size()) {
dberrprint(db, "DB::remove_bulk");
err = true;
}
printf("synchronizing the database:\n");
class Informer implements FileProcessor {
public boolean process(String path, long count, long size) {
return true;
}
}
Informer informer = new Informer();
if (!db.synchronize(false, informer)) {
dberrprint(db, "DB::synchronize");
err = true;
}
if (!db.occupy(false, informer)) {
dberrprint(db, "DB::occupy");
err = true;
}
printf("performing transaction:\n");
if (db.begin_transaction(false)) {
if (!db.set("tako", "ika")) {
dberrprint(db, "DB::set");
err = true;
}
if (!db.end_transaction(true)) {
dberrprint(db, "DB::end_transaction");
err = true;
}
} else {
dberrprint(db, "DB::begin_transaction");
err = true;
}
String value = db.get("tako");
if (value == null || !value.equals("ika")) {
dberrprint(db, "DB::get");
err = true;
}
if (!db.remove("tako")) {
dberrprint(db, "DB::remove");
err = true;
}
long cnt = db.count();
if (db.begin_transaction(false)) {
if (!db.set("tako", "ika") || !db.set("kani", "ebi")) {
dberrprint(db, "DB::set");
err = true;
}
if (!db.end_transaction(false)) {
dberrprint(db, "DB::end_transaction");
err = true;
}
} else {
dberrprint(db, "DB::begin_transaction");
err = true;
}
if (db.get("tako") != null || db.get("kani") != null || db.count() != cnt) {
dberrprint(db, "DB::transaction");
err = true;
}
String corepath = db.path();
String suffix = null;
if (corepath.endsWith(".kch")) {
suffix = ".kch";
} else if (corepath.endsWith(".kct")) {
suffix = ".kct";
} else if (corepath.endsWith(".kcd")) {
suffix = ".kcd";
} else if (corepath.endsWith(".kcf")) {
suffix = ".kcf";
}
if (suffix != null) {
printf("performing copy and merge:\n");
String[] copypaths = new String[2];
for (int i = 0; i < copypaths.length; i++) {
copypaths[i] = String.format("%s.%d%s", corepath, i + 1, suffix);
}
DB[] srcary = new DB[copypaths.length];
for (int i = 0; i < copypaths.length; i++) {
if (!db.copy(copypaths[i])) {
dberrprint(db, "DB::copy");
err = true;
}
srcary[i] = new DB();
if (!srcary[i].open(copypaths[i], DB.OREADER)) {
dberrprint(srcary[i], "DB::open");
err = true;
}
}
if (!db.merge(srcary, DB.MAPPEND)) {
dberrprint(db, "DB::merge");
err = true;
}
for (int i = 0; i < copypaths.length; i++) {
if (!srcary[i].close()) {
dberrprint(srcary[i], "DB::close");
err = true;
}
Utility.remove_files_recursively(copypaths[i]);
}
}
printf("executing mapreduce process:\n");
class MapReduceImpl extends MapReduce {
public boolean map(byte[] key, byte[] value) {
mapcnt_++;
return emit(value, key);
}
public boolean reduce(byte[] key, ValueIterator iter) {
byte[] value;
while ((value = iter.next()) != null) {
redcnt_++;
}
return true;
}
public boolean preprocess() {
emit("pre".getBytes(), "process".getBytes());
emit("PROCESS".getBytes(), "PRE".getBytes());
return true;
}
public boolean midprocess() {
emit("mid".getBytes(), "process".getBytes());
emit("PROCESS".getBytes(), "MID".getBytes());
return true;
}
public boolean postprocess() {
return true;
}
public long mapcnt() {
return mapcnt_;
}
public long redcnt() {
return redcnt_;
}
private long mapcnt_ = 0;
private long redcnt_ = 0;
}
rnum = db.count();
MapReduceImpl mr = new MapReduceImpl();
if (!mr.execute(db, null, 0)) {
dberrprint(db, "MapReduce::execute");
err = true;
}
if (mr.mapcnt() != rnum || mr.redcnt() != rnum + 4) {
dberrprint(db, "MapReduce::execute");
err = true;
}
} finally {
printf("closing the database:\n");
if (!db.close()) {
dberrprint(db, "DB::close");
err = true;
}
}
printf("checking the exceptional mode:\n");
db = new DB(DB.GEXCEPTIONAL);
try {
db.open("hoge", DB.OREADER);
dberrprint(db, "DB::open");
err = true;
} catch (Error.XINVALID e) {
if (e.code() != Error.INVALID) {
dberrprint(db, "DB::open");
err = true;
}
}
printf("%s\n\n", err ? "error" : "ok");
return err ? 1 : 0;
}
/** perform memsize command */
private static int procmemsize(long rnum, String path) {
System.gc();
long musage = memusagerss();
double stime = Utility.time();
long count = -1;
if (path == null) {
int bnum = rnum < Integer.MAX_VALUE ? (int)rnum : Integer.MAX_VALUE;
Map<String, String> map = new HashMap<String, String>(bnum, 100);
for (long i = 0; i < rnum; i++) {
String key = String.format("%08d", i);
String value = String.format("%08d", i);
map.put(key, value);
}
count = map.size();
} else {
DB db = new DB();
if (db.open(path, DB.OWRITER | DB.OCREATE | DB.OTRUNCATE)) {
for (long i = 0; i < rnum; i++) {
String key = String.format("%08d", i);
String value = String.format("%08d", i);
db.set(key, value);
}
count = db.count();
db.close();
}
}
printf("count: %d\n", count);
double etime = Utility.time();
printf("time: %.3f\n", etime - stime);
System.gc();
printf("usage: %.3f MB\n", (memusagerss() - musage) / 1024.0 / 1024.0);
return 0;
}
/** print formatted information string and flush the buffer */
private static void printf(String format, Object... args) {
STDOUT.printf(format, args);
STDOUT.flush();
}
/** get a random number */
private static long rand(long range) {
long num = (long)(RND.nextDouble() * range);
return num < range ? num : 0;
}
/** get the memory usage */
private static long memusage() {
Runtime rt = Runtime.getRuntime();
return rt.totalMemory() - rt.freeMemory();
}
/** get the memory usage of RSS */
private static long memusagerss() {
long rss = -1;
try {
Reader fr = new FileReader("/proc/self/status");
LineNumberReader lnr = new LineNumberReader(fr);
String line;
while ((line = lnr.readLine()) != null) {
int idx = line.indexOf(':');
if (idx < 0) continue;
String name = line.substring(0, idx);
idx++;
while (idx < line.length() && Character.isWhitespace(line.charAt(idx))) idx++;
String value = line.substring(idx, line.length());
if (name.equals("VmRSS")) {
rss = Utility.atoix(value);
break;
}
}
fr.close();
} catch (Exception e) {
}
return rss;
}
//----------------------------------------------------------------
// private static inner classes
//----------------------------------------------------------------
private static class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread th, Throwable e) {
e.printStackTrace();
System.exit(1);
}
}
//----------------------------------------------------------------
// private constants
//----------------------------------------------------------------
/** The standard output stream. */
private static final PrintStream STDOUT = System.out;
/** The standard error stream. */
private static final PrintStream STDERR = System.err;
/** The rondom generator. */
private static final Random RND = new Random();
/** The exception handler. */
private static final ExceptionHandler EXH = new ExceptionHandler();
//----------------------------------------------------------------
// private methods
//----------------------------------------------------------------
/**
* Dummy constructor.
*/
private Test() {}
}
// END OF FILE