package org.apache.blur.store.blockcache; /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; import org.junit.Test; public class BlockCacheTest { @Test public void testBlockCache() throws IOException, InterruptedException, ExecutionException { int blocksPerSlab = 1024; int slabs = 4; // Test block are larger than cache size. final int blocksInTest = (blocksPerSlab * slabs) * 2; final int blockSize = BlockCache._8K; int slabSize = blockSize * blocksPerSlab; long totalMemory = slabs * (long) slabSize; final BlockCache blockCache = new BlockCache(true, totalMemory, slabSize); final int threads = 4; ExecutorService pool = Executors.newFixedThreadPool(threads); List<Future<Boolean>> futures = new ArrayList<Future<Boolean>>(); final int testSpace = blocksInTest / threads; for (int g = 0; g < threads; g++) { final int file = g; futures.add(pool.submit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return runTest(blockSize, file, testSpace, blockCache); } })); } for (Future<Boolean> future : futures) { if (!future.get()) { fail(); } } blockCache.close(); } private boolean runTest(int blockSize, int file, int blocksInTest, BlockCache blockCache) { byte[] buffer = new byte[blockSize]; Random random = new Random(); byte[] newData = new byte[blockSize]; AtomicLong hitsInCache = new AtomicLong(); AtomicLong missesInCache = new AtomicLong(); long storeTime = 0; long fetchTime = 0; int passes = 10000; BlockCacheKey blockCacheKey = new BlockCacheKey(); for (int j = 0; j < passes; j++) { long block = random.nextInt(blocksInTest); blockCacheKey.setBlock(block); blockCacheKey.setFile(file); if (blockCache.fetch(blockCacheKey, buffer)) { hitsInCache.incrementAndGet(); } else { missesInCache.incrementAndGet(); } byte[] testData = testData(random, blockSize, newData); long t1 = System.nanoTime(); boolean store = blockCache.store(blockCacheKey, 0, testData, 0, blockSize); storeTime += (System.nanoTime() - t1); if (store) { long t3 = System.nanoTime(); if (blockCache.fetch(blockCacheKey, buffer)) { fetchTime += (System.nanoTime() - t3); if (!Arrays.equals(testData, buffer)) { return false; } } } } System.out.println("Cache Hits = " + hitsInCache.get()); System.out.println("Cache Misses = " + missesInCache.get()); System.out.println("Store = avg " + (storeTime / (double) passes) / 1000000.0 + " ms"); System.out.println("Fetch = avg " + (fetchTime / (double) passes) / 1000000.0 + " ms"); System.out.println("# of Elements = " + blockCache.getSize()); return true; } /** * Verify checking of buffer size limits against the cached block size. * @throws IOException */ @Test public void testLongBuffer() throws IOException { Random random = new Random(); int blockSize = BlockCache._8K; int slabSize = blockSize * 1024; long totalMemory = 2 * slabSize; BlockCache blockCache = new BlockCache(true, totalMemory, slabSize); BlockCacheKey blockCacheKey = new BlockCacheKey(); blockCacheKey.setBlock(0); blockCacheKey.setFile(0); byte[] newData = new byte[blockSize * 3]; byte[] testData = testData(random, blockSize, newData); assertTrue(blockCache.store(blockCacheKey, 0, testData, 0, blockSize)); assertTrue(blockCache.store(blockCacheKey, 0, testData, blockSize, blockSize)); assertTrue(blockCache.store(blockCacheKey, 0, testData, blockSize * 2, blockSize)); assertTrue(blockCache.store(blockCacheKey, 1, testData, 0, blockSize - 1)); assertTrue(blockCache.store(blockCacheKey, 1, testData, blockSize, blockSize - 1)); assertTrue(blockCache.store(blockCacheKey, 1, testData, blockSize * 2, blockSize - 1)); blockCache.close(); } private static byte[] testData(Random random, int size, byte[] buf) { random.nextBytes(buf); return buf; } }