/* * 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.map.diskmap.DBStructure; import com.github.geophile.erdo.map.diskmap.Manifest; import com.github.geophile.erdo.transaction.TimestampSet; import com.github.geophile.erdo.util.FileUtil; import com.github.geophile.erdo.util.Interval; 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.List; import static java.lang.Math.max; import static java.lang.Math.min; import static org.junit.Assert.assertEquals; // Transaction timestamps should be assigned without holes, even with read-only transactions. public class OrderedMapTransactionTimestampTest { @BeforeClass public static void beforeClass() throws IOException { DB_DIRECTORY = new File(FileUtil.tempDirectory(), DB_NAME); } @Before public void before() { FileUtil.deleteDirectory(DB_DIRECTORY); } @After public void after() { FACTORY.reset(); } @Test public void testAllUpdates() throws IOException, InterruptedException, DeadlockException, TransactionRolledBackException { Database db = Database.createDatabase(DB_DIRECTORY, Configuration.defaultConfiguration()); OrderedMap map = db.createMap(MAP_NAME, RecordFactory.simpleRecordFactory(TestKey.class, TestRecord.class)); TestRecord record; final int N = 10; for (int i = 0; i < N; i++) { record = TestRecord.createRecord(i, null); map.put(record); db.commitTransaction(); } db.close(); TimestampSet allTimestamps = timestamps(manifests()); int count = 0; long minTimestamp = Long.MAX_VALUE; long maxTimestamp = Long.MIN_VALUE; for (Interval interval : allTimestamps) { minTimestamp = min(minTimestamp, interval.min()); maxTimestamp = max(maxTimestamp, interval.max()); count++; } assertEquals(1, count); assertEquals(0, minTimestamp); assertEquals(N - 1, maxTimestamp); } @Test public void testUpdatesAndReads() throws IOException, InterruptedException, DeadlockException, TransactionRolledBackException { Database db = Database.createDatabase(DB_DIRECTORY, Configuration.defaultConfiguration()); OrderedMap map = db.createMap(MAP_NAME, RecordFactory.simpleRecordFactory(TestKey.class, TestRecord.class)); TestRecord record; final int N = 10; for (int i = 0; i < N; i++) { // Write transaction record = TestRecord.createRecord(i, null); map.put(record); db.commitTransaction(); // Read transaction Cursor cursor = map.first(); while (cursor.next() != null); db.commitTransaction(); } db.close(); TimestampSet allTimestamps = timestamps(manifests()); int count = 0; long minTimestamp = Long.MAX_VALUE; long maxTimestamp = Long.MIN_VALUE; for (Interval interval : allTimestamps) { minTimestamp = min(minTimestamp, interval.min()); maxTimestamp = max(maxTimestamp, interval.max()); count++; } assertEquals(1, count); assertEquals(0, minTimestamp); assertEquals(2 * N - 1, maxTimestamp); } @Test public void testUpdatesAndRollbacks() throws IOException, InterruptedException, DeadlockException, TransactionRolledBackException { Database db = Database.createDatabase(DB_DIRECTORY, Configuration.defaultConfiguration()); OrderedMap map = db.createMap(MAP_NAME, RecordFactory.simpleRecordFactory(TestKey.class, TestRecord.class)); TestRecord record; final int N = 10; for (int i = 0; i < N; i++) { // commit an update record = TestRecord.createRecord(i, null); map.put(record); db.commitTransaction(); // rollback an update record = TestRecord.createRecord(i, null); map.put(record); db.rollbackTransaction(); } db.close(); TimestampSet allTimestamps = timestamps(manifests()); // System.out.println(allTimestamps); int count = 0; long minTimestamp = Long.MAX_VALUE; long maxTimestamp = Long.MIN_VALUE; for (Interval interval : allTimestamps) { minTimestamp = min(minTimestamp, interval.min()); maxTimestamp = max(maxTimestamp, interval.max()); count++; } assertEquals(1, count); assertEquals(0, minTimestamp); assertEquals(N - 1, maxTimestamp); } private TimestampSet timestamps(List<Manifest> manifests) { TimestampSet allTimestamps = new TimestampSet(); for (Manifest manifest : manifests) { TimestampSet timestamps = manifest.timestamps(); allTimestamps = allTimestamps.union(timestamps); } return allTimestamps; } private List<Manifest> manifests() throws IOException { List<Manifest> manifests = new ArrayList<>(); DBStructure dbStructure = new DBStructure(DB_DIRECTORY); for (File manifestFile : dbStructure.forestDirectory().listFiles()) { manifests.add(Manifest.read(manifestFile)); } return manifests; } private static final TestFactory FACTORY = new TestFactory(); private static final String DB_NAME = "erdo"; private static File DB_DIRECTORY; private static final String MAP_NAME = "map"; }