/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo; import com.github.geophile.erdo.apiimpl.DatabaseImpl; import com.github.geophile.erdo.apiimpl.DatabaseOnDisk; import com.github.geophile.erdo.util.FileUtil; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.fail; public class CommitTest { @BeforeClass public static void beforeClass() { FACTORY = new TestFactory(); } @Before public void before() throws IOException, InterruptedException { final File DB_DIRECTORY = new File(FileUtil.tempDirectory(), DB_NAME); FileUtil.deleteDirectory(DB_DIRECTORY); db = DatabaseOnDisk.createDatabase(DB_DIRECTORY, FACTORY); } @After public void after() { FACTORY.reset(); } @Test public void testSynchronousCommit() throws IOException, InterruptedException, DeadlockException, TransactionRolledBackException { OrderedMap map = db.createMap(MAP_NAME, RecordFactory.simpleRecordFactory(TestKey.class, TestRecord.class)); int count = 0; while (count < RECORDS) { map.ensurePresent(TestRecord.createRecord(count++, FILLER)); if (count % RECORDS_PER_TRANSACTION == 0) { /* System.out.println(String.format("Commit %s", count)); */ db.commitTransaction(); } } // Check contents Cursor cursor = map.first(); AbstractRecord record; int expected = 0; while ((record = cursor.next()) != null) { assertEquals(expected++, key(record)); } db.close(); } @Test public void testAsynchronousCommit() throws IOException, InterruptedException, DeadlockException, TransactionRolledBackException { OrderedMap map = db.createMap(MAP_NAME, RecordFactory.simpleRecordFactory(TestKey.class, TestRecord.class)); final List<Integer> commitCounts = new ArrayList<>(); TransactionCallback callback = new TransactionCallback() { public void whenDurable(Object commitInfo) { commitCounts.add((Integer) commitInfo); /* System.out.println(String.format("%s: Callback for %s: %s/%s", System.currentTimeMillis(), commitInfo, commitCounts.size(), TRANSACTIONS)); */ synchronized (commitCounts) { if (commitCounts.size() == TRANSACTIONS) { commitCounts.notify(); } } } }; int count = 0; while (count < RECORDS) { map.ensurePresent(TestRecord.createRecord(count++, FILLER)); if (count % RECORDS_PER_TRANSACTION == 0) { /* System.out.println(String.format("%s: Commit %s", System.currentTimeMillis(), count)); */ db.commitTransactionAsynchronously(callback, count); } } db.flush(); long startWait = System.currentTimeMillis(); synchronized (commitCounts) { while (commitCounts.size() < TRANSACTIONS) { commitCounts.wait(1000); long now = System.currentTimeMillis(); if (now - startWait > 10000) { System.out.println(String.format("Waiting too long, commitCounts.size() = %s, TRANSACTIONS = %s", commitCounts.size(), TRANSACTIONS)); fail(); } } } Collections.sort(commitCounts); int expected = 0; for (Integer commitCount : commitCounts) { expected += RECORDS_PER_TRANSACTION; assertEquals(expected, commitCount.intValue()); } /* System.out.println("Callbacks complete"); */ // Check contents Cursor cursor = map.first(); AbstractRecord record; expected = 0; while ((record = cursor.next()) != null) { assertEquals(expected++, key(record)); } db.close(); } private int key(AbstractRecord record) { return ((TestKey) record.key()).key(); } private void dump(String label, OrderedMap map) throws IOException, InterruptedException { System.out.println(label); Cursor cursor = map.first(); AbstractRecord record; while ((record = cursor.next()) != null) { System.out.println(String.format(" %s, deleted: %s", record, record.deleted())); } } private static final String DB_NAME = "erdo"; private static final String MAP_NAME = "map"; private static final int RECORDS = 1000000; private static final int RECORDS_PER_TRANSACTION = 1000; private static final int TRANSACTIONS = RECORDS / RECORDS_PER_TRANSACTION; private static final String FILLER = "xxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx"; private static TestFactory FACTORY; private Configuration configuration; private DatabaseImpl db; }