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.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25
26 import java.lang.management.ManagementFactory;
27 import java.util.Iterator;
28
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.ChoreService;
31 import org.apache.hadoop.hbase.CoordinatedStateManager;
32 import org.apache.hadoop.hbase.HBaseConfiguration;
33 import org.apache.hadoop.hbase.HBaseTestingUtility;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.Server;
36 import org.apache.hadoop.hbase.ServerName;
37 import org.apache.hadoop.hbase.testclassification.SmallTests;
38 import org.apache.hadoop.hbase.Waiter;
39 import org.apache.hadoop.hbase.client.ClusterConnection;
40 import org.apache.hadoop.hbase.io.hfile.BlockCache;
41 import org.apache.hadoop.hbase.io.hfile.BlockCacheKey;
42 import org.apache.hadoop.hbase.io.hfile.CacheStats;
43 import org.apache.hadoop.hbase.io.hfile.Cacheable;
44 import org.apache.hadoop.hbase.io.hfile.CachedBlock;
45 import org.apache.hadoop.hbase.io.hfile.ResizableBlockCache;
46 import org.apache.hadoop.hbase.io.util.HeapMemorySizeUtil;
47 import org.apache.hadoop.hbase.regionserver.HeapMemoryManager.TunerContext;
48 import org.apache.hadoop.hbase.regionserver.HeapMemoryManager.TunerResult;
49 import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
50 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
51 import org.junit.Test;
52 import org.junit.experimental.categories.Category;
53
54 @Category(SmallTests.class)
55 public class TestHeapMemoryManager {
56
57 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
58
59 private long maxHeapSize = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax();
60
61 @Test
62 public void testAutoTunerShouldBeOffWhenMaxMinRangesForMemstoreIsNotGiven() throws Exception {
63 Configuration conf = HBaseConfiguration.create();
64 conf.setFloat(HeapMemorySizeUtil.MEMSTORE_SIZE_KEY, 0.02f);
65 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.75f);
66 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.03f);
67 HeapMemoryManager manager = new HeapMemoryManager(new BlockCacheStub(0),
68 new MemstoreFlusherStub(0), new RegionServerStub(conf), new RegionServerAccountingStub());
69 assertFalse(manager.isTunerOn());
70 }
71
72 @Test
73 public void testAutoTunerShouldBeOffWhenMaxMinRangesForBlockCacheIsNotGiven() throws Exception {
74 Configuration conf = HBaseConfiguration.create();
75 conf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0.02f);
76 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
77 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.03f);
78 HeapMemoryManager manager = new HeapMemoryManager(new BlockCacheStub(0),
79 new MemstoreFlusherStub(0), new RegionServerStub(conf), new RegionServerAccountingStub());
80 assertFalse(manager.isTunerOn());
81 }
82
83 @Test
84 public void testWhenMemstoreAndBlockCacheMaxMinChecksFails() throws Exception {
85 BlockCacheStub blockCache = new BlockCacheStub(0);
86 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub(0);
87 Configuration conf = HBaseConfiguration.create();
88 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
89 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.06f);
90 try {
91 new HeapMemoryManager(blockCache, memStoreFlusher,
92 new RegionServerStub(conf), new RegionServerAccountingStub());
93 fail();
94 } catch (RuntimeException e) {
95 }
96 conf = HBaseConfiguration.create();
97 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.2f);
98 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
99 try {
100 new HeapMemoryManager(blockCache, memStoreFlusher,
101 new RegionServerStub(conf), new RegionServerAccountingStub());
102 fail();
103 } catch (RuntimeException e) {
104 }
105 }
106
107 @Test
108 public void testWhenClusterIsWriteHeavyWithEmptyMemstore() throws Exception {
109 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
110 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
111 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
112
113 blockCache.setTestBlockSize(0);
114 regionServerAccounting.setTestMemstoreSize(0);
115 Configuration conf = HBaseConfiguration.create();
116 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
117 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
118 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
119 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
120 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
121 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
122
123 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
124 new RegionServerStub(conf), regionServerAccounting);
125 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
126 long oldBlockCacheSize = blockCache.maxSize;
127 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
128 heapMemoryManager.start(choreService);
129 memStoreFlusher.flushType = FlushType.ABOVE_HIGHER_MARK;
130 memStoreFlusher.requestFlush(null, false);
131 memStoreFlusher.requestFlush(null, false);
132 memStoreFlusher.requestFlush(null, false);
133 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
134 memStoreFlusher.requestFlush(null, false);
135
136 Thread.sleep(1500);
137
138 assertEquals(oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
139 assertEquals(oldBlockCacheSize, blockCache.maxSize);
140 }
141
142 @Test
143 public void testWhenClusterIsReadHeavyWithEmptyBlockCache() throws Exception {
144 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
145 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
146 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
147
148 blockCache.setTestBlockSize(0);
149 regionServerAccounting.setTestMemstoreSize(0);
150 Configuration conf = HBaseConfiguration.create();
151 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
152 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
153 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
154 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
155 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
156 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
157
158 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
159 new RegionServerStub(conf), regionServerAccounting);
160 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
161 long oldBlockCacheSize = blockCache.maxSize;
162 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
163 heapMemoryManager.start(choreService);
164 blockCache.evictBlock(null);
165 blockCache.evictBlock(null);
166 blockCache.evictBlock(null);
167
168 Thread.sleep(1500);
169
170 assertEquals(oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
171 assertEquals(oldBlockCacheSize, blockCache.maxSize);
172 }
173
174 @Test
175 public void testWhenClusterIsWriteHeavy() throws Exception {
176 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
177 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
178 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
179
180 blockCache.setTestBlockSize(0);
181 regionServerAccounting.setTestMemstoreSize((long) (maxHeapSize * 0.4 * 0.8));
182 Configuration conf = HBaseConfiguration.create();
183 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
184 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
185 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
186 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
187 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
188 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
189
190 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
191 new RegionServerStub(conf), regionServerAccounting);
192 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
193 long oldBlockCacheSize = blockCache.maxSize;
194 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
195 heapMemoryManager.start(choreService);
196 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
197 memStoreFlusher.requestFlush(null, false);
198 memStoreFlusher.requestFlush(null, false);
199 memStoreFlusher.requestFlush(null, false);
200 memStoreFlusher.requestFlush(null, false);
201
202 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
203 assertHeapSpaceDelta(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE, oldMemstoreHeapSize,
204 memStoreFlusher.memstoreSize);
205 assertHeapSpaceDelta(-(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE), oldBlockCacheSize,
206 blockCache.maxSize);
207 oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
208 oldBlockCacheSize = blockCache.maxSize;
209
210 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
211 memStoreFlusher.requestFlush(null, false);
212 memStoreFlusher.requestFlush(null, false);
213
214 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
215 assertHeapSpaceDelta(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE, oldMemstoreHeapSize,
216 memStoreFlusher.memstoreSize);
217 assertHeapSpaceDelta(-(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE), oldBlockCacheSize,
218 blockCache.maxSize);
219 }
220
221 @Test
222 public void testWhenClusterIsReadHeavy() throws Exception {
223 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
224 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
225 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
226
227 blockCache.setTestBlockSize((long) (maxHeapSize * 0.4 * 0.8));
228 regionServerAccounting.setTestMemstoreSize(0);
229 Configuration conf = HBaseConfiguration.create();
230 conf.setFloat(HeapMemorySizeUtil.MEMSTORE_SIZE_LOWER_LIMIT_KEY, 0.7f);
231 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
232 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
233 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
234 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
235 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
236 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
237
238 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
239 new RegionServerStub(conf), new RegionServerAccountingStub());
240 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
241 long oldBlockCacheSize = blockCache.maxSize;
242 long oldMemstoreLowerMarkSize = 7 * oldMemstoreHeapSize / 10;
243 long maxTuneSize = oldMemstoreHeapSize - (oldMemstoreLowerMarkSize + oldMemstoreHeapSize) / 2;
244 float maxStepValue = (maxTuneSize * 1.0f) / oldMemstoreHeapSize;
245 maxStepValue = maxStepValue > DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE ?
246 DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE:maxStepValue;
247 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
248 heapMemoryManager.start(choreService);
249 blockCache.evictBlock(null);
250 blockCache.evictBlock(null);
251 blockCache.evictBlock(null);
252
253 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
254 assertHeapSpaceDelta(-maxStepValue, oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
255 assertHeapSpaceDelta(maxStepValue, oldBlockCacheSize, blockCache.maxSize);
256 oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
257 oldBlockCacheSize = blockCache.maxSize;
258 oldMemstoreLowerMarkSize = 7 * oldMemstoreHeapSize / 10;
259 maxTuneSize = oldMemstoreHeapSize - (oldMemstoreLowerMarkSize + oldMemstoreHeapSize) / 2;
260 maxStepValue = (maxTuneSize * 1.0f) / oldMemstoreHeapSize;
261 maxStepValue = maxStepValue > DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE ?
262 DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE:maxStepValue;
263
264 blockCache.evictBlock(null);
265
266 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
267 assertHeapSpaceDelta(-maxStepValue, oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
268 assertHeapSpaceDelta(maxStepValue, oldBlockCacheSize, blockCache.maxSize);
269 }
270
271 @Test
272 public void testWhenClusterIsHavingMoreWritesThanReads() throws Exception {
273 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
274 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
275 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
276
277 blockCache.setTestBlockSize(0);
278 regionServerAccounting.setTestMemstoreSize((long) (maxHeapSize * 0.4 * 0.8));
279 blockCache.setTestBlockSize((long) (maxHeapSize * 0.4 * 0.8));
280 Configuration conf = HBaseConfiguration.create();
281 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
282 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
283 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
284 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
285 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
286 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
287
288 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
289 new RegionServerStub(conf), regionServerAccounting);
290 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
291 long oldBlockCacheSize = blockCache.maxSize;
292 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
293 heapMemoryManager.start(choreService);
294 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
295 memStoreFlusher.requestFlush(null, false);
296 memStoreFlusher.requestFlush(null, false);
297 memStoreFlusher.requestFlush(null, false);
298 blockCache.evictBlock(null);
299
300 Thread.sleep(1500);
301
302 assertEquals(oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
303 assertEquals(oldBlockCacheSize, blockCache.maxSize);
304
305 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
306 memStoreFlusher.requestFlush(null, false);
307 memStoreFlusher.requestFlush(null, false);
308 memStoreFlusher.requestFlush(null, false);
309
310 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
311 assertHeapSpaceDelta(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE, oldMemstoreHeapSize,
312 memStoreFlusher.memstoreSize);
313 assertHeapSpaceDelta(-(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE), oldBlockCacheSize,
314 blockCache.maxSize);
315 }
316
317 @Test
318 public void testBlockedFlushesIncreaseMemstoreInSteadyState() throws Exception {
319 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
320 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
321 RegionServerAccountingStub regionServerAccounting = new RegionServerAccountingStub();
322
323 blockCache.setTestBlockSize(0);
324 regionServerAccounting.setTestMemstoreSize((long) (maxHeapSize * 0.4 * 0.8));
325 blockCache.setTestBlockSize((long) (maxHeapSize * 0.4 * 0.8));
326 Configuration conf = HBaseConfiguration.create();
327 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.75f);
328 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.10f);
329 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
330 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.05f);
331 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
332 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
333
334 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
335 new RegionServerStub(conf), regionServerAccounting);
336 long oldMemstoreHeapSize = memStoreFlusher.memstoreSize;
337 long oldBlockCacheSize = blockCache.maxSize;
338 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
339 heapMemoryManager.start(choreService);
340 memStoreFlusher.flushType = FlushType.ABOVE_LOWER_MARK;
341 memStoreFlusher.requestFlush(null, false);
342 memStoreFlusher.requestFlush(null, false);
343 memStoreFlusher.requestFlush(null, false);
344 blockCache.evictBlock(null);
345 blockCache.evictBlock(null);
346
347 Thread.sleep(1500);
348
349 assertEquals(oldMemstoreHeapSize, memStoreFlusher.memstoreSize);
350 assertEquals(oldBlockCacheSize, blockCache.maxSize);
351
352 memStoreFlusher.flushType = FlushType.ABOVE_HIGHER_MARK;
353 memStoreFlusher.requestFlush(null, false);
354 blockCache.evictBlock(null);
355 blockCache.evictBlock(null);
356 blockCache.evictBlock(null);
357 blockCache.evictBlock(null);
358
359 Thread.sleep(1500);
360 assertHeapSpaceDelta(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE, oldMemstoreHeapSize,
361 memStoreFlusher.memstoreSize);
362 assertHeapSpaceDelta(-(DefaultHeapMemoryTuner.DEFAULT_MAX_STEP_VALUE), oldBlockCacheSize,
363 blockCache.maxSize);
364 }
365
366 @Test
367 public void testPluggingInHeapMemoryTuner() throws Exception {
368 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
369 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
370 Configuration conf = HBaseConfiguration.create();
371 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.78f);
372 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.05f);
373 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.75f);
374 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.02f);
375 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
376 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
377 conf.setClass(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_CLASS, CustomHeapMemoryTuner.class,
378 HeapMemoryTuner.class);
379
380 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
381 new RegionServerStub(conf), new RegionServerAccountingStub());
382 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
383 heapMemoryManager.start(choreService);
384
385 CustomHeapMemoryTuner.memstoreSize = 0.78f;
386 CustomHeapMemoryTuner.blockCacheSize = 0.02f;
387
388 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
389 assertHeapSpace(0.78f, memStoreFlusher.memstoreSize);
390 assertHeapSpace(0.02f, blockCache.maxSize);
391
392 CustomHeapMemoryTuner.blockCacheSize = 0.75f;
393 CustomHeapMemoryTuner.memstoreSize = 0.05f;
394
395 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
396 assertHeapSpace(0.75f, blockCache.maxSize);
397 assertHeapSpace(0.05f, memStoreFlusher.memstoreSize);
398 }
399
400 @Test
401 public void testWhenSizeGivenByHeapTunerGoesOutsideRange() throws Exception {
402 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
403 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
404 Configuration conf = HBaseConfiguration.create();
405 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.7f);
406 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.1f);
407 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
408 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.1f);
409 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
410 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
411 conf.setClass(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_CLASS, CustomHeapMemoryTuner.class,
412 HeapMemoryTuner.class);
413 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
414 new RegionServerStub(conf), new RegionServerAccountingStub());
415 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
416 heapMemoryManager.start(choreService);
417 CustomHeapMemoryTuner.memstoreSize = 0.78f;
418 CustomHeapMemoryTuner.blockCacheSize = 0.02f;
419 Thread.sleep(1500);
420
421
422 assertHeapSpace(0.7f, memStoreFlusher.memstoreSize);
423 assertHeapSpace(0.1f, blockCache.maxSize);
424 }
425
426 @Test
427 public void testWhenCombinedHeapSizesFromTunerGoesOutSideMaxLimit() throws Exception {
428 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
429 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.4));
430 Configuration conf = HBaseConfiguration.create();
431 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.7f);
432 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.1f);
433 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
434 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.1f);
435 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
436 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
437 conf.setClass(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_CLASS, CustomHeapMemoryTuner.class,
438 HeapMemoryTuner.class);
439 HeapMemoryManager heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
440 new RegionServerStub(conf), new RegionServerAccountingStub());
441 long oldMemstoreSize = memStoreFlusher.memstoreSize;
442 long oldBlockCacheSize = blockCache.maxSize;
443 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
444 heapMemoryManager.start(choreService);
445 CustomHeapMemoryTuner.memstoreSize = 0.7f;
446 CustomHeapMemoryTuner.blockCacheSize = 0.3f;
447
448 Thread.sleep(1500);
449 assertEquals(oldMemstoreSize, memStoreFlusher.memstoreSize);
450 assertEquals(oldBlockCacheSize, blockCache.maxSize);
451 }
452
453 @Test
454 public void testWhenL2BlockCacheIsOnHeap() throws Exception {
455 HeapMemoryManager heapMemoryManager = null;
456 BlockCacheStub blockCache = new BlockCacheStub((long) (maxHeapSize * 0.4));
457 MemstoreFlusherStub memStoreFlusher = new MemstoreFlusherStub((long) (maxHeapSize * 0.3));
458 Configuration conf = HBaseConfiguration.create();
459 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.7f);
460 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MIN_RANGE_KEY, 0.1f);
461 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.7f);
462 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MIN_RANGE_KEY, 0.1f);
463 conf.setInt(DefaultHeapMemoryTuner.NUM_PERIODS_TO_IGNORE, 0);
464 conf.setFloat(HeapMemorySizeUtil.MEMSTORE_SIZE_KEY, 0.4F);
465 conf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0.3F);
466 conf.setFloat(HConstants.BUCKET_CACHE_SIZE_KEY, 0.1F);
467 conf.set(HConstants.BUCKET_CACHE_IOENGINE_KEY, "heap");
468
469 conf.setLong(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_PERIOD, 1000);
470 conf.setClass(HeapMemoryManager.HBASE_RS_HEAP_MEMORY_TUNER_CLASS, CustomHeapMemoryTuner.class,
471 HeapMemoryTuner.class);
472
473 try {
474 heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
475 new RegionServerStub(conf), new RegionServerAccountingStub());
476 fail("Should have failed as the collective heap memory need is above 80%");
477 } catch (Exception e) {
478 }
479
480
481 conf.setFloat(HeapMemoryManager.MEMSTORE_SIZE_MAX_RANGE_KEY, 0.6f);
482 conf.setFloat(HeapMemoryManager.BLOCK_CACHE_SIZE_MAX_RANGE_KEY, 0.6f);
483 heapMemoryManager = new HeapMemoryManager(blockCache, memStoreFlusher,
484 new RegionServerStub(conf), new RegionServerAccountingStub());
485 long oldMemstoreSize = memStoreFlusher.memstoreSize;
486 long oldBlockCacheSize = blockCache.maxSize;
487 final ChoreService choreService = new ChoreService("TEST_SERVER_NAME");
488 heapMemoryManager.start(choreService);
489 CustomHeapMemoryTuner.memstoreSize = 0.4f;
490 CustomHeapMemoryTuner.blockCacheSize = 0.4f;
491
492 Thread.sleep(1500);
493
494
495 assertEquals(oldMemstoreSize, memStoreFlusher.memstoreSize);
496 assertEquals(oldBlockCacheSize, blockCache.maxSize);
497 CustomHeapMemoryTuner.memstoreSize = 0.1f;
498 CustomHeapMemoryTuner.blockCacheSize = 0.5f;
499
500 waitForTune(memStoreFlusher, memStoreFlusher.memstoreSize);
501 assertHeapSpace(0.1f, memStoreFlusher.memstoreSize);
502 assertHeapSpace(0.5f, blockCache.maxSize);
503 }
504
505 private void assertHeapSpace(float expectedHeapPercentage, long currentHeapSpace) {
506 long expected = (long) (this.maxHeapSize * expectedHeapPercentage);
507 assertEquals(expected, currentHeapSpace);
508 }
509
510 private void assertHeapSpaceDelta(double expectedDeltaPercent, long oldHeapSpace, long newHeapSpace) {
511 double expctedMinDelta = (double) (this.maxHeapSize * expectedDeltaPercent);
512
513 double error = 0.95;
514 if (expectedDeltaPercent > 0) {
515 assertTrue(expctedMinDelta*error <= (double)(newHeapSpace - oldHeapSpace));
516 assertTrue(expctedMinDelta/error >= (double)(newHeapSpace - oldHeapSpace));
517 } else {
518 assertTrue(-expctedMinDelta*error <= (double)(oldHeapSpace - newHeapSpace));
519 assertTrue(-expctedMinDelta/error >= (double)(oldHeapSpace - newHeapSpace));
520 }
521 }
522
523
524 private void waitForTune(final MemstoreFlusherStub memStoreFlusher,
525 final long oldMemstoreHeapSize) throws Exception {
526
527 UTIL.waitFor(10000, new Waiter.Predicate<Exception>() {
528 @Override
529 public boolean evaluate() throws Exception {
530 return oldMemstoreHeapSize != memStoreFlusher.memstoreSize;
531 }
532 });
533 }
534
535 private static class BlockCacheStub implements ResizableBlockCache {
536 CacheStats stats = new CacheStats("test");
537 long maxSize = 0;
538 private long testBlockSize = 0;
539
540 public BlockCacheStub(long size){
541 this.maxSize = size;
542 }
543
544 @Override
545 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory,
546 boolean cacheDataInL1) {
547
548 }
549
550 @Override
551 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
552
553 }
554
555 @Override
556 public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat,
557 boolean updateCacheMetrics) {
558 return null;
559 }
560
561 @Override
562 public boolean evictBlock(BlockCacheKey cacheKey) {
563 stats.evicted(0, cacheKey != null ? cacheKey.isPrimary() : true);
564 return false;
565 }
566
567 @Override
568 public int evictBlocksByHfileName(String hfileName) {
569 stats.evicted(0, true);
570 return 0;
571 }
572
573 @Override
574 public CacheStats getStats() {
575 return this.stats;
576 }
577
578 @Override
579 public void shutdown() {
580
581 }
582
583 @Override
584 public long size() {
585 return 0;
586 }
587
588 @Override
589 public long getFreeSize() {
590 return 0;
591 }
592
593 @Override
594 public long getCurrentSize() {
595 return this.testBlockSize;
596 }
597
598 @Override
599 public long getBlockCount() {
600 return 0;
601 }
602
603 @Override
604 public void setMaxSize(long size) {
605 this.maxSize = size;
606 }
607
608 @Override
609 public Iterator<CachedBlock> iterator() {
610 return null;
611 }
612
613 @Override
614 public BlockCache[] getBlockCaches() {
615 return null;
616 }
617
618 public void setTestBlockSize(long testBlockSize) {
619 this.testBlockSize = testBlockSize;
620 }
621 }
622
623 private static class MemstoreFlusherStub implements FlushRequester {
624
625 long memstoreSize;
626
627 FlushRequestListener listener;
628
629 FlushType flushType = FlushType.NORMAL;
630
631 public MemstoreFlusherStub(long memstoreSize) {
632 this.memstoreSize = memstoreSize;
633 }
634
635 @Override
636 public void requestFlush(Region region, boolean forceFlushAllStores) {
637 this.listener.flushRequested(flushType, region);
638 }
639
640 @Override
641 public void requestDelayedFlush(Region region, long delay, boolean forceFlushAllStores) {
642
643 }
644
645 @Override
646 public void registerFlushRequestListener(FlushRequestListener listener) {
647 this.listener = listener;
648 }
649
650 @Override
651 public boolean unregisterFlushRequestListener(FlushRequestListener listener) {
652 return false;
653 }
654
655 @Override
656 public void setGlobalMemstoreLimit(long globalMemStoreSize) {
657 this.memstoreSize = globalMemStoreSize;
658 }
659 }
660
661 private static class RegionServerStub implements Server {
662 private Configuration conf;
663 private boolean stopped = false;
664
665 public RegionServerStub(Configuration conf) {
666 this.conf = conf;
667 }
668
669 @Override
670 public void abort(String why, Throwable e) {
671
672 }
673
674 @Override
675 public boolean isAborted() {
676 return false;
677 }
678
679 @Override
680 public void stop(String why) {
681 this.stopped = true;
682 }
683
684 @Override
685 public boolean isStopped() {
686 return this.stopped;
687 }
688
689 @Override
690 public Configuration getConfiguration() {
691 return this.conf;
692 }
693
694 @Override
695 public ZooKeeperWatcher getZooKeeper() {
696 return null;
697 }
698
699 @Override
700 public CoordinatedStateManager getCoordinatedStateManager() {
701 return null;
702 }
703
704 @Override
705 public ClusterConnection getConnection() {
706 return null;
707 }
708
709 @Override
710 public MetaTableLocator getMetaTableLocator() {
711 return null;
712 }
713
714 @Override
715 public ServerName getServerName() {
716 return ServerName.valueOf("server1",4000,12345);
717 }
718
719 @Override
720 public ChoreService getChoreService() {
721 return null;
722 }
723 }
724
725 static class CustomHeapMemoryTuner implements HeapMemoryTuner {
726 static float blockCacheSize = 0.4f;
727 static float memstoreSize = 0.4f;
728
729 @Override
730 public Configuration getConf() {
731 return null;
732 }
733
734 @Override
735 public void setConf(Configuration arg0) {
736
737 }
738
739 @Override
740 public TunerResult tune(TunerContext context) {
741 TunerResult result = new TunerResult(true);
742 result.setBlockCacheSize(blockCacheSize);
743 result.setMemstoreSize(memstoreSize);
744 return result;
745 }
746 }
747
748 private static class RegionServerAccountingStub extends RegionServerAccounting {
749 private long testMemstoreSize = 0;
750 @Override
751 public long getGlobalMemstoreSize() {
752 return testMemstoreSize;
753 }
754 public void setTestMemstoreSize(long testMemstoreSize) {
755 this.testMemstoreSize = testMemstoreSize;
756 }
757 }
758 }