Author: tedyu
Date: Wed Sep 14 23:47:21 2011
New Revision: 1170902

URL: http://svn.apache.org/viewvc?rev=1170902&view=rev
Log:
HBASE-4330  Fix races in slab cache (Li Pi & Todd)

Modified:
    hbase/trunk/CHANGES.txt
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java
    
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SingleSizeCache.java
    hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/Slab.java
    
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SlabCache.java
    
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestUtils.java
    
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSingleSizeCache.java
    
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlab.java
    
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlabCache.java

Modified: hbase/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Wed Sep 14 23:47:21 2011
@@ -235,7 +235,6 @@ Release 0.91.0 - Unreleased
    HBASE-4315  RPC logging too verbose (todd)
    HBASE-4273  java.lang.NullPointerException when a table is being disabled 
and
                HMaster restarts (Ming Ma)
-   HBASE-4310  SlabCache metrics bugfix (Li Pi)
    HBASE-4027  Off Heap Cache never creates Slabs (Li Pi)
    HBASE-4265  zookeeper.KeeperException$NodeExistsException if HMaster 
restarts
                while table is being disabled (Ming Ma)
@@ -262,6 +261,7 @@ Release 0.91.0 - Unreleased
                exception (Jinchao Gao)
    HBASE-4394  Add support for seeking hints to FilterList
    HBASE-4406  TestOpenRegionHandler failing after HBASE-4287 (todd)
+   HBASE-4330  Fix races in slab cache (Li Pi & Todd)
 
   IMPROVEMENTS
    HBASE-3290  Max Compaction Size (Nicolas Spiegelberg via Stack)  

Modified: 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java 
(original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java 
Wed Sep 14 23:47:21 2011
@@ -91,18 +91,17 @@ public class HFileBlock implements Cache
   private static final CacheableDeserializer<Cacheable> blockDeserializer =
   new CacheableDeserializer<Cacheable>() {
     public HFileBlock deserialize(ByteBuffer buf) throws IOException{
-      ByteBuffer tempCopy = buf.duplicate();
-      ByteBuffer newByteBuffer = ByteBuffer.allocate(tempCopy.limit()
+      ByteBuffer newByteBuffer = ByteBuffer.allocate(buf.limit()
           - HFileBlock.EXTRA_SERIALIZATION_SPACE);
-      tempCopy.limit(tempCopy.limit()
+      buf.limit(buf.limit()
           - HFileBlock.EXTRA_SERIALIZATION_SPACE).rewind();
-      newByteBuffer.put(tempCopy);
+      newByteBuffer.put(buf);
       HFileBlock ourBuffer = new HFileBlock(newByteBuffer);
 
-      tempCopy.position(tempCopy.limit());
-      tempCopy.limit(tempCopy.limit() + HFileBlock.EXTRA_SERIALIZATION_SPACE);
-      ourBuffer.offset = tempCopy.getLong();
-      ourBuffer.nextBlockOnDiskSizeWithHeader = tempCopy.getInt();
+      buf.position(buf.limit());
+      buf.limit(buf.limit() + HFileBlock.EXTRA_SERIALIZATION_SPACE);
+      ourBuffer.offset = buf.getLong();
+      ourBuffer.nextBlockOnDiskSizeWithHeader = buf.getInt();
       return ourBuffer;
     }
   };
@@ -1534,4 +1533,4 @@ public class HFileBlock implements Cache
   }
 
 
-}
\ No newline at end of file
+}

Modified: 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SingleSizeCache.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SingleSizeCache.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SingleSizeCache.java
 (original)
+++ 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SingleSizeCache.java
 Wed Sep 14 23:47:21 2011
@@ -19,12 +19,10 @@
  */
 package org.apache.hadoop.hbase.io.hfile.slab;
 
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -94,24 +92,9 @@ public class SingleSizeCache implements 
     MapEvictionListener<String, CacheablePair> listener = new 
MapEvictionListener<String, CacheablePair>() {
       @Override
       public void onEviction(String key, CacheablePair value) {
-        try {
-          value.evictionLock.writeLock().lock();
-          timeSinceLastAccess.set(System.nanoTime()
-              - value.recentlyAccessed.get());
-          backingStore.free(value.serializedData);
-          stats.evict();
-          /**
-           * We may choose to run this cache alone, without the SlabCache on
-           * top, no evictionWatcher in that case
-           */
-          if (evictionWatcher != null) {
-            evictionWatcher.onEviction(key, false);
-          }
-          size.addAndGet(-1 * value.heapSize());
-          stats.evicted();
-        } finally {
-          value.evictionLock.writeLock().unlock();
-        }
+        timeSinceLastAccess.set(System.nanoTime()
+            - value.recentlyAccessed.get());
+        doEviction(key, value);
       }
     };
 
