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); } }