NativeStoreTxnTest.java
/*******************************************************************************
* Copyright (c) 2019 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.sail.nativerdf;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.File;
import java.nio.file.Files;
import org.eclipse.rdf4j.common.io.NioFile;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.model.vocabulary.FOAF;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.sail.nativerdf.btree.RecordIterator;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
public class NativeStoreTxnTest {
@TempDir
File tempFolder;
protected Repository repo;
protected ValueFactory vf = SimpleValueFactory.getInstance();
protected IRI ctx = vf.createIRI("http://ex.org/ctx");
@BeforeEach
public void before() {
File dataDir = new File(tempFolder, "dbmodel");
repo = new SailRepository(new NativeStore(dataDir, "spoc,posc"));
repo.init();
}
@AfterEach
public void after() {
repo.shutDown();
}
@Test
public void testTxncacheCleanup() throws Exception {
/*
* Test for issue # On windows the txncacheXXX.dat files did not get properly deleted, as the file is locked
* when the deletion is attempted.
*/
IRI res = vf.createIRI("http://ex.org/s");
addStmt(vf.createStatement(res, RDF.TYPE, FOAF.PERSON));
Statement st1 = vf.createStatement(res, RDFS.LABEL, vf.createLiteral("test"));
addStmt(st1);
Statement remStmt = vf.createStatement(res, RDFS.LABEL, vf.createLiteral("test"), ctx);
removeStmt(remStmt);
File repoDir = repo.getDataDir();
System.out.println("Data dir: " + repoDir);
for (File file : repoDir.listFiles()) {
System.out.println("# " + file.getName());
}
assertEquals(15, repoDir.listFiles().length);
// make sure there is no txncacheXXX.dat file
assertFalse(Files.list(repoDir.getAbsoluteFile().toPath())
.anyMatch(file -> file.toFile().getName().matches("txncache[0-9]+.*dat")));
try (RepositoryConnection conn = repo.getConnection()) {
assertEquals(1, conn.size());
}
}
protected void addStmt(Statement stmt) {
try (RepositoryConnection conn = repo.getConnection()) {
conn.begin();
conn.add(stmt, ctx);
conn.commit();
}
}
protected void removeStmt(Statement stmt) {
try (RepositoryConnection conn = repo.getConnection()) {
conn.begin();
conn.remove(stmt);
conn.commit();
}
}
@Test
public void testOldTxnStatusFile() throws Exception {
TripleStore tripleStore = new TripleStore(repo.getDataDir(), "spoc");
try {
tripleStore.startTransaction();
tripleStore.storeTriple(1, 2, 3, 4);
// forget to commit or rollback
} finally {
tripleStore.close();
}
File txnStatusFile = new File(repo.getDataDir().getAbsolutePath() + "/txn-status");
// write old format of txn-status
NioFile nioFile = new NioFile(txnStatusFile);
byte[] bytes = "COMMITTING".getBytes(US_ASCII);
nioFile.truncate(bytes.length);
nioFile.writeBytes(bytes, 0);
// Try to restore from the uncompleted transaction
tripleStore = new TripleStore(repo.getDataDir(), "spoc");
try {
try (RecordIterator iter = tripleStore.getTriples(-1, -1, -1, -1)) {
// iter should contain exactly one element
assertNotNull(iter.next());
assertNull(iter.next());
}
} finally {
tripleStore.close();
}
TxnStatusFile.TxnStatus currentStatus = new TxnStatusFile(repo.getDataDir()).getTxnStatus();
assertEquals(TxnStatusFile.TxnStatus.NONE, currentStatus);
}
@Test
public void testOldTxnStatusesDoNotConflict() {
String[] oldTxtStatuses = { "NONE", "ACTIVE", "COMMITTING", "ROLLING_BACK", "UNKNOWN" };
for (String value1 : oldTxtStatuses) {
for (TxnStatusFile.TxnStatus value2 : TxnStatusFile.TxnStatus.values()) {
byte firstByteInOldValue = value1.getBytes(US_ASCII)[0];
byte firstByteInNewValue = value2.getOnDisk()[0];
assertNotEquals(firstByteInOldValue, firstByteInNewValue);
}
}
}
}