package org.infinispan.lucene;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Collections;
import java.util.Set;
import org.infinispan.Cache;
import org.infinispan.lucene.impl.FileListCacheValue;
import org.testng.AssertJUnit;
/**
* DirectoryIntegrityCheck contains helpers to assert assumptions we make on the structure of an
* index as stored in an Infinispan cache.
*
* @author Sanne Grinovero
* @since 4.1
*/
public class DirectoryIntegrityCheck {
private DirectoryIntegrityCheck() {
//not to be instantiated
}
/**
* Verifies that no garbage elements are left over in the cache and that for each type of object
* the expected value is stored. Also asserts for proper size metadata comparing to actual bytes
* used in chunks. It's assumed that only one index is stored in the inspected cache, and that
* the index is not being used by IndexReaders or IndexWriters.
*
* @param cache
* The cache to inspect
* @param indexName
* The name of the unique index stored in the cache
*/
public static void verifyDirectoryStructure(Cache cache, String indexName) {
verifyDirectoryStructure(cache, indexName, false, Collections.emptySet(), -1);
}
public static void verifyDirectoryStructure(Cache cache, String indexName, Set<String> ignoreFiles) {
verifyDirectoryStructure(cache, indexName, false, ignoreFiles, -1);
}
public static void verifyDirectoryStructure(Cache cache, String indexName, boolean wasAStressTest, int affinitySegmentId) {
verifyDirectoryStructure(cache,indexName,wasAStressTest, Collections.emptySet(), affinitySegmentId);
}
public static void verifyDirectoryStructure(Cache cache, String indexName, boolean wasAStressTest, Set<String> ignoreFiles, int affinitySegmentId) {
FileListCacheValue fileList = (FileListCacheValue) cache.get(new FileListCacheKey(indexName, affinitySegmentId));
assertNotNull(fileList);
int fileListCacheKeyInstances = 0;
for (Object key : cache.keySet()) {
if (key instanceof ChunkCacheKey) {
ChunkCacheKey existingChunkKey = (ChunkCacheKey) key;
String filename = existingChunkKey.getFileName();
assertEquals(existingChunkKey.getIndexName(), indexName);
// the chunk must either match an entry in fileList or have a pending readLock:
// if (fileList.contains(filename) == false) {
// verifyReadlockExists(cache, indexName, filename);
// }
Object value = cache.get(existingChunkKey);
assertNotNull(value);
assertTrue(value instanceof byte[]);
byte[] buffer = (byte[]) cache.get(existingChunkKey);
assertTrue(buffer.length != 0);
} else if (key instanceof FileCacheKey) {
FileCacheKey fileCacheKey = (FileCacheKey) key;
assertEquals(fileCacheKey.getIndexName(), indexName);
String filename = fileCacheKey.getFileName();
// if (fileList.contains(filename) == false) {
// // if the file is not registered, assert that a readlock prevented it from being
// // deleted:
// verifyReadlockExists(cache, indexName, filename);
// }
Object value = cache.get(fileCacheKey);
assertNotNull(value);
assertTrue(value instanceof FileMetadata);
FileMetadata metadata = (FileMetadata) value;
long totalFileSize = metadata.getSize();
long actualFileSize = deepCountFileSize(fileCacheKey, cache, affinitySegmentId);
assertEquals(actualFileSize, totalFileSize);
if (!ignoreFiles.contains(fileCacheKey.getFileName())) {
assertTrue(fileCacheKey + " should not have existed", fileList.contains(fileCacheKey.getFileName()));
}
} else if (key instanceof FileListCacheKey) {
fileListCacheKeyInstances++;
assertEquals(1, fileListCacheKeyInstances);
} else if (key instanceof FileReadLockKey) {
/*//FIXME testcase to be fixed after ISPN-616
FileReadLockKey readLockKey = (FileReadLockKey) key;
Assert.assertEquals(readLockKey.getIndexName(), indexName);
Object value = cache.get(readLockKey);
// we verify that a ReadLock exists only for existing files
Assert.assertTrue(cache.get(new FileCacheKey(indexName, readLockKey.getFileName())) != null, key + " left over from deleted "
+ readLockKey.getFileName());
Assert.assertTrue(cache.get(new ChunkCacheKey(indexName, readLockKey.getFileName(), 0)) != null);
Assert.assertTrue(fileList.contains(readLockKey.getFileName()), "readlock still exists but the file was deleted: "
+ readLockKey);
Assert.assertTrue(value == null || value.equals(1));
*/
} else {
AssertJUnit.fail("an unexpected key was found in the cache having key type " + key.getClass() + " toString:" + key);
}
}
}
private static void verifyReadlockExists(Cache cache, String indexName, String filename, int affinitySegmentId) {
FileReadLockKey readLockKey = new FileReadLockKey(indexName, filename, affinitySegmentId);
Object readLockValue = cache.get(readLockKey);
assertNotNull(readLockValue);
assertTrue(readLockValue instanceof Integer);
int v = ((Integer) readLockValue).intValue();
assertTrue("readlock exists for unregistered file of unexpected value: " + v + " for file: " + filename, v > 1);
}
/**
* For a given FileCacheKey return the total size of all chunks related to the file.
*
* @param fileCacheKey
* the key to the file to inspect
* @param cache
* the cache storing the chunks
* @return the total size adding all found chunks up
*/
public static long deepCountFileSize(FileCacheKey fileCacheKey, Cache cache, int affinitySegmentId) {
String indexName = fileCacheKey.getIndexName();
String fileName = fileCacheKey.getFileName();
long accumulator = 0;
FileMetadata metadata = (FileMetadata) cache.get(fileCacheKey);
int bufferSize = metadata.getBufferSize();
for (int i = 0;; i++) {
ChunkCacheKey chunkKey = new ChunkCacheKey(indexName, fileName, i, bufferSize, affinitySegmentId);
byte[] buffer = (byte[]) cache.get(chunkKey);
if (buffer == null) {
AssertJUnit.assertFalse(cache.containsKey(chunkKey));
return accumulator;
} else {
assert buffer.length > 0; //check we don't store useless data
accumulator += buffer.length;
}
}
}
public static void assertFileNotExists(Cache cache, String indexName, String fileName, long maxWaitForCondition, int affinitySegmentId) throws InterruptedException {
FileListCacheValue fileList = (FileListCacheValue) cache.get(new FileListCacheKey(indexName, affinitySegmentId));
AssertJUnit.assertNotNull(fileList);
AssertJUnit.assertFalse(fileList.contains(fileName)); //check is in sync: no waiting allowed in this case
boolean allok = false;
while (maxWaitForCondition >= 0 && !allok) {
Thread.sleep(10);
maxWaitForCondition -= 10;
allok=true;
FileMetadata metadata = (FileMetadata) cache.get(new FileCacheKey(indexName, fileName, affinitySegmentId));
if (metadata!=null) allok=false;
for (int i = 0; i < 100; i++) {
//bufferSize set to 0 as metadata might not be available, and it's not part of equals/hashcode anyway.
ChunkCacheKey key = new ChunkCacheKey(indexName, fileName, i, 0, affinitySegmentId);
if (cache.get(key)!=null) allok=false;
}
}
assertTrue(allok);
}
/**
* Verified the file exists and has a specified value for readLock;
* Consider that null should be interpreted as value 1;
*/
public static void assertFileExistsHavingRLCount(Cache cache, String fileName, String indexName, int expectedReadcount, int chunkSize, boolean expectRegisteredInFat, int affinitySegmentId) {
FileListCacheValue fileList = (FileListCacheValue) cache.get(new FileListCacheKey(indexName,affinitySegmentId));
assertNotNull(fileList);
assertTrue(fileList.contains(fileName) == expectRegisteredInFat);
FileMetadata metadata = (FileMetadata) cache.get(new FileCacheKey(indexName, fileName, affinitySegmentId));
assertNotNull(metadata);
long totalFileSize = metadata.getSize();
int chunkNumbers = (int)(totalFileSize / chunkSize);
for (int i = 0; i < chunkNumbers; i++) {
assertNotNull(cache.get(new ChunkCacheKey(indexName, fileName, i, metadata.getBufferSize(), affinitySegmentId)));
}
FileReadLockKey readLockKey = new FileReadLockKey(indexName,fileName, affinitySegmentId);
Object value = cache.get(readLockKey);
if (expectedReadcount <= 1) {
assertTrue("readlock value is " + value, value == null || Integer.valueOf(1).equals(value));
}
else {
assertNotNull(value);
assertTrue(value instanceof Integer);
int v = (Integer)value;
assertEquals(v, expectedReadcount);
}
}
}