1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.io.hfile;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25
26 import java.nio.ByteBuffer;
27 import java.util.Random;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.testclassification.SmallTests;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.hbase.HBaseConfiguration;
37 import org.apache.hadoop.hbase.Waiter;
38 import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
39 import org.apache.hadoop.hbase.io.HeapSize;
40 import org.apache.hadoop.hbase.io.hfile.LruBlockCache.EvictionThread;
41 import org.apache.hadoop.hbase.util.ClassSize;
42 import org.junit.Test;
43 import org.junit.experimental.categories.Category;
44
45
46
47
48
49
50
51
52 @Category(SmallTests.class)
53 public class TestLruBlockCache {
54
55 @Test
56 public void testCacheEvictionThreadSafe() throws Exception {
57 long maxSize = 100000;
58 int numBlocks = 9;
59 int testRuns = 10;
60 final long blockSize = calculateBlockSizeDefault(maxSize, numBlocks);
61 assertTrue("calculateBlockSize appears broken.", blockSize * numBlocks <= maxSize);
62
63 final Configuration conf = HBaseConfiguration.create();
64 final LruBlockCache cache = new LruBlockCache(maxSize, blockSize);
65 EvictionThread evictionThread = cache.getEvictionThread();
66 assertTrue(evictionThread != null);
67 while (!evictionThread.isEnteringRun()) {
68 Thread.sleep(1);
69 }
70 final String hfileName = "hfile";
71 int threads = 10;
72 final int blocksPerThread = 5 * numBlocks;
73 for (int run = 0; run != testRuns; ++run) {
74 final AtomicInteger blockCount = new AtomicInteger(0);
75 ExecutorService service = Executors.newFixedThreadPool(threads);
76 for (int i = 0; i != threads; ++i) {
77 service.execute(new Runnable() {
78 @Override
79 public void run() {
80 for (int blockIndex = 0; blockIndex < blocksPerThread || (!cache.isEvictionInProgress()); ++blockIndex) {
81 CachedItem block = new CachedItem(hfileName, (int) blockSize, blockCount.getAndIncrement());
82 boolean inMemory = Math.random() > 0.5;
83 cache.cacheBlock(block.cacheKey, block, inMemory, false);
84 }
85 cache.evictBlocksByHfileName(hfileName);
86 }
87 });
88 }
89 service.shutdown();
90
91 service.awaitTermination(10, TimeUnit.MINUTES);
92 Waiter.waitFor(conf, 10000, 100, new ExplainingPredicate<Exception>() {
93 @Override
94 public boolean evaluate() throws Exception {
95 return cache.getBlockCount() == 0;
96 }
97
98 @Override
99 public String explainFailure() throws Exception {
100 return "Cache block count failed to return to 0";
101 }
102 });
103 assertEquals(0, cache.getBlockCount());
104 assertEquals(cache.getOverhead(), cache.getCurrentSize());
105 }
106 }
107 @Test
108 public void testBackgroundEvictionThread() throws Exception {
109 long maxSize = 100000;
110 int numBlocks = 9;
111 long blockSize = calculateBlockSizeDefault(maxSize, numBlocks);
112 assertTrue("calculateBlockSize appears broken.", blockSize * numBlocks <= maxSize);
113
114 LruBlockCache cache = new LruBlockCache(maxSize,blockSize);
115 EvictionThread evictionThread = cache.getEvictionThread();
116 assertTrue(evictionThread != null);
117
118 CachedItem[] blocks = generateFixedBlocks(numBlocks + 1, blockSize, "block");
119
120
121 while (!evictionThread.isEnteringRun()) {
122 Thread.sleep(1);
123 }
124
125
126 for (CachedItem block : blocks) {
127 cache.cacheBlock(block.cacheKey, block);
128 }
129
130
131 int n = 0;
132 while(cache.getStats().getEvictionCount() == 0) {
133 Thread.sleep(200);
134 assertTrue("Eviction never happened.", n++ < 20);
135 }
136
137
138
139
140
141
142
143
144 n = 0;
145 for (long prevCnt = 0
146 curCnt = cache.getBlockCount();
147 prevCnt != curCnt; prevCnt = curCnt, curCnt = cache.getBlockCount()) {
148 Thread.sleep(200);
149 assertTrue("Cache never stabilized.", n++ < 20);
150 }
151
152 long evictionCount = cache.getStats().getEvictionCount();
153 assertTrue(evictionCount >= 1);
154 System.out.println("Background Evictions run: " + evictionCount);
155 }
156
157 @Test
158 public void testCacheSimple() throws Exception {
159
160 long maxSize = 1000000;
161 long blockSize = calculateBlockSizeDefault(maxSize, 101);
162
163 LruBlockCache cache = new LruBlockCache(maxSize, blockSize);
164
165 CachedItem [] blocks = generateRandomBlocks(100, blockSize);
166
167 long expectedCacheSize = cache.heapSize();
168
169
170 for (CachedItem block : blocks) {
171 assertTrue(cache.getBlock(block.cacheKey, true, false, true) == null);
172 }
173
174
175 for (CachedItem block : blocks) {
176 cache.cacheBlock(block.cacheKey, block);
177 expectedCacheSize += block.cacheBlockHeapSize();
178 }
179
180
181 assertEquals(expectedCacheSize, cache.heapSize());
182
183
184 for (CachedItem block : blocks) {
185 HeapSize buf = cache.getBlock(block.cacheKey, true, false, true);
186 assertTrue(buf != null);
187 assertEquals(buf.heapSize(), block.heapSize());
188 }
189
190
191 long expectedBlockCount = cache.getBlockCount();
192 for (CachedItem block : blocks) {
193 cache.cacheBlock(block.cacheKey, block);
194 }
195 assertEquals(
196 "Cache should ignore cache requests for blocks already in cache",
197 expectedBlockCount, cache.getBlockCount());
198
199
200 assertEquals(expectedCacheSize, cache.heapSize());
201
202
203 for (CachedItem block : blocks) {
204 HeapSize buf = cache.getBlock(block.cacheKey, true, false, true);
205 assertTrue(buf != null);
206 assertEquals(buf.heapSize(), block.heapSize());
207 }
208
209
210 assertEquals(0, cache.getStats().getEvictionCount());
211 Thread t = new LruBlockCache.StatisticsThread(cache);
212 t.start();
213 t.join();
214 }
215
216 @Test
217 public void testCacheEvictionSimple() throws Exception {
218
219 long maxSize = 100000;
220 long blockSize = calculateBlockSizeDefault(maxSize, 10);
221
222 LruBlockCache cache = new LruBlockCache(maxSize,blockSize,false);
223
224 CachedItem [] blocks = generateFixedBlocks(10, blockSize, "block");
225
226 long expectedCacheSize = cache.heapSize();
227
228
229 for (CachedItem block : blocks) {
230 cache.cacheBlock(block.cacheKey, block);
231 expectedCacheSize += block.cacheBlockHeapSize();
232 }
233
234
235 assertEquals(1, cache.getStats().getEvictionCount());
236
237
238 assertTrue(expectedCacheSize >
239 (maxSize * LruBlockCache.DEFAULT_ACCEPTABLE_FACTOR));
240
241
242 assertTrue(cache.heapSize() < maxSize);
243
244
245 assertTrue(cache.heapSize() <
246 (maxSize * LruBlockCache.DEFAULT_ACCEPTABLE_FACTOR));
247
248
249 assertTrue(cache.getBlock(blocks[0].cacheKey, true, false, true) == null);
250 for(int i=1;i<blocks.length;i++) {
251 assertEquals(cache.getBlock(blocks[i].cacheKey, true, false, true),
252 blocks[i]);
253 }
254 }
255
256 @Test
257 public void testCacheEvictionTwoPriorities() throws Exception {
258
259 long maxSize = 100000;
260 long blockSize = calculateBlockSizeDefault(maxSize, 10);
261
262 LruBlockCache cache = new LruBlockCache(maxSize,blockSize,false);
263
264 CachedItem [] singleBlocks = generateFixedBlocks(5, 10000, "single");
265 CachedItem [] multiBlocks = generateFixedBlocks(5, 10000, "multi");
266
267 long expectedCacheSize = cache.heapSize();
268
269
270 for (CachedItem block : multiBlocks) {
271 cache.cacheBlock(block.cacheKey, block);
272 expectedCacheSize += block.cacheBlockHeapSize();
273 assertEquals(cache.getBlock(block.cacheKey, true, false, true), block);
274 }
275
276
277 for (CachedItem block : singleBlocks) {
278 cache.cacheBlock(block.cacheKey, block);
279 expectedCacheSize += block.heapSize();
280 }
281
282
283 assertEquals(cache.getStats().getEvictionCount(), 1);
284
285
286 assertEquals(cache.getStats().getEvictedCount(), 2);
287
288
289 assertTrue(expectedCacheSize >
290 (maxSize * LruBlockCache.DEFAULT_ACCEPTABLE_FACTOR));
291
292
293 assertTrue(cache.heapSize() <= maxSize);
294
295
296 assertTrue(cache.heapSize() <=
297 (maxSize * LruBlockCache.DEFAULT_ACCEPTABLE_FACTOR));
298
299
300
301
302
303 assertTrue(cache.getBlock(singleBlocks[0].cacheKey, true, false, true) == null);
304 assertTrue(cache.getBlock(multiBlocks[0].cacheKey, true, false, true) == null);
305
306
307 for(int i=1;i<4;i++) {
308 assertEquals(cache.getBlock(singleBlocks[i].cacheKey, true, false, true),
309 singleBlocks[i]);
310 assertEquals(cache.getBlock(multiBlocks[i].cacheKey, true, false, true),
311 multiBlocks[i]);
312 }
313 }
314
315 @Test
316 public void testCacheEvictionThreePriorities() throws Exception {
317
318 long maxSize = 100000;
319 long blockSize = calculateBlockSize(maxSize, 10);
320
321 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
322 (int)Math.ceil(1.2*maxSize/blockSize),
323 LruBlockCache.DEFAULT_LOAD_FACTOR,
324 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
325 0.98f,
326 0.99f,
327 0.33f,
328 0.33f,
329 0.34f,
330 1.2f,
331 false,
332 16 * 1024 * 1024);
333
334 CachedItem [] singleBlocks = generateFixedBlocks(5, blockSize, "single");
335 CachedItem [] multiBlocks = generateFixedBlocks(5, blockSize, "multi");
336 CachedItem [] memoryBlocks = generateFixedBlocks(5, blockSize, "memory");
337
338 long expectedCacheSize = cache.heapSize();
339
340
341 for(int i=0;i<3;i++) {
342
343
344 cache.cacheBlock(singleBlocks[i].cacheKey, singleBlocks[i]);
345 expectedCacheSize += singleBlocks[i].cacheBlockHeapSize();
346
347
348 cache.cacheBlock(multiBlocks[i].cacheKey, multiBlocks[i]);
349 expectedCacheSize += multiBlocks[i].cacheBlockHeapSize();
350 cache.getBlock(multiBlocks[i].cacheKey, true, false, true);
351
352
353 cache.cacheBlock(memoryBlocks[i].cacheKey, memoryBlocks[i], true, false);
354 expectedCacheSize += memoryBlocks[i].cacheBlockHeapSize();
355
356 }
357
358
359 assertEquals(0, cache.getStats().getEvictionCount());
360
361
362 assertEquals(expectedCacheSize, cache.heapSize());
363
364
365 cache.cacheBlock(singleBlocks[3].cacheKey, singleBlocks[3]);
366
367
368 assertEquals(1, cache.getStats().getEvictionCount());
369 assertEquals(1, cache.getStats().getEvictedCount());
370
371
372 assertEquals(null, cache.getBlock(singleBlocks[0].cacheKey, true, false, true));
373
374
375 cache.getBlock(singleBlocks[1].cacheKey, true, false, true);
376
377
378 cache.cacheBlock(singleBlocks[4].cacheKey, singleBlocks[4]);
379
380
381 assertEquals(2, cache.getStats().getEvictionCount());
382 assertEquals(2, cache.getStats().getEvictedCount());
383
384
385 assertEquals(null, cache.getBlock(multiBlocks[0].cacheKey, true, false, true));
386
387
388 cache.cacheBlock(memoryBlocks[3].cacheKey, memoryBlocks[3], true, false);
389
390
391 assertEquals(3, cache.getStats().getEvictionCount());
392 assertEquals(3, cache.getStats().getEvictedCount());
393
394
395 assertEquals(null, cache.getBlock(memoryBlocks[0].cacheKey, true, false, true));
396
397
398 CachedItem [] bigBlocks = generateFixedBlocks(3, blockSize*3, "big");
399 cache.cacheBlock(bigBlocks[0].cacheKey, bigBlocks[0]);
400
401
402 assertEquals(4, cache.getStats().getEvictionCount());
403 assertEquals(6, cache.getStats().getEvictedCount());
404
405
406 assertEquals(null, cache.getBlock(singleBlocks[2].cacheKey, true, false, true));
407 assertEquals(null, cache.getBlock(singleBlocks[3].cacheKey, true, false, true));
408 assertEquals(null, cache.getBlock(singleBlocks[4].cacheKey, true, false, true));
409
410
411 cache.getBlock(bigBlocks[0].cacheKey, true, false, true);
412
413
414 cache.cacheBlock(bigBlocks[1].cacheKey, bigBlocks[1]);
415
416
417 assertEquals(5, cache.getStats().getEvictionCount());
418 assertEquals(9, cache.getStats().getEvictedCount());
419
420
421 assertEquals(null, cache.getBlock(singleBlocks[1].cacheKey, true, false, true));
422 assertEquals(null, cache.getBlock(multiBlocks[1].cacheKey, true, false, true));
423 assertEquals(null, cache.getBlock(multiBlocks[2].cacheKey, true, false, true));
424
425
426 cache.cacheBlock(bigBlocks[2].cacheKey, bigBlocks[2], true, false);
427
428
429 assertEquals(6, cache.getStats().getEvictionCount());
430 assertEquals(12, cache.getStats().getEvictedCount());
431
432
433 assertEquals(null, cache.getBlock(memoryBlocks[1].cacheKey, true, false, true));
434 assertEquals(null, cache.getBlock(memoryBlocks[2].cacheKey, true, false, true));
435 assertEquals(null, cache.getBlock(memoryBlocks[3].cacheKey, true, false, true));
436 }
437
438 @Test
439 public void testCacheEvictionInMemoryForceMode() throws Exception {
440 long maxSize = 100000;
441 long blockSize = calculateBlockSize(maxSize, 10);
442
443 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
444 (int)Math.ceil(1.2*maxSize/blockSize),
445 LruBlockCache.DEFAULT_LOAD_FACTOR,
446 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
447 0.98f,
448 0.99f,
449 0.2f,
450 0.3f,
451 0.5f,
452 1.2f,
453 true,
454 16 * 1024 * 1024);
455
456 CachedItem [] singleBlocks = generateFixedBlocks(10, blockSize, "single");
457 CachedItem [] multiBlocks = generateFixedBlocks(10, blockSize, "multi");
458 CachedItem [] memoryBlocks = generateFixedBlocks(10, blockSize, "memory");
459
460 long expectedCacheSize = cache.heapSize();
461
462
463 for(int i = 0; i < 4; i++) {
464
465 cache.cacheBlock(singleBlocks[i].cacheKey, singleBlocks[i]);
466 expectedCacheSize += singleBlocks[i].cacheBlockHeapSize();
467
468 cache.cacheBlock(multiBlocks[i].cacheKey, multiBlocks[i]);
469 expectedCacheSize += multiBlocks[i].cacheBlockHeapSize();
470 cache.getBlock(multiBlocks[i].cacheKey, true, false, true);
471 }
472
473 cache.cacheBlock(singleBlocks[4].cacheKey, singleBlocks[4]);
474 expectedCacheSize += singleBlocks[4].cacheBlockHeapSize();
475
476 assertEquals(0, cache.getStats().getEvictionCount());
477
478 assertEquals(expectedCacheSize, cache.heapSize());
479
480
481 cache.cacheBlock(memoryBlocks[0].cacheKey, memoryBlocks[0], true, false);
482
483 assertEquals(1, cache.getStats().getEvictionCount());
484 assertEquals(1, cache.getStats().getEvictedCount());
485
486 assertEquals(null, cache.getBlock(singleBlocks[0].cacheKey, true, false, true));
487
488
489 cache.cacheBlock(memoryBlocks[1].cacheKey, memoryBlocks[1], true, false);
490
491 assertEquals(2, cache.getStats().getEvictionCount());
492 assertEquals(2, cache.getStats().getEvictedCount());
493
494 assertEquals(null, cache.getBlock(singleBlocks[1].cacheKey, true, false, true));
495
496
497 cache.cacheBlock(memoryBlocks[2].cacheKey, memoryBlocks[2], true, false);
498 cache.cacheBlock(memoryBlocks[3].cacheKey, memoryBlocks[3], true, false);
499 cache.cacheBlock(memoryBlocks[4].cacheKey, memoryBlocks[4], true, false);
500 cache.cacheBlock(memoryBlocks[5].cacheKey, memoryBlocks[5], true, false);
501
502 assertEquals(6, cache.getStats().getEvictionCount());
503 assertEquals(6, cache.getStats().getEvictedCount());
504
505 assertEquals(null, cache.getBlock(singleBlocks[2].cacheKey, true, false, true));
506 assertEquals(null, cache.getBlock(singleBlocks[3].cacheKey, true, false, true));
507 assertEquals(null, cache.getBlock(multiBlocks[0].cacheKey, true, false, true));
508 assertEquals(null, cache.getBlock(multiBlocks[1].cacheKey, true, false, true));
509
510
511
512 cache.cacheBlock(memoryBlocks[6].cacheKey, memoryBlocks[6], true, false);
513 cache.cacheBlock(memoryBlocks[7].cacheKey, memoryBlocks[7], true, false);
514 cache.cacheBlock(memoryBlocks[8].cacheKey, memoryBlocks[8], true, false);
515
516 assertEquals(9, cache.getStats().getEvictionCount());
517 assertEquals(9, cache.getStats().getEvictedCount());
518
519 assertEquals(null, cache.getBlock(singleBlocks[4].cacheKey, true, false, true));
520 assertEquals(null, cache.getBlock(multiBlocks[2].cacheKey, true, false, true));
521 assertEquals(null, cache.getBlock(multiBlocks[3].cacheKey, true, false, true));
522
523
524
525 cache.cacheBlock(memoryBlocks[9].cacheKey, memoryBlocks[9], true, false);
526
527 assertEquals(10, cache.getStats().getEvictionCount());
528 assertEquals(10, cache.getStats().getEvictedCount());
529
530 assertEquals(null, cache.getBlock(memoryBlocks[0].cacheKey, true, false, true));
531
532
533
534
535 cache.cacheBlock(singleBlocks[9].cacheKey, singleBlocks[9]);
536
537 assertEquals(11, cache.getStats().getEvictionCount());
538 assertEquals(11, cache.getStats().getEvictedCount());
539
540 assertEquals(null, cache.getBlock(singleBlocks[9].cacheKey, true, false, true));
541 }
542
543
544 @Test
545 public void testScanResistance() throws Exception {
546
547 long maxSize = 100000;
548 long blockSize = calculateBlockSize(maxSize, 10);
549
550 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
551 (int)Math.ceil(1.2*maxSize/blockSize),
552 LruBlockCache.DEFAULT_LOAD_FACTOR,
553 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
554 0.66f,
555 0.99f,
556 0.33f,
557 0.33f,
558 0.34f,
559 1.2f,
560 false,
561 16 * 1024 * 1024);
562
563 CachedItem [] singleBlocks = generateFixedBlocks(20, blockSize, "single");
564 CachedItem [] multiBlocks = generateFixedBlocks(5, blockSize, "multi");
565
566
567 for (CachedItem block : multiBlocks) {
568 cache.cacheBlock(block.cacheKey, block);
569 cache.getBlock(block.cacheKey, true, false, true);
570 }
571
572
573 for(int i=0;i<5;i++) {
574 cache.cacheBlock(singleBlocks[i].cacheKey, singleBlocks[i]);
575 }
576
577
578 assertEquals(1, cache.getStats().getEvictionCount());
579
580
581 assertEquals(4, cache.getStats().getEvictedCount());
582
583
584 assertEquals(null, cache.getBlock(singleBlocks[0].cacheKey, true, false, true));
585 assertEquals(null, cache.getBlock(singleBlocks[1].cacheKey, true, false, true));
586 assertEquals(null, cache.getBlock(multiBlocks[0].cacheKey, true, false, true));
587 assertEquals(null, cache.getBlock(multiBlocks[1].cacheKey, true, false, true));
588
589
590
591
592
593
594
595
596 for(int i=5;i<18;i++) {
597 cache.cacheBlock(singleBlocks[i].cacheKey, singleBlocks[i]);
598 }
599
600
601 assertEquals(4, cache.getStats().getEvictionCount());
602 assertEquals(16, cache.getStats().getEvictedCount());
603
604
605 assertEquals(7, cache.getBlockCount());
606
607 }
608
609 @Test
610 public void testMaxBlockSize() throws Exception {
611 long maxSize = 100000;
612 long blockSize = calculateBlockSize(maxSize, 10);
613
614 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
615 (int)Math.ceil(1.2*maxSize/blockSize),
616 LruBlockCache.DEFAULT_LOAD_FACTOR,
617 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
618 0.66f,
619 0.99f,
620 0.33f,
621 0.33f,
622 0.34f,
623 1.2f,
624 false,
625 1024);
626 CachedItem [] tooLong = generateFixedBlocks(10, 1024+5, "long");
627 CachedItem [] small = generateFixedBlocks(15, 600, "small");
628
629
630 for (CachedItem i:tooLong) {
631 cache.cacheBlock(i.cacheKey, i);
632 }
633 for (CachedItem i:small) {
634 cache.cacheBlock(i.cacheKey, i);
635 }
636 assertEquals(15,cache.getBlockCount());
637 for (CachedItem i:small) {
638 assertNotNull(cache.getBlock(i.cacheKey, true, false, false));
639 }
640 for (CachedItem i:tooLong) {
641 assertNull(cache.getBlock(i.cacheKey, true, false, false));
642 }
643
644 assertEquals(10, cache.getStats().getFailedInserts());
645 }
646
647
648 @Test
649 public void testResizeBlockCache() throws Exception {
650
651 long maxSize = 300000;
652 long blockSize = calculateBlockSize(maxSize, 31);
653
654 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
655 (int)Math.ceil(1.2*maxSize/blockSize),
656 LruBlockCache.DEFAULT_LOAD_FACTOR,
657 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
658 0.98f,
659 0.99f,
660 0.33f,
661 0.33f,
662 0.34f,
663 1.2f,
664 false,
665 16 * 1024 * 1024);
666
667 CachedItem [] singleBlocks = generateFixedBlocks(10, blockSize, "single");
668 CachedItem [] multiBlocks = generateFixedBlocks(10, blockSize, "multi");
669 CachedItem [] memoryBlocks = generateFixedBlocks(10, blockSize, "memory");
670
671
672 for(int i=0;i<10;i++) {
673
674
675 cache.cacheBlock(singleBlocks[i].cacheKey, singleBlocks[i]);
676
677
678 cache.cacheBlock(multiBlocks[i].cacheKey, multiBlocks[i]);
679 cache.getBlock(multiBlocks[i].cacheKey, true, false, true);
680
681
682 cache.cacheBlock(memoryBlocks[i].cacheKey, memoryBlocks[i], true, false);
683 }
684
685
686 assertEquals(0, cache.getStats().getEvictionCount());
687
688
689 cache.setMaxSize((long)(maxSize * 0.5f));
690
691
692 assertEquals(1, cache.getStats().getEvictionCount());
693
694
695 assertEquals(15, cache.getStats().getEvictedCount());
696
697
698 for(int i=0;i<5;i++) {
699 assertEquals(null, cache.getBlock(singleBlocks[i].cacheKey, true, false, true));
700 assertEquals(null, cache.getBlock(multiBlocks[i].cacheKey, true, false, true));
701 assertEquals(null, cache.getBlock(memoryBlocks[i].cacheKey, true, false, true));
702 }
703
704
705 for(int i=5;i<10;i++) {
706 assertEquals(singleBlocks[i], cache.getBlock(singleBlocks[i].cacheKey, true, false, true));
707 assertEquals(multiBlocks[i], cache.getBlock(multiBlocks[i].cacheKey, true, false, true));
708 assertEquals(memoryBlocks[i], cache.getBlock(memoryBlocks[i].cacheKey, true, false, true));
709 }
710 }
711
712
713 @Test
714 public void testPastNPeriodsMetrics() throws Exception {
715 double delta = 0.01;
716
717
718 CacheStats stats = new CacheStats("test", 3);
719
720
721 stats.rollMetricsPeriod();
722 assertEquals(0.0, stats.getHitRatioPastNPeriods(), delta);
723 assertEquals(0.0, stats.getHitCachingRatioPastNPeriods(), delta);
724
725
726
727 stats.hit(false, true, BlockType.DATA);
728 stats.hit(true, true, BlockType.DATA);
729 stats.miss(false, false, BlockType.DATA);
730 stats.miss(false, false, BlockType.DATA);
731 stats.rollMetricsPeriod();
732 assertEquals(0.5, stats.getHitRatioPastNPeriods(), delta);
733 assertEquals(1.0, stats.getHitCachingRatioPastNPeriods(), delta);
734
735
736
737 stats.miss(true, false, BlockType.DATA);
738 stats.miss(false, false, BlockType.DATA);
739 stats.miss(false, false, BlockType.DATA);
740 stats.miss(false, false, BlockType.DATA);
741 stats.rollMetricsPeriod();
742 assertEquals(0.25, stats.getHitRatioPastNPeriods(), delta);
743 assertEquals(0.5, stats.getHitCachingRatioPastNPeriods(), delta);
744
745
746
747 stats.hit(false, true, BlockType.DATA);
748 stats.hit(true, true, BlockType.DATA);
749 stats.hit(false, true, BlockType.DATA);
750 stats.hit(true, true, BlockType.DATA);
751 stats.rollMetricsPeriod();
752 assertEquals(0.5, stats.getHitRatioPastNPeriods(), delta);
753 assertEquals(0.75, stats.getHitCachingRatioPastNPeriods(), delta);
754
755
756
757 stats.miss(true, false, BlockType.DATA);
758 stats.miss(true, false, BlockType.DATA);
759 stats.rollMetricsPeriod();
760 assertEquals(0.4, stats.getHitRatioPastNPeriods(), delta);
761 assertEquals(0.4, stats.getHitCachingRatioPastNPeriods(), delta);
762
763
764
765 stats.miss(true, false, BlockType.DATA);
766 stats.miss(true, false, BlockType.DATA);
767 stats.hit(false, true, BlockType.DATA);
768 stats.hit(false, true, BlockType.DATA);
769 stats.rollMetricsPeriod();
770 assertEquals(0.6, stats.getHitRatioPastNPeriods(), delta);
771 assertEquals((double)1/3, stats.getHitCachingRatioPastNPeriods(), delta);
772
773
774
775 stats.rollMetricsPeriod();
776 assertEquals((double)1/3, stats.getHitRatioPastNPeriods(), delta);
777 assertEquals(0.0, stats.getHitCachingRatioPastNPeriods(), delta);
778
779
780
781 stats.rollMetricsPeriod();
782 assertEquals(0.5, stats.getHitRatioPastNPeriods(), delta);
783 assertEquals(0.0, stats.getHitCachingRatioPastNPeriods(), delta);
784
785
786
787 stats.rollMetricsPeriod();
788 assertEquals(0.0, stats.getHitRatioPastNPeriods(), delta);
789 assertEquals(0.0, stats.getHitCachingRatioPastNPeriods(), delta);
790
791
792
793 stats.miss(true, false, BlockType.DATA);
794 stats.miss(false, false, BlockType.DATA);
795 stats.hit(true, true, BlockType.DATA);
796 stats.hit(false, true, BlockType.DATA);
797 stats.rollMetricsPeriod();
798 assertEquals(0.5, stats.getHitRatioPastNPeriods(), delta);
799 assertEquals(0.5, stats.getHitCachingRatioPastNPeriods(), delta);
800 }
801
802 @Test
803 public void testCacheBlockNextBlockMetadataMissing() {
804 long maxSize = 100000;
805 long blockSize = calculateBlockSize(maxSize, 10);
806 int size = 100;
807 int length = HConstants.HFILEBLOCK_HEADER_SIZE + size;
808 byte[] byteArr = new byte[length];
809 ByteBuffer buf = ByteBuffer.wrap(byteArr, 0, size);
810 HFileContext meta = new HFileContextBuilder().build();
811 HFileBlock blockWithNextBlockMetadata = new HFileBlock(BlockType.DATA, size, size, -1, buf,
812 HFileBlock.FILL_HEADER, -1, 52, -1, meta);
813 HFileBlock blockWithoutNextBlockMetadata = new HFileBlock(BlockType.DATA, size, size, -1, buf,
814 HFileBlock.FILL_HEADER, -1, -1, -1, meta);
815
816 LruBlockCache cache = new LruBlockCache(maxSize, blockSize, false,
817 (int)Math.ceil(1.2*maxSize/blockSize),
818 LruBlockCache.DEFAULT_LOAD_FACTOR,
819 LruBlockCache.DEFAULT_CONCURRENCY_LEVEL,
820 0.66f,
821 0.99f,
822 0.33f,
823 0.33f,
824 0.34f,
825 1.2f,
826 false,
827 1024);
828
829 BlockCacheKey key = new BlockCacheKey("key1", 0);
830 ByteBuffer actualBuffer = ByteBuffer.allocate(length);
831 ByteBuffer block1Buffer = ByteBuffer.allocate(length);
832 ByteBuffer block2Buffer = ByteBuffer.allocate(length);
833 blockWithNextBlockMetadata.serialize(block1Buffer, true);
834 blockWithoutNextBlockMetadata.serialize(block2Buffer, true);
835
836
837 CacheTestUtils.getBlockAndAssertEquals(cache, key, blockWithNextBlockMetadata,
838 actualBuffer, block1Buffer);
839
840
841 CacheTestUtils.getBlockAndAssertEquals(cache, key, blockWithoutNextBlockMetadata,
842 actualBuffer, block1Buffer);
843
844
845 cache.clearCache();
846 assertNull(cache.getBlock(key, false, false, false));
847 CacheTestUtils.getBlockAndAssertEquals(cache, key, blockWithoutNextBlockMetadata,
848 actualBuffer, block2Buffer);
849
850
851 CacheTestUtils.getBlockAndAssertEquals(cache, key, blockWithNextBlockMetadata,
852 actualBuffer, block1Buffer);
853 }
854
855 private CachedItem [] generateFixedBlocks(int numBlocks, int size, String pfx) {
856 CachedItem [] blocks = new CachedItem[numBlocks];
857 for(int i=0;i<numBlocks;i++) {
858 blocks[i] = new CachedItem(pfx + i, size);
859 }
860 return blocks;
861 }
862
863 private CachedItem [] generateFixedBlocks(int numBlocks, long size, String pfx) {
864 return generateFixedBlocks(numBlocks, (int)size, pfx);
865 }
866
867 private CachedItem [] generateRandomBlocks(int numBlocks, long maxSize) {
868 CachedItem [] blocks = new CachedItem[numBlocks];
869 Random r = new Random();
870 for(int i=0;i<numBlocks;i++) {
871 blocks[i] = new CachedItem("block" + i, r.nextInt((int)maxSize)+1);
872 }
873 return blocks;
874 }
875
876 private long calculateBlockSize(long maxSize, int numBlocks) {
877 long roughBlockSize = maxSize / numBlocks;
878 int numEntries = (int)Math.ceil((1.2)*maxSize/roughBlockSize);
879 long totalOverhead = LruBlockCache.CACHE_FIXED_OVERHEAD +
880 ClassSize.CONCURRENT_HASHMAP +
881 (numEntries * ClassSize.CONCURRENT_HASHMAP_ENTRY) +
882 (LruBlockCache.DEFAULT_CONCURRENCY_LEVEL * ClassSize.CONCURRENT_HASHMAP_SEGMENT);
883 long negateBlockSize = (long)(totalOverhead/numEntries);
884 negateBlockSize += LruCachedBlock.PER_BLOCK_OVERHEAD;
885 return ClassSize.align((long)Math.floor((roughBlockSize - negateBlockSize)*0.99f));
886 }
887
888 private long calculateBlockSizeDefault(long maxSize, int numBlocks) {
889 long roughBlockSize = maxSize / numBlocks;
890 int numEntries = (int)Math.ceil((1.2)*maxSize/roughBlockSize);
891 long totalOverhead = LruBlockCache.CACHE_FIXED_OVERHEAD +
892 ClassSize.CONCURRENT_HASHMAP +
893 (numEntries * ClassSize.CONCURRENT_HASHMAP_ENTRY) +
894 (LruBlockCache.DEFAULT_CONCURRENCY_LEVEL * ClassSize.CONCURRENT_HASHMAP_SEGMENT);
895 long negateBlockSize = totalOverhead / numEntries;
896 negateBlockSize += LruCachedBlock.PER_BLOCK_OVERHEAD;
897 return ClassSize.align((long)Math.floor((roughBlockSize - negateBlockSize)*
898 LruBlockCache.DEFAULT_ACCEPTABLE_FACTOR));
899 }
900
901 private static class CachedItem implements Cacheable {
902 BlockCacheKey cacheKey;
903 int size;
904
905 CachedItem(String blockName, int size, int offset) {
906 this.cacheKey = new BlockCacheKey(blockName, offset);
907 this.size = size;
908 }
909
910 CachedItem(String blockName, int size) {
911 this.cacheKey = new BlockCacheKey(blockName, 0);
912 this.size = size;
913 }
914
915
916 @Override
917 public long heapSize() {
918 return ClassSize.align(size);
919 }
920
921
922 public long cacheBlockHeapSize() {
923 return LruCachedBlock.PER_BLOCK_OVERHEAD
924 + ClassSize.align(cacheKey.heapSize())
925 + ClassSize.align(size);
926 }
927
928 @Override
929 public int getSerializedLength() {
930 return 0;
931 }
932
933 @Override
934 public CacheableDeserializer<Cacheable> getDeserializer() {
935 return null;
936 }
937
938 @Override
939 public void serialize(ByteBuffer destination, boolean includeNextBlockOnDiskSize) {
940 }
941
942 @Override
943 public BlockType getBlockType() {
944 return BlockType.DATA;
945 }
946
947 }
948
949 }
950