package org.infinispan.persistence.sifs;
import static org.infinispan.persistence.PersistenceUtil.internalMetadata;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;
import java.io.File;
import org.infinispan.commons.util.Util;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.marshall.core.MarshalledEntry;
import org.infinispan.marshall.core.MarshalledEntryImpl;
import org.infinispan.persistence.BaseStoreTest;
import org.infinispan.persistence.sifs.configuration.SoftIndexFileStoreConfigurationBuilder;
import org.infinispan.persistence.spi.AdvancedLoadWriteStore;
import org.infinispan.persistence.spi.PersistenceException;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.test.fwk.TestInternalCacheEntryFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Low level single-file cache store tests.
*
* @author Galder ZamarreƱo
* @since 6.0
*/
@Test(groups = "unit", testName = "persistence.SoftIndexFileStoreTest")
public class SoftIndexFileStoreTest extends BaseStoreTest {
SoftIndexFileStore store;
String tmpDirectory;
boolean startIndex = true;
boolean keepIndex = false;
@BeforeClass
protected void setUpTempDir() {
tmpDirectory = TestingUtil.tmpDirectory(this.getClass());
}
@AfterClass
protected void clearTempDir() {
Util.recursiveFileRemove(tmpDirectory);
}
@Override
protected AdvancedLoadWriteStore createStore() throws Exception {
clearTempDir();
store = new SoftIndexFileStore() {
boolean firstTime = true;
@Override
protected void startIndex() {
if (startIndex) {
super.startIndex();
}
}
@Override
public void start() {
super.start();
if (!firstTime) {
assertEquals(keepIndex, isIndexLoaded());
}
firstTime = false;
}
@Override
public void stop() {
super.stop();
if (!keepIndex) {
for (File f : new File(tmpDirectory).listFiles()) {
if (!f.isDirectory()) {
f.delete();
}
}
}
}
};
ConfigurationBuilder builder = TestCacheManagerFactory
.getDefaultCacheConfiguration(false);
builder.persistence()
.addStore(SoftIndexFileStoreConfigurationBuilder.class)
.indexLocation(tmpDirectory).dataLocation(tmpDirectory + "/data")
.maxFileSize(1000);
store.init(createContext(builder.build()));
return store;
}
@Override
protected boolean storePurgesAllExpired() {
return false;
}
public void testLoadUnload() {
int numEntries = 10000;
for (int i = 0; i < numEntries; ++i) {
InternalCacheEntry ice = TestInternalCacheEntryFactory.create(key(i), "value" + i);
store.write(new MarshalledEntryImpl(ice.getKey(), ice.getValue(), internalMetadata(ice), getMarshaller()));
}
for (int i = 0; i < numEntries; ++i) {
assertNotNull(key(i), store.load(key(i)));
assertTrue(key(i), store.delete(key(i)));
}
store.clear();
for (int i = 0; i < numEntries; ++i) {
InternalCacheEntry ice = TestInternalCacheEntryFactory.create(key(i), "value" + i);
store.write(new MarshalledEntryImpl(ice.getKey(), ice.getValue(), internalMetadata(ice), getMarshaller()));
}
for (int i = numEntries - 1; i >= 0; --i) {
assertNotNull(key(i), store.load(key(i)));
assertTrue(key(i), store.delete(key(i)));
}
}
// test for ISPN-5658
public void testStopStartAndMultipleWrites() {
MarshalledEntry<Object, Object> entry1 = marshalledEntry(internalCacheEntry("k1", "v1", -1));
MarshalledEntry<Object, Object> entry2 = marshalledEntry(internalCacheEntry("k1", "v2", -1));
store.write(entry1);
store.write(entry1);
store.write(entry1);
store.stop();
store.start();
MarshalledEntry entry = store.load("k1");
assertNotNull(entry);
assertEquals("v1", entry.getValue());
store.write(entry2);
store.stop();
store.start();
entry = store.load("k1");
assertNotNull(entry);
assertEquals("v2", entry.getValue());
}
// test for ISPN-5743
public void testStopStartWithRemoves() {
String KEY = "k1";
MarshalledEntry<Object, Object> entry1 = marshalledEntry(internalCacheEntry(KEY, "v1", -1));
MarshalledEntry<Object, Object> entry2 = marshalledEntry(internalCacheEntry(KEY, "v2", -1));
store.write(entry1);
store.delete(KEY);
store.stop();
store.start();
assertNull(store.load(KEY));
store.write(entry2);
store.delete(KEY);
store.write(entry1);
store.stop();
startIndex = false;
store.start();
assertEquals(entry1.getValue(), store.load(KEY).getValue());
startIndex = true;
store.startIndex();
}
// test for ISPN-5753
public void testOverrideWithExpirableAndCompaction() throws InterruptedException {
// write immortal entry
store.write(marshalledEntry(internalCacheEntry("key", "value1", -1)));
writeGibberish(); // make sure that compaction happens - value1 is evacuated
log.debug("Size :" + store.size());
store.write(marshalledEntry(internalCacheEntry("key", "value2", 1)));
timeService.advance(2);
writeGibberish(); // make sure that compaction happens - value2 expires
store.stop();
store.start();
// value1 has been overwritten and value2 has expired
MarshalledEntry entry = store.load("key");
assertNull(entry != null ? entry.getKey() + "=" + entry.getValue() : null, entry);
}
public void testStopStartWithLoadDoesNotNukeValues() throws InterruptedException, PersistenceException {
keepIndex = true;
try {
testStopStartDoesNotNukeValues();
} finally {
keepIndex = false;
}
}
private void writeGibberish() {
for (int i = 0; i < 100; ++i) {
store.write(marshalledEntry(internalCacheEntry("foo", "bar", -1)));
store.delete("foo");
}
}
private String key(int i) {
return String.format("key%010d", i);
}
}