1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import static org.junit.Assert.*;
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Random;
26 import java.util.concurrent.atomic.AtomicInteger;
27
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.MultithreadedTestUtil;
30 import org.apache.hadoop.hbase.MultithreadedTestUtil.TestThread;
31 import org.apache.hadoop.hbase.testclassification.SmallTests;
32 import org.apache.hadoop.hbase.util.ByteRange;
33 import org.junit.Test;
34
35 import com.google.common.collect.Iterables;
36 import com.google.common.collect.Lists;
37 import com.google.common.collect.Maps;
38 import com.google.common.primitives.Ints;
39 import org.junit.experimental.categories.Category;
40
41 @Category(SmallTests.class)
42 public class TestMemStoreLAB {
43
44
45
46
47 @Test
48 public void testLABRandomAllocation() {
49 Random rand = new Random();
50 MemStoreLAB mslab = new HeapMemStoreLAB();
51 int expectedOff = 0;
52 byte[] lastBuffer = null;
53
54
55
56 for (int i = 0; i < 100000; i++) {
57 int size = rand.nextInt(1000);
58 ByteRange alloc = mslab.allocateBytes(size);
59
60 if (alloc.getBytes() != lastBuffer) {
61 expectedOff = 0;
62 lastBuffer = alloc.getBytes();
63 }
64 assertEquals(expectedOff, alloc.getOffset());
65 assertTrue("Allocation overruns buffer",
66 alloc.getOffset() + size <= alloc.getBytes().length);
67 expectedOff += size;
68 }
69 }
70
71 @Test
72 public void testLABLargeAllocation() {
73 MemStoreLAB mslab = new HeapMemStoreLAB();
74 ByteRange alloc = mslab.allocateBytes(2*1024*1024);
75 assertNull("2MB allocation shouldn't be satisfied by LAB.",
76 alloc);
77 }
78
79
80
81
82
83 @Test
84 public void testLABThreading() throws Exception {
85 Configuration conf = new Configuration();
86 MultithreadedTestUtil.TestContext ctx =
87 new MultithreadedTestUtil.TestContext(conf);
88
89 final AtomicInteger totalAllocated = new AtomicInteger();
90
91 final MemStoreLAB mslab = new HeapMemStoreLAB();
92 List<List<AllocRecord>> allocations = Lists.newArrayList();
93
94 for (int i = 0; i < 10; i++) {
95 final List<AllocRecord> allocsByThisThread = Lists.newLinkedList();
96 allocations.add(allocsByThisThread);
97
98 TestThread t = new MultithreadedTestUtil.RepeatingTestThread(ctx) {
99 private Random r = new Random();
100 @Override
101 public void doAnAction() throws Exception {
102 int size = r.nextInt(1000);
103 ByteRange alloc = mslab.allocateBytes(size);
104 totalAllocated.addAndGet(size);
105 allocsByThisThread.add(new AllocRecord(alloc, size));
106 }
107 };
108 ctx.addThread(t);
109 }
110
111 ctx.startThreads();
112 while (totalAllocated.get() < 50*1024*1024 && ctx.shouldRun()) {
113 Thread.sleep(10);
114 }
115 ctx.stop();
116
117
118
119 Map<byte[], Map<Integer, AllocRecord>> mapsByChunk =
120 Maps.newHashMap();
121
122 int sizeCounted = 0;
123 for (AllocRecord rec : Iterables.concat(allocations)) {
124 sizeCounted += rec.size;
125 if (rec.size == 0) continue;
126
127 Map<Integer, AllocRecord> mapForThisByteArray =
128 mapsByChunk.get(rec.alloc.getBytes());
129 if (mapForThisByteArray == null) {
130 mapForThisByteArray = Maps.newTreeMap();
131 mapsByChunk.put(rec.alloc.getBytes(), mapForThisByteArray);
132 }
133 AllocRecord oldVal = mapForThisByteArray.put(rec.alloc.getOffset(), rec);
134 assertNull("Already had an entry " + oldVal + " for allocation " + rec,
135 oldVal);
136 }
137 assertEquals("Sanity check test", sizeCounted, totalAllocated.get());
138
139
140 for (Map<Integer, AllocRecord> allocsInChunk : mapsByChunk.values()) {
141 int expectedOff = 0;
142 for (AllocRecord alloc : allocsInChunk.values()) {
143 assertEquals(expectedOff, alloc.alloc.getOffset());
144 assertTrue("Allocation overruns buffer",
145 alloc.alloc.getOffset() + alloc.size <= alloc.alloc.getBytes().length);
146 expectedOff += alloc.size;
147 }
148 }
149
150 }
151
152 private static class AllocRecord implements Comparable<AllocRecord>{
153 private final ByteRange alloc;
154 private final int size;
155 public AllocRecord(ByteRange alloc, int size) {
156 super();
157 this.alloc = alloc;
158 this.size = size;
159 }
160
161 @Override
162 public int compareTo(AllocRecord e) {
163 if (alloc.getBytes() != e.alloc.getBytes()) {
164 throw new RuntimeException("Can only compare within a particular array");
165 }
166 return Ints.compare(alloc.getOffset(), e.alloc.getOffset());
167 }
168
169 @Override
170 public String toString() {
171 return "AllocRecord(offset=" + alloc.getOffset() + ", size=" + size + ")";
172 }
173
174 }
175
176 }
177