@@ -121,7 +104,7 @@ public class SingleSizeCache implements 
   }
 
   @Override
-  public synchronized void cacheBlock(String blockName, Cacheable toBeCached) {
+  public void cacheBlock(String blockName, Cacheable toBeCached) {
     ByteBuffer storedBlock;
 
     /*
@@ -129,12 +112,18 @@ public class SingleSizeCache implements 
      * items than the memory we have allocated, but the Slab Allocator may 
still
      * be empty if we have not yet completed eviction
      */
-    do {
+
+    try {
       storedBlock = backingStore.alloc(toBeCached.getSerializedLength());
-    } while (storedBlock == null);
+    } catch (InterruptedException e) {
+      LOG.warn("SlabAllocator was interrupted while waiting for block to 
become available");
+      LOG.warn(e);
+      return;
+    }
 
     CacheablePair newEntry = new CacheablePair(toBeCached.getDeserializer(),
         storedBlock);
+    toBeCached.serialize(storedBlock);
 
     CacheablePair alreadyCached = backingMap.putIfAbsent(blockName, newEntry);
 
@@ -142,7 +131,6 @@ public class SingleSizeCache implements 
       backingStore.free(storedBlock);
       throw new RuntimeException("already cached " + blockName);
     }
-    toBeCached.serialize(storedBlock);
     newEntry.recentlyAccessed.set(System.nanoTime());
     this.size.addAndGet(newEntry.heapSize());
   }
@@ -157,20 +145,21 @@ public class SingleSizeCache implements 
 
     stats.hit(caching);
     // If lock cannot be obtained, that means we're undergoing eviction.
-    if (contentBlock.evictionLock.readLock().tryLock()) {
-      try {
-        contentBlock.recentlyAccessed.set(System.nanoTime());
+    try {
+      contentBlock.recentlyAccessed.set(System.nanoTime());
+      synchronized (contentBlock) {
+        if (contentBlock.serializedData == null) {
+          // concurrently evicted
+          LOG.warn("Concurrent eviction of " + key);
+          return null;
+        }
         return contentBlock.deserializer
-            .deserialize(contentBlock.serializedData);
-      } catch (IOException e) {
-        e.printStackTrace();
-        LOG.warn("Deserializer throwing ioexception, possibly deserializing 
wrong object buffer");
-        return null;
-      } finally {
-        contentBlock.evictionLock.readLock().unlock();
+            .deserialize(contentBlock.serializedData.asReadOnlyBuffer());
       }
+    } catch (Throwable t) {
+      LOG.error("Deserializer threw an exception. This may indicate a bug.", 
t);
+      return null;
     }
-    return null;
   }
 
   /**
@@ -183,23 +172,45 @@ public class SingleSizeCache implements 
     stats.evict();
     CacheablePair evictedBlock = backingMap.remove(key);
     if (evictedBlock != null) {
-      try {
-        evictedBlock.evictionLock.writeLock().lock();
-        backingStore.free(evictedBlock.serializedData);
-        evictionWatcher.onEviction(key, false);
-        stats.evicted();
-        size.addAndGet(-1 * evictedBlock.heapSize());
-      } finally {
-        evictedBlock.evictionLock.writeLock().unlock();
-      }
+      doEviction(key, evictedBlock);
     }
     return evictedBlock != null;
 
   }
 
+  private void doEviction(String key, CacheablePair evictedBlock) {
+    long evictedHeap = 0;
+    synchronized (evictedBlock) {
+      if (evictedBlock.serializedData == null) {
+        // someone else already freed
+        return;
+      }
+      evictedHeap = evictedBlock.heapSize();
+      ByteBuffer bb = evictedBlock.serializedData;
+      evictedBlock.serializedData = null;
+      backingStore.free(bb);
+
+      // We have to do this callback inside the synchronization here.
+      // Otherwise we can have the following interleaving:
+      // Thread A calls getBlock():
+      // SlabCache directs call to this SingleSizeCache
+      // It gets the CacheablePair object
+      // Thread B runs eviction
+      // doEviction() is called and sets serializedData = null, here.
+      // Thread A sees the null serializedData, and returns null
+      // Thread A calls cacheBlock on the same block, and gets
+      // "already cached" since the block is still in backingStore
+      if (evictionWatcher != null) {
+        evictionWatcher.onEviction(key, false);
+      }
+    }
+    stats.evicted();
+    size.addAndGet(-1 * evictedHeap);
+  }
+
   public void logStats() {
 
-    long milliseconds = (long)this.timeSinceLastAccess.get() / 1000000;
+    long milliseconds = (long) this.timeSinceLastAccess.get() / 1000000;
 
     LOG.info("For Slab of size " + this.blockSize + ": "
         + this.getOccupiedSize() / this.blockSize
@@ -299,8 +310,7 @@ public class SingleSizeCache implements 
   /* Just a pair class, holds a reference to the parent cacheable */
   private class CacheablePair implements HeapSize {
     final CacheableDeserializer<Cacheable> deserializer;
-    final ByteBuffer serializedData;
-    final ReentrantReadWriteLock evictionLock;
+    ByteBuffer serializedData;
     AtomicLong recentlyAccessed;
 
     private CacheablePair(CacheableDeserializer<Cacheable> deserializer,
@@ -308,7 +318,6 @@ public class SingleSizeCache implements 
       this.recentlyAccessed = new AtomicLong();
       this.deserializer = deserializer;
       this.serializedData = serializedData;
-      evictionLock = new ReentrantReadWriteLock();
     }
 
     /*

Modified: 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/Slab.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/Slab.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/Slab.java 
(original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/Slab.java 
Wed Sep 14 23:47:21 2011
@@ -21,6 +21,8 @@ package org.apache.hadoop.hbase.io.hfile
 
 import java.nio.ByteBuffer;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.util.ClassSize;
@@ -37,7 +39,7 @@ class Slab implements org.apache.hadoop.
   static final Log LOG = LogFactory.getLog(Slab.class);
 
   /** This is where our items, or blocks of the slab, are stored. */
-  private ConcurrentLinkedQueue<ByteBuffer> buffers;
+  private LinkedBlockingQueue<ByteBuffer> buffers;
 
   /** This is where our Slabs are stored */
   private ConcurrentLinkedQueue<ByteBuffer> slabs;
@@ -47,7 +49,7 @@ class Slab implements org.apache.hadoop.
   private long heapSize;
 
   Slab(int blockSize, int numBlocks) {
-    buffers = new ConcurrentLinkedQueue<ByteBuffer>();
+    buffers = new LinkedBlockingQueue<ByteBuffer>();
     slabs = new ConcurrentLinkedQueue<ByteBuffer>();
 
     this.blockSize = blockSize;
@@ -108,16 +110,13 @@ class Slab implements org.apache.hadoop.
   }
 
   /*
-   * This returns null if empty. Throws an exception if you try to allocate a
-   * bigger size than the allocator can handle.
+   * Throws an exception if you try to allocate a
+   * bigger size than the allocator can handle. Alloc will block until a 
buffer is available.
    */
-  ByteBuffer alloc(int bufferSize) {
+  ByteBuffer alloc(int bufferSize) throws InterruptedException {
     int newCapacity = Preconditions.checkPositionIndex(bufferSize, blockSize);
 
-    ByteBuffer returnedBuffer = buffers.poll();
-    if (returnedBuffer == null) {
-      return null;
-    }
+    ByteBuffer returnedBuffer = buffers.take();
 
     returnedBuffer.clear().limit(newCapacity);
     return returnedBuffer;

Modified: 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SlabCache.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SlabCache.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SlabCache.java 
(original)
+++ 
hbase/trunk/src/main/java/org/apache/hadoop/hbase/io/hfile/slab/SlabCache.java 
Wed Sep 14 23:47:21 2011
@@ -204,11 +204,14 @@ public class SlabCache implements SlabIt
 
     this.successfullyCachedStats.addin(cachedItem.getSerializedLength());
     SingleSizeCache scache = scacheEntry.getValue();
-    scache.cacheBlock(blockName, cachedItem); // if this
-                                              // fails, due to
-                                              // block already
-    // being there, exception will be thrown
-    backingStore.put(blockName, scache);
+
+    /*This will throw a runtime exception if we try to cache the same value 
twice*/
+    scache.cacheBlock(blockName, cachedItem);
+
+    /*Spinlock, if we're spinlocking, that means an eviction hasn't taken 
place yet*/
+    while (backingStore.putIfAbsent(blockName, scache) != null) {
+      Thread.yield();
+    }
   }
 
   /**
@@ -232,6 +235,7 @@ public class SlabCache implements SlabIt
   public Cacheable getBlock(String key, boolean caching) {
     SingleSizeCache cachedBlock = backingStore.get(key);
     if (cachedBlock == null) {
+      stats.miss(caching);
       return null;
     }
 
@@ -272,12 +276,15 @@ public class SlabCache implements SlabIt
   }
 
   /**
-   * Sends a shutdown to all SingleSizeCache's contained by this cache.F
+   * Sends a shutdown to all SingleSizeCache's contained by this cache.
+   *
+   * Also terminates the scheduleThreadPool.
    */
   public void shutdown() {
     for (SingleSizeCache s : sizer.values()) {
       s.shutdown();
     }
+    this.scheduleThreadPool.shutdown();
   }
 
   public long heapSize() {

Modified: 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestUtils.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestUtils.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestUtils.java 
(original)
+++ 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestUtils.java 
Wed Sep 14 23:47:21 2011
@@ -22,6 +22,7 @@ package org.apache.hadoop.hbase.io.hfile
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.*;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -57,8 +58,8 @@ public class CacheTestUtils {
         public void doAnAction() throws Exception {
           if (!blocksToTest.isEmpty()) {
             HFileBlockPair ourBlock = blocksToTest.poll();
-            //if we run out of blocks to test, then we should stop the tests.
-            if(ourBlock == null){
+            // if we run out of blocks to test, then we should stop the tests.
+            if (ourBlock == null) {
               ctx.stop();
               return;
             }
@@ -67,7 +68,9 @@ public class CacheTestUtils {
                 false);
             if (retrievedBlock != null) {
               assertEquals(ourBlock.block, retrievedBlock);
+              toBeTested.evictBlock(ourBlock.blockName);
               hits.incrementAndGet();
+              assertNull(toBeTested.getBlock(ourBlock.blockName, false));
             } else {
               miss.incrementAndGet();
             }
@@ -75,6 +78,7 @@ public class CacheTestUtils {
           }
         }
       };
+      t.setDaemon(true);
       ctx.addThread(t);
     }
     ctx.startThreads();
@@ -82,8 +86,9 @@ public class CacheTestUtils {
       Thread.sleep(10);
     }
     ctx.stop();
-    if((double) hits.get() / ((double) hits.get() +  (double) miss.get()) < 
passingScore){
-      fail("Too many nulls returned. Hits: " + hits.get() + " Misses: " + 
miss.get());
+    if ((double) hits.get() / ((double) hits.get() + (double) miss.get()) < 
passingScore) {
+      fail("Too many nulls returned. Hits: " + hits.get() + " Misses: "
+          + miss.get());
     }
   }
 
@@ -130,19 +135,25 @@ public class CacheTestUtils {
 
   public static void hammerSingleKey(final BlockCache toBeTested,
       int BlockSize, int numThreads, int numQueries) throws Exception {
-    final HFileBlockPair kv = generateHFileBlocks(BlockSize, 1)[0];
+    final String key = "key";
+    final byte[] buf = new byte[5 * 1024];
+    Arrays.fill(buf, (byte) 5);
+
+    final ByteArrayCacheable bac = new ByteArrayCacheable(buf);
     Configuration conf = new Configuration();
     MultithreadedTestUtil.TestContext ctx = new 
MultithreadedTestUtil.TestContext(
         conf);
 
     final AtomicInteger totalQueries = new AtomicInteger();
-    toBeTested.cacheBlock(kv.blockName, kv.block);
+    toBeTested.cacheBlock(key, bac);
 
     for (int i = 0; i < numThreads; i++) {
       TestThread t = new MultithreadedTestUtil.RepeatingTestThread(ctx) {
         @Override
         public void doAnAction() throws Exception {
-          assertEquals(kv.block, toBeTested.getBlock(kv.blockName, false));
+          ByteArrayCacheable returned = (ByteArrayCacheable) toBeTested
+              .getBlock(key, false);
+          assertArrayEquals(buf, returned.buf);
           totalQueries.incrementAndGet();
         }
       };
@@ -157,6 +168,94 @@ public class CacheTestUtils {
     ctx.stop();
   }
 
+  public static void hammerEviction(final BlockCache toBeTested, int BlockSize,
+      int numThreads, int numQueries) throws Exception {
+
+    Configuration conf = new Configuration();
+    MultithreadedTestUtil.TestContext ctx = new 
MultithreadedTestUtil.TestContext(
+        conf);
+
+    final AtomicInteger totalQueries = new AtomicInteger();
+
+    for (int i = 0; i < numThreads; i++) {
+      final int finalI = i;
+
+      final byte[] buf = new byte[5 * 1024];
+      TestThread t = new MultithreadedTestUtil.RepeatingTestThread(ctx) {
+        @Override
+        public void doAnAction() throws Exception {
+          for (int j = 0; j < 10; j++) {
+            String key = "key_" + finalI + "_" + j;
+            Arrays.fill(buf, (byte) (finalI * j));
+            final ByteArrayCacheable bac = new ByteArrayCacheable(buf);
+
+            ByteArrayCacheable gotBack = (ByteArrayCacheable) toBeTested
+                .getBlock(key, true);
+            if (gotBack != null) {
+              assertArrayEquals(gotBack.buf, bac.buf);
+            } else {
+              toBeTested.cacheBlock(key, bac);
+            }
+          }
+          totalQueries.incrementAndGet();
+        }
+      };
+
+      ctx.addThread(t);
+    }
+
+    ctx.startThreads();
+    while (totalQueries.get() < numQueries && ctx.shouldRun()) {
+      Thread.sleep(10);
+    }
+    ctx.stop();
+
+    assertTrue(toBeTested.getStats().getEvictedCount() > 0);
+  }
+
+  private static class ByteArrayCacheable implements Cacheable {
+
+    final byte[] buf;
+
+    public ByteArrayCacheable(byte[] buf) {
+      this.buf = buf;
+    }
+
+    @Override
+    public long heapSize() {
+      return 4 + buf.length;
+    }
+
+    @Override
+    public int getSerializedLength() {
+      return 4 + buf.length;
+    }
+
+    @Override
+    public void serialize(ByteBuffer destination) {
+      destination.putInt(buf.length);
+      Thread.yield();
+      destination.put(buf);
+      destination.rewind();
+    }
+
+    @Override
+    public CacheableDeserializer<Cacheable> getDeserializer() {
+      return new CacheableDeserializer<Cacheable>() {
+
+        @Override
+        public Cacheable deserialize(ByteBuffer b) throws IOException {
+          int len = b.getInt();
+          Thread.yield();
+          byte buf[] = new byte[len];
+          b.get(buf);
+          return new ByteArrayCacheable(buf);
+        }
+      };
+    }
+
+  }
+
   private static HFileBlockPair[] generateHFileBlocks(int blockSize,
       int numBlocks) {
     HFileBlockPair[] returnedBlocks = new HFileBlockPair[numBlocks];

Modified: 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSingleSizeCache.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSingleSizeCache.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSingleSizeCache.java
 (original)
+++ 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSingleSizeCache.java
 Wed Sep 14 23:47:21 2011
@@ -63,5 +63,10 @@ public class TestSingleSizeCache {
   public void testCacheMultiThreadedSingleKey() throws Exception {
     CacheTestUtils.hammerSingleKey(cache, BLOCK_SIZE, NUM_THREADS, 
NUM_QUERIES);
   }
+  
+  @Test
+  public void testCacheMultiThreadedEviction() throws Exception {
+    CacheTestUtils.hammerEviction(cache, BLOCK_SIZE, NUM_THREADS, NUM_QUERIES);
+  }
 
 }

Modified: 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlab.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlab.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlab.java 
(original)
+++ 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlab.java 
Wed Sep 14 23:47:21 2011
@@ -42,7 +42,7 @@ public class TestSlab {
   }
 
   @Test
-  public void testBasicFunctionality() {
+  public void testBasicFunctionality() throws InterruptedException {
     for (int i = 0; i < NUMBLOCKS; i++) {
       buffers[i] = testSlab.alloc(BLOCKSIZE);
       assertEquals(BLOCKSIZE, buffers[i].limit());

Modified: 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlabCache.java
URL: 
http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlabCache.java?rev=1170902&r1=1170901&r2=1170902&view=diff
==============================================================================
--- 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlabCache.java
 (original)
+++ 
hbase/trunk/src/test/java/org/apache/hadoop/hbase/io/hfile/slab/TestSlabCache.java
 Wed Sep 14 23:47:21 2011
@@ -43,7 +43,7 @@ public class TestSlabCache {
   static final int CACHE_SIZE = 1000000;
   static final int NUM_BLOCKS = 101;
   static final int BLOCK_SIZE = CACHE_SIZE / NUM_BLOCKS;
-  static final int NUM_THREADS = 1000;
+  static final int NUM_THREADS = 50;
   static final int NUM_QUERIES = 10000;
   SlabCache cache;
 
@@ -83,6 +83,11 @@ public class TestSlabCache {
   }
 
   @Test
+  public void testCacheMultiThreadedEviction() throws Exception {
+    CacheTestUtils.hammerEviction(cache, BLOCK_SIZE, 10, NUM_QUERIES);
+  }
+
+  @Test
   /*Just checks if ranges overlap*/
   public void testStatsArithmetic(){
     SlabStats test = cache.requestStats;


Reply via email to