use of org.cojen.tupl.Database in project Tupl by cojen.
the class Compact method main.
/**
* @param args a base file path for the database, a compaction target, and an optional
* cache size
*/
public static void main(String[] args) throws Exception {
var config = new DatabaseConfig().createFilePath(false).baseFilePath(args[0]).eventListener(EventListener.printTo(System.out).ignore(EventType.Category.CHECKPOINT)).checkpointSizeThreshold(0);
double target = Double.parseDouble(args[1]);
if (args.length > 2) {
config.minCacheSize(Long.parseLong(args[2]));
}
Database db = Database.open(config);
System.out.println("Before: " + db.stats());
db.compactFile(null, target);
System.out.println("After: " + db.stats());
}
use of org.cojen.tupl.Database in project Tupl by cojen.
the class DatabaseReplicatorTest method prepareTransfer.
private void prepareTransfer(boolean prepareCommit) throws Exception {
// Prepared transaction should be transferred to replica and finish.
var dbQueue = new LinkedBlockingQueue<Database>();
var txnQueue = new LinkedBlockingQueue<Transaction>();
Supplier<PrepareHandler> supplier = () -> new PrepareHandler() {
private Database mDb;
@Override
public void init(Database db) {
mDb = db;
}
@Override
public void prepare(Transaction txn, byte[] message) throws IOException {
dbQueue.add(mDb);
txnQueue.add(txn);
}
@Override
public void prepareCommit(Transaction txn, byte[] message) throws IOException {
prepare(txn, message);
}
};
Database[] dbs = startGroup(2, Role.NORMAL, supplier);
Database leaderDb = dbs[0];
Database replicaDb = dbs[1];
Index leaderIx = leaderDb.openIndex("test");
// Wait for replica to catch up.
fence(leaderDb, replicaDb);
Index replicaIx = replicaDb.openIndex("test");
Transaction txn1 = leaderDb.newTransaction();
PrepareHandler handler = leaderDb.prepareWriter("TestHandler");
byte[] k1 = "k1".getBytes();
byte[] v1 = "v1".getBytes();
leaderIx.store(txn1, k1, v1);
if (prepareCommit) {
handler.prepareCommit(txn1, null);
fastAssertArrayEquals(v1, leaderIx.load(null, k1));
} else {
handler.prepare(txn1, null);
try {
leaderIx.load(null, k1);
fail();
} catch (LockTimeoutException e) {
}
}
leaderDb.failover();
// Replica is now the leader and should have the transaction.
assertEquals(replicaDb, dbQueue.take());
Transaction txn2 = txnQueue.take();
assertNotEquals(txn1, txn2);
assertEquals(txn1.id(), txn2.id());
fastAssertArrayEquals(v1, replicaIx.load(txn2, k1));
byte[] k2 = "k2".getBytes();
byte[] v2 = "v2".getBytes();
replicaIx.store(txn2, k2, v2);
if (prepareCommit) {
fastAssertArrayEquals(v1, replicaIx.load(null, k1));
} else {
try {
replicaIx.load(null, k1);
fail();
} catch (LockTimeoutException e) {
}
}
txn2.commit();
// Wait for old leader to catch up. This will fail at first because the old leader
// transaction is stuck.
boolean pass = true;
try {
fence(replicaDb, leaderDb, true);
pass = false;
} catch (AssertionError e) {
}
assertTrue(pass);
try {
txn1.commit();
fail();
} catch (UnmodifiableReplicaException e) {
// This will unstick the transaction.
}
fence(replicaDb, leaderDb);
// Verify that the old leader observes the committed changes.
fastAssertArrayEquals(v1, leaderIx.load(null, k1));
fastAssertArrayEquals(v2, leaderIx.load(null, k2));
}
use of org.cojen.tupl.Database in project Tupl by cojen.
the class DatabaseReplicatorTest method largeWrite.
@Test
public void largeWrite() throws Exception {
Database[] dbs = startGroup(1);
Database db = dbs[0];
Index ix = db.openIndex("test");
var value = new byte[100_000];
// illegal redo op
Arrays.fill(value, 0, value.length, (byte) 0x7f);
byte[] key = "hello".getBytes();
Transaction txn = db.newTransaction();
Cursor c = ix.newCursor(txn);
c.find(key);
// This used to hang due to a bug. The commit index was too high, and so it wouldn't be
// confirmed.
c.commit(value);
db.checkpoint();
db = closeAndReopen(0);
ix = db.openIndex("test");
fastAssertArrayEquals(value, ix.load(null, key));
db.close();
}
use of org.cojen.tupl.Database in project Tupl by cojen.
the class DatabaseReplicatorTest method prepareBlank.
private void prepareBlank(boolean prepareCommit) throws Exception {
// Test against a prepared transaction that has no changes. It should still ensure that
// the transaction is created properly on the replica.
var dbQueue = new LinkedBlockingQueue<Database>();
var txnQueue = new LinkedBlockingQueue<Transaction>();
var msgQueue = new LinkedBlockingQueue<byte[]>();
var pcQueue = new LinkedBlockingQueue<Boolean>();
Supplier<PrepareHandler> supplier = () -> new PrepareHandler() {
private Database mDb;
@Override
public void init(Database db) {
mDb = db;
}
@Override
public void prepare(Transaction txn, byte[] message) throws IOException {
doPrepare(txn, message, false);
}
@Override
public void prepareCommit(Transaction txn, byte[] message) throws IOException {
doPrepare(txn, message, true);
}
private void doPrepare(Transaction txn, byte[] message, boolean commit) throws IOException {
dbQueue.add(mDb);
txnQueue.add(txn);
msgQueue.add(message);
pcQueue.add(commit);
}
};
Database[] dbs = startGroup(2, Role.NORMAL, supplier);
Database leaderDb = dbs[0];
Database replicaDb = dbs[1];
Index leaderIx = leaderDb.openIndex("test");
// Wait for replica to catch up.
fence(leaderDb, replicaDb);
Index replicaIx = replicaDb.openIndex("test");
Transaction txn1 = leaderDb.newTransaction();
PrepareHandler handler = leaderDb.prepareWriter("TestHandler");
if (prepareCommit) {
handler.prepareCommit(txn1, "message".getBytes());
} else {
handler.prepare(txn1, "message".getBytes());
}
leaderDb.failover();
// Must capture the id before it gets replaced.
long txnId = txn1.id();
try {
txn1.commit();
fail();
} catch (UnmodifiableReplicaException e) {
// This will unstick the transaction.
}
// Replica is now the leader and should have the transaction.
assertEquals(replicaDb, dbQueue.take());
Transaction txn2 = txnQueue.take();
assertNotEquals(txn1, txn2);
assertEquals(txnId, txn2.id());
fastAssertArrayEquals("message".getBytes(), msgQueue.take());
assertEquals(prepareCommit, pcQueue.take());
byte[] k1 = "k1".getBytes();
byte[] v1 = "v1".getBytes();
replicaIx.store(txn2, k1, v1);
txn2.commit();
fence(replicaDb, leaderDb);
// Verify that the old leader observes the committed changes.
fastAssertArrayEquals(v1, leaderIx.load(null, k1));
}
use of org.cojen.tupl.Database in project Tupl by cojen.
the class DatabaseReplicatorTest method basicTest.
private void basicTest(int memberCount) throws Exception {
Database[] dbs = startGroup(memberCount);
Index ix0 = dbs[0].openIndex("test");
for (int t = 0; t < 10; t++) {
byte[] key = ("hello-" + t).getBytes();
byte[] value = ("world-" + t).getBytes();
ix0.store(null, key, value);
fastAssertArrayEquals(value, ix0.load(null, key));
for (int i = 0; i < dbs.length; i++) {
for (int q = 100; --q >= 0; ) {
byte[] actual = null;
try {
Index ix = dbs[i].openIndex("test");
actual = ix.load(null, key);
fastAssertArrayEquals(value, actual);
break;
} catch (UnmodifiableReplicaException e) {
// Index doesn't exist yet due to replication delay.
if (q == 0) {
throw e;
}
} catch (AssertionError e) {
// Value doesn't exist yet due to replication delay.
if (q == 0 || actual != null) {
throw e;
}
}
TestUtils.sleep(100);
}
}
}
}
Aggregations