Author: todd
Date: Mon Feb 7 21:56:05 2011
New Revision: 1068156
URL: http://svn.apache.org/viewvc?rev=1068156&view=rev
Log:
HBASE-3455. Amend patch - forgot to add TestMemStoreLAB.java
Added:
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/TestMemStoreLAB.java
Added:
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/TestMemStoreLAB.java
URL:
http://svn.apache.org/viewvc/hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/TestMemStoreLAB.java?rev=1068156&view=auto
==============================================================================
---
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/TestMemStoreLAB.java
(added)
+++
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/TestMemStoreLAB.java
Mon Feb 7 21:56:05 2011
@@ -0,0 +1,177 @@
+/**
+ * Copyright 2011 The Apache Software Foundation
+ *
+ * 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.
+ */
+package org.apache.hadoop.hbase.regionserver;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.MultithreadedTestUtil;
+import org.apache.hadoop.hbase.MultithreadedTestUtil.TestThread;
+import org.apache.hadoop.hbase.regionserver.MemStoreLAB.Allocation;
+import org.junit.Test;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+
+public class TestMemStoreLAB {
+
+ /**
+ * Test a bunch of random allocations
+ */
+ @Test
+ public void testLABRandomAllocation() {
+ Random rand = new Random();
+ MemStoreLAB mslab = new MemStoreLAB();
+ int expectedOff = 0;
+ byte[] lastBuffer = null;
+ // 100K iterations by 0-1K alloc -> 50MB expected
+ // should be reasonable for unit test and also cover wraparound
+ // behavior
+ for (int i = 0; i < 100000; i++) {
+ int size = rand.nextInt(1000);
+ Allocation alloc = mslab.allocateBytes(size);
+
+ if (alloc.getData() != lastBuffer) {
+ expectedOff = 0;
+ lastBuffer = alloc.getData();
+ }
+ assertEquals(expectedOff, alloc.getOffset());
+ assertTrue("Allocation " + alloc + " overruns buffer",
+ alloc.getOffset() + size <= alloc.getData().length);
+ expectedOff += size;
+ }
+ }
+
+ @Test
+ public void testLABLargeAllocation() {
+ MemStoreLAB mslab = new MemStoreLAB();
+ Allocation alloc = mslab.allocateBytes(2*1024*1024);
+ assertNull("2MB allocation shouldn't be satisfied by LAB.",
+ alloc);
+ }
+
+ /**
+ * Test allocation from lots of threads, making sure the results don't
+ * overlap in any way
+ */
+ @Test
+ public void testLABThreading() throws Exception {
+ Configuration conf = new Configuration();
+ MultithreadedTestUtil.TestContext ctx =
+ new MultithreadedTestUtil.TestContext(conf);
+
+ final AtomicInteger totalAllocated = new AtomicInteger();
+
+ final MemStoreLAB mslab = new MemStoreLAB();
+ List<List<AllocRecord>> allocations = Lists.newArrayList();
+
+ for (int i = 0; i < 10; i++) {
+ final List<AllocRecord> allocsByThisThread = Lists.newLinkedList();
+ allocations.add(allocsByThisThread);
+
+ TestThread t = new MultithreadedTestUtil.RepeatingTestThread(ctx) {
+ private Random r = new Random();
+ @Override
+ public void doAnAction() throws Exception {
+ int size = r.nextInt(1000);
+ Allocation alloc = mslab.allocateBytes(size);
+ totalAllocated.addAndGet(size);
+ allocsByThisThread.add(new AllocRecord(alloc, size));
+ }
+ };
+ ctx.addThread(t);
+ }
+
+ ctx.startThreads();
+ while (totalAllocated.get() < 50*1024*1024 && ctx.shouldRun()) {
+ Thread.sleep(10);
+ }
+ ctx.stop();
+
+ // Partition the allocations by the actual byte[] they point into,
+ // make sure offsets are unique for each chunk
+ Map<byte[], Map<Integer, AllocRecord>> mapsByChunk =
+ Maps.newHashMap();
+
+ int sizeCounted = 0;
+ for (AllocRecord rec : Iterables.concat(allocations)) {
+ sizeCounted += rec.size;
+ if (rec.size == 0) continue;
+
+ Map<Integer, AllocRecord> mapForThisByteArray =
+ mapsByChunk.get(rec.alloc.getData());
+ if (mapForThisByteArray == null) {
+ mapForThisByteArray = Maps.newTreeMap();
+ mapsByChunk.put(rec.alloc.getData(), mapForThisByteArray);
+ }
+ AllocRecord oldVal = mapForThisByteArray.put(rec.alloc.getOffset(), rec);
+ assertNull("Already had an entry " + oldVal + " for allocation " + rec,
+ oldVal);
+ }
+ assertEquals("Sanity check test", sizeCounted, totalAllocated.get());
+
+ // Now check each byte array to make sure allocations don't overlap
+ for (Map<Integer, AllocRecord> allocsInChunk : mapsByChunk.values()) {
+ int expectedOff = 0;
+ for (AllocRecord alloc : allocsInChunk.values()) {
+ assertEquals(expectedOff, alloc.alloc.getOffset());
+ assertTrue("Allocation " + alloc + " overruns buffer",
+ alloc.alloc.getOffset() + alloc.size <=
alloc.alloc.getData().length);
+ expectedOff += alloc.size;
+ }
+ }
+
+ }
+
+ private static class AllocRecord implements Comparable<AllocRecord>{
+ private final Allocation alloc;
+ private final int size;
+ public AllocRecord(Allocation alloc, int size) {
+ super();
+ this.alloc = alloc;
+ this.size = size;
+ }
+
+ @Override
+ public int compareTo(AllocRecord e) {
+ if (alloc.getData() != e.alloc.getData()) {
+ throw new RuntimeException("Can only compare within a particular
array");
+ }
+ return Ints.compare(alloc.getOffset(), e.alloc.getOffset());
+ }
+
+ @Override
+ public String toString() {
+ return "AllocRecord(alloc=" + alloc + ", size=" + size + ")";
+ }
+
+ }
+}