001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.io; 019 020import static org.hamcrest.MatcherAssert.assertThat; 021import static org.hamcrest.Matchers.lessThan; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024 025import java.io.IOException; 026import java.lang.management.ManagementFactory; 027import java.lang.management.RuntimeMXBean; 028import java.nio.ByteBuffer; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Map; 034import java.util.TreeMap; 035import java.util.concurrent.ConcurrentHashMap; 036import java.util.concurrent.ConcurrentSkipListMap; 037import java.util.concurrent.CopyOnWriteArrayList; 038import java.util.concurrent.CopyOnWriteArraySet; 039import java.util.concurrent.TimeUnit; 040import java.util.concurrent.atomic.AtomicBoolean; 041import java.util.concurrent.atomic.AtomicInteger; 042import java.util.concurrent.atomic.AtomicLong; 043import java.util.concurrent.atomic.AtomicReference; 044import java.util.concurrent.locks.ReentrantReadWriteLock; 045import org.apache.hadoop.hbase.KeyValue; 046import org.apache.hadoop.hbase.client.Delete; 047import org.apache.hadoop.hbase.client.Mutation; 048import org.apache.hadoop.hbase.client.Put; 049import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; 050import org.apache.hadoop.hbase.io.hfile.ExclusiveMemHFileBlock; 051import org.apache.hadoop.hbase.io.hfile.HFileBlock; 052import org.apache.hadoop.hbase.io.hfile.HFileContext; 053import org.apache.hadoop.hbase.io.hfile.LruBlockCache; 054import org.apache.hadoop.hbase.io.hfile.LruCachedBlock; 055import org.apache.hadoop.hbase.io.hfile.SharedMemHFileBlock; 056import org.apache.hadoop.hbase.regionserver.CSLMImmutableSegment; 057import org.apache.hadoop.hbase.regionserver.CellArrayImmutableSegment; 058import org.apache.hadoop.hbase.regionserver.CellArrayMap; 059import org.apache.hadoop.hbase.regionserver.CellSet; 060import org.apache.hadoop.hbase.regionserver.CompactingMemStore; 061import org.apache.hadoop.hbase.regionserver.CompactionPipeline; 062import org.apache.hadoop.hbase.regionserver.DefaultMemStore; 063import org.apache.hadoop.hbase.regionserver.HRegion; 064import org.apache.hadoop.hbase.regionserver.HStore; 065import org.apache.hadoop.hbase.regionserver.ImmutableSegment; 066import org.apache.hadoop.hbase.regionserver.MemStoreCompactor; 067import org.apache.hadoop.hbase.regionserver.MutableSegment; 068import org.apache.hadoop.hbase.regionserver.Segment; 069import org.apache.hadoop.hbase.regionserver.StoreContext; 070import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.NonSyncTimeRangeTracker; 071import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.SyncTimeRangeTracker; 072import org.apache.hadoop.hbase.regionserver.throttle.StoreHotnessProtector; 073import org.apache.hadoop.hbase.testclassification.IOTests; 074import org.apache.hadoop.hbase.testclassification.SmallTests; 075import org.apache.hadoop.hbase.util.ClassSize; 076import org.junit.jupiter.api.BeforeAll; 077import org.junit.jupiter.api.Tag; 078import org.junit.jupiter.api.Test; 079import org.slf4j.Logger; 080import org.slf4j.LoggerFactory; 081 082/** 083 * Testing the sizing that HeapSize offers and compares to the size given by ClassSize. 084 */ 085@Tag(IOTests.TAG) 086@Tag(SmallTests.TAG) 087public class TestHeapSize { 088 089 private static final Logger LOG = LoggerFactory.getLogger(TestHeapSize.class); 090 // List of classes implementing HeapSize 091 // BatchOperation, BatchUpdate, BlockIndex, Entry, Entry<K,V>, HStoreKey 092 // KeyValue, LruBlockCache, Put, WALKey 093 094 @BeforeAll 095 public static void beforeClass() throws Exception { 096 // Print detail on jvm so we know what is different should below test fail. 097 RuntimeMXBean b = ManagementFactory.getRuntimeMXBean(); 098 LOG.info("name=" + b.getName()); 099 LOG.info("specname=" + b.getSpecName()); 100 LOG.info("specvendor=" + b.getSpecVendor()); 101 LOG.info("vmname=" + b.getVmName()); 102 LOG.info("vmversion=" + b.getVmVersion()); 103 LOG.info("vmvendor=" + b.getVmVendor()); 104 Map<String, String> p = b.getSystemProperties(); 105 LOG.info("properties=" + p); 106 } 107 108 /** 109 * Test our hard-coded sizing of native java objects 110 */ 111 @Test 112 public void testNativeSizes() throws IOException { 113 Class<?> cl; 114 long expected; 115 long actual; 116 117 // ArrayList 118 cl = ArrayList.class; 119 expected = ClassSize.estimateBase(cl, false); 120 actual = ClassSize.ARRAYLIST; 121 if (expected != actual) { 122 ClassSize.estimateBase(cl, true); 123 assertEquals(expected, actual); 124 } 125 126 // ByteBuffer 127 cl = ByteBuffer.class; 128 expected = ClassSize.estimateBase(cl, false); 129 actual = ClassSize.BYTE_BUFFER; 130 if (expected != actual) { 131 ClassSize.estimateBase(cl, true); 132 assertEquals(expected, actual); 133 } 134 135 // Integer 136 cl = Integer.class; 137 expected = ClassSize.estimateBase(cl, false); 138 actual = ClassSize.INTEGER; 139 if (expected != actual) { 140 ClassSize.estimateBase(cl, true); 141 assertEquals(expected, actual); 142 } 143 144 // Map.Entry 145 // Interface is public, all others are not. Hard to size via ClassSize 146 // cl = Map.Entry.class; 147 // expected = ClassSize.estimateBase(cl, false); 148 // actual = ClassSize.MAP_ENTRY; 149 // if(expected != actual) { 150 // ClassSize.estimateBase(cl, true); 151 // assertEquals(expected, actual); 152 // } 153 154 // Object 155 cl = Object.class; 156 expected = ClassSize.estimateBase(cl, false); 157 actual = ClassSize.align(ClassSize.OBJECT); 158 if (expected != actual) { 159 ClassSize.estimateBase(cl, true); 160 assertEquals(expected, actual); 161 } 162 163 // TreeMap 164 cl = TreeMap.class; 165 expected = ClassSize.estimateBase(cl, false); 166 actual = ClassSize.TREEMAP; 167 if (expected != actual) { 168 ClassSize.estimateBase(cl, true); 169 assertEquals(expected, actual); 170 } 171 172 // String 173 cl = String.class; 174 expected = ClassSize.estimateBase(cl, false); 175 actual = ClassSize.STRING; 176 if (expected != actual) { 177 ClassSize.estimateBase(cl, true); 178 assertEquals(expected, actual); 179 } 180 181 // ConcurrentHashMap 182 cl = ConcurrentHashMap.class; 183 expected = ClassSize.estimateBase(cl, false); 184 actual = ClassSize.CONCURRENT_HASHMAP; 185 if (expected != actual) { 186 ClassSize.estimateBase(cl, true); 187 assertEquals(expected, actual); 188 } 189 190 // ConcurrentSkipListMap 191 cl = ConcurrentSkipListMap.class; 192 expected = ClassSize.estimateBase(cl, false); 193 actual = ClassSize.CONCURRENT_SKIPLISTMAP; 194 if (expected != actual) { 195 ClassSize.estimateBase(cl, true); 196 assertEquals(expected, actual); 197 } 198 199 // CellArrayMap 200 cl = CellArrayMap.class; 201 expected = ClassSize.estimateBase(cl, false); 202 actual = ClassSize.CELL_ARRAY_MAP; 203 if (expected != actual) { 204 ClassSize.estimateBase(cl, true); 205 assertEquals(expected, actual); 206 } 207 208 // ReentrantReadWriteLock 209 cl = ReentrantReadWriteLock.class; 210 expected = ClassSize.estimateBase(cl, false); 211 actual = ClassSize.REENTRANT_LOCK; 212 if (expected != actual) { 213 ClassSize.estimateBase(cl, true); 214 assertEquals(expected, actual); 215 } 216 217 // AtomicLong 218 cl = AtomicLong.class; 219 expected = ClassSize.estimateBase(cl, false); 220 actual = ClassSize.ATOMIC_LONG; 221 if (expected != actual) { 222 ClassSize.estimateBase(cl, true); 223 assertEquals(expected, actual); 224 } 225 226 // AtomicInteger 227 cl = AtomicInteger.class; 228 expected = ClassSize.estimateBase(cl, false); 229 actual = ClassSize.ATOMIC_INTEGER; 230 if (expected != actual) { 231 ClassSize.estimateBase(cl, true); 232 assertEquals(expected, actual); 233 } 234 235 // AtomicBoolean 236 cl = AtomicBoolean.class; 237 expected = ClassSize.estimateBase(cl, false); 238 actual = ClassSize.ATOMIC_BOOLEAN; 239 if (expected != actual) { 240 ClassSize.estimateBase(cl, true); 241 assertEquals(expected, actual); 242 } 243 244 // CopyOnWriteArraySet 245 cl = CopyOnWriteArraySet.class; 246 expected = ClassSize.estimateBase(cl, false); 247 actual = ClassSize.COPYONWRITE_ARRAYSET; 248 if (expected != actual) { 249 ClassSize.estimateBase(cl, true); 250 assertEquals(expected, actual); 251 } 252 253 // CopyOnWriteArrayList 254 cl = CopyOnWriteArrayList.class; 255 expected = ClassSize.estimateBase(cl, false); 256 actual = ClassSize.COPYONWRITE_ARRAYLIST; 257 if (expected != actual) { 258 ClassSize.estimateBase(cl, true); 259 assertEquals(expected, actual); 260 } 261 262 // SyncTimeRangeTracker 263 cl = SyncTimeRangeTracker.class; 264 expected = ClassSize.estimateBase(cl, false); 265 actual = ClassSize.SYNC_TIMERANGE_TRACKER; 266 if (expected != actual) { 267 ClassSize.estimateBase(cl, true); 268 assertEquals(expected, actual); 269 } 270 271 // NonSyncTimeRangeTracker 272 cl = NonSyncTimeRangeTracker.class; 273 expected = ClassSize.estimateBase(cl, false); 274 actual = ClassSize.NON_SYNC_TIMERANGE_TRACKER; 275 if (expected != actual) { 276 ClassSize.estimateBase(cl, true); 277 assertEquals(expected, actual); 278 } 279 280 // CellSet 281 cl = CellSet.class; 282 expected = ClassSize.estimateBase(cl, false); 283 actual = ClassSize.CELL_SET; 284 if (expected != actual) { 285 ClassSize.estimateBase(cl, true); 286 assertEquals(expected, actual); 287 } 288 } 289 290 /** 291 * Testing the classes that implements HeapSize and are a part of 0.20. Some are not tested here 292 * for example BlockIndex which is tested in TestHFile since it is a non public class 293 */ 294 @Test 295 public void testSizes() throws IOException { 296 Class<?> cl; 297 long expected; 298 long actual; 299 300 // KeyValue 301 cl = KeyValue.class; 302 expected = ClassSize.estimateBase(cl, false); 303 KeyValue kv = new KeyValue(); 304 actual = kv.heapSize(); 305 if (expected != actual) { 306 ClassSize.estimateBase(cl, true); 307 assertEquals(expected, actual); 308 } 309 310 // LruBlockCache Overhead 311 cl = LruBlockCache.class; 312 actual = LruBlockCache.CACHE_FIXED_OVERHEAD; 313 expected = ClassSize.estimateBase(cl, false); 314 if (expected != actual) { 315 ClassSize.estimateBase(cl, true); 316 assertEquals(expected, actual); 317 } 318 319 // CachedBlock Fixed Overhead 320 // We really need "deep" sizing but ClassSize does not do this. 321 // Perhaps we should do all these more in this style.... 322 cl = LruCachedBlock.class; 323 actual = LruCachedBlock.PER_BLOCK_OVERHEAD; 324 expected = ClassSize.estimateBase(cl, false); 325 expected += ClassSize.estimateBase(String.class, false); 326 expected += ClassSize.estimateBase(ByteBuffer.class, false); 327 if (expected != actual) { 328 ClassSize.estimateBase(cl, true); 329 ClassSize.estimateBase(String.class, true); 330 ClassSize.estimateBase(ByteBuffer.class, true); 331 assertEquals(expected, actual); 332 } 333 334 // DefaultMemStore Overhead 335 cl = DefaultMemStore.class; 336 actual = DefaultMemStore.FIXED_OVERHEAD; 337 expected = ClassSize.estimateBase(cl, false); 338 if (expected != actual) { 339 ClassSize.estimateBase(cl, true); 340 assertEquals(expected, actual); 341 } 342 343 // DefaultMemStore Deep Overhead 344 actual = DefaultMemStore.DEEP_OVERHEAD; 345 expected = ClassSize.estimateBase(cl, false); 346 if (expected != actual) { 347 ClassSize.estimateBase(cl, true); 348 assertEquals(expected, actual); 349 } 350 351 // CompactingMemStore Deep Overhead 352 cl = CompactingMemStore.class; 353 actual = CompactingMemStore.DEEP_OVERHEAD; 354 expected = ClassSize.estimateBase(cl, false); 355 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 356 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 357 expected += ClassSize.estimateBase(CompactionPipeline.class, false); 358 expected += ClassSize.estimateBase(LinkedList.class, false); // inside CompactionPipeline 359 expected += ClassSize.estimateBase(LinkedList.class, false); // inside CompactionPipeline 360 expected += ClassSize.estimateBase(MemStoreCompactor.class, false); 361 expected += ClassSize.estimateBase(AtomicBoolean.class, false);// inside MemStoreCompactor 362 if (expected != actual) { 363 ClassSize.estimateBase(cl, true); 364 ClassSize.estimateBase(AtomicBoolean.class, true); 365 ClassSize.estimateBase(AtomicBoolean.class, true); 366 ClassSize.estimateBase(CompactionPipeline.class, true); 367 ClassSize.estimateBase(LinkedList.class, true); 368 ClassSize.estimateBase(LinkedList.class, true); 369 ClassSize.estimateBase(MemStoreCompactor.class, true); 370 ClassSize.estimateBase(AtomicBoolean.class, true); 371 assertEquals(expected, actual); 372 } 373 374 // Segment Deep overhead 375 cl = Segment.class; 376 actual = Segment.DEEP_OVERHEAD; 377 expected = ClassSize.estimateBase(cl, false); 378 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 379 expected += ClassSize.estimateBase(AtomicReference.class, false); 380 expected += ClassSize.estimateBase(CellSet.class, false); 381 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 382 if (expected != actual) { 383 ClassSize.estimateBase(cl, true); 384 ClassSize.estimateBase(AtomicLong.class, true); 385 ClassSize.estimateBase(AtomicReference.class, true); 386 ClassSize.estimateBase(CellSet.class, true); 387 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 388 assertEquals(expected, actual); 389 } 390 391 // MutableSegment Deep overhead 392 cl = MutableSegment.class; 393 actual = MutableSegment.DEEP_OVERHEAD; 394 expected = ClassSize.estimateBase(cl, false); 395 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 396 expected += ClassSize.estimateBase(AtomicReference.class, false); 397 expected += ClassSize.estimateBase(CellSet.class, false); 398 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 399 expected += ClassSize.estimateBase(SyncTimeRangeTracker.class, false); 400 expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false); 401 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 402 if (expected != actual) { 403 ClassSize.estimateBase(cl, true); 404 ClassSize.estimateBase(AtomicLong.class, true); 405 ClassSize.estimateBase(AtomicLong.class, true); 406 ClassSize.estimateBase(AtomicReference.class, true); 407 ClassSize.estimateBase(CellSet.class, true); 408 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 409 ClassSize.estimateBase(SyncTimeRangeTracker.class, true); 410 ClassSize.estimateBase(ConcurrentSkipListMap.class, true); 411 ClassSize.estimateBase(AtomicBoolean.class, true); 412 assertEquals(expected, actual); 413 } 414 415 // ImmutableSegments Deep overhead 416 cl = ImmutableSegment.class; 417 actual = ImmutableSegment.DEEP_OVERHEAD; 418 expected = ClassSize.estimateBase(cl, false); 419 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 420 expected += ClassSize.estimateBase(AtomicReference.class, false); 421 expected += ClassSize.estimateBase(CellSet.class, false); 422 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 423 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 424 if (expected != actual) { 425 ClassSize.estimateBase(cl, true); 426 ClassSize.estimateBase(AtomicLong.class, true); 427 ClassSize.estimateBase(AtomicLong.class, true); 428 ClassSize.estimateBase(AtomicReference.class, true); 429 ClassSize.estimateBase(CellSet.class, true); 430 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 431 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 432 assertEquals(expected, actual); 433 } 434 435 cl = CSLMImmutableSegment.class; 436 actual = CSLMImmutableSegment.DEEP_OVERHEAD_CSLM; 437 expected = ClassSize.estimateBase(cl, false); 438 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 439 expected += ClassSize.estimateBase(AtomicReference.class, false); 440 expected += ClassSize.estimateBase(CellSet.class, false); 441 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 442 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 443 expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false); 444 if (expected != actual) { 445 ClassSize.estimateBase(cl, true); 446 ClassSize.estimateBase(AtomicLong.class, true); 447 ClassSize.estimateBase(AtomicLong.class, true); 448 ClassSize.estimateBase(AtomicReference.class, true); 449 ClassSize.estimateBase(CellSet.class, true); 450 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 451 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 452 ClassSize.estimateBase(ConcurrentSkipListMap.class, true); 453 assertEquals(expected, actual); 454 } 455 cl = CellArrayImmutableSegment.class; 456 actual = CellArrayImmutableSegment.DEEP_OVERHEAD_CAM; 457 expected = ClassSize.estimateBase(cl, false); 458 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 459 expected += ClassSize.estimateBase(AtomicReference.class, false); 460 expected += ClassSize.estimateBase(CellSet.class, false); 461 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 462 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 463 expected += ClassSize.estimateBase(CellArrayMap.class, false); 464 if (expected != actual) { 465 ClassSize.estimateBase(cl, true); 466 ClassSize.estimateBase(AtomicLong.class, true); 467 ClassSize.estimateBase(AtomicLong.class, true); 468 ClassSize.estimateBase(AtomicReference.class, true); 469 ClassSize.estimateBase(CellSet.class, true); 470 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 471 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 472 ClassSize.estimateBase(CellArrayMap.class, true); 473 assertEquals(expected, actual); 474 } 475 476 // Store Overhead 477 cl = HStore.class; 478 actual = HStore.FIXED_OVERHEAD; 479 expected = ClassSize.estimateBase(cl, false); 480 if (expected != actual) { 481 ClassSize.estimateBase(cl, true); 482 assertEquals(expected, actual); 483 } 484 485 // Region Overhead 486 cl = HRegion.class; 487 actual = HRegion.FIXED_OVERHEAD; 488 expected = ClassSize.estimateBase(cl, false); 489 if (expected != actual) { 490 ClassSize.estimateBase(cl, true); 491 assertEquals(expected, actual); 492 } 493 494 cl = StoreHotnessProtector.class; 495 actual = StoreHotnessProtector.FIXED_SIZE; 496 expected = ClassSize.estimateBase(cl, false); 497 if (expected != actual) { 498 ClassSize.estimateBase(cl, true); 499 assertEquals(expected, actual); 500 } 501 502 // Block cache key overhead. Only tests fixed overhead as estimating heap 503 // size of strings is hard. 504 cl = BlockCacheKey.class; 505 actual = BlockCacheKey.FIXED_OVERHEAD; 506 expected = ClassSize.estimateBase(cl, false); 507 if (expected != actual) { 508 ClassSize.estimateBase(cl, true); 509 assertEquals(expected, actual); 510 } 511 512 // Currently NOT testing Deep Overheads of many of these classes. 513 // Deep overheads cover a vast majority of stuff, but will not be 100% 514 // accurate because it's unclear when we're referencing stuff that's already 515 // accounted for. But we have satisfied our two core requirements. 516 // Sizing is quite accurate now, and our tests will throw errors if 517 // any of these classes are modified without updating overhead sizes. 518 } 519 520 @Test 521 public void testHFileBlockSize() throws IOException { 522 long expected; 523 long actual; 524 525 actual = HFileContext.FIXED_OVERHEAD; 526 expected = ClassSize.estimateBase(HFileContext.class, false); 527 assertEquals(expected, actual); 528 529 actual = HFileBlock.FIXED_OVERHEAD; 530 expected = ClassSize.estimateBase(HFileBlock.class, false); 531 assertEquals(expected, actual); 532 533 actual = ExclusiveMemHFileBlock.FIXED_OVERHEAD; 534 expected = ClassSize.estimateBase(ExclusiveMemHFileBlock.class, false); 535 assertEquals(expected, actual); 536 537 actual = SharedMemHFileBlock.FIXED_OVERHEAD; 538 expected = ClassSize.estimateBase(SharedMemHFileBlock.class, false); 539 assertEquals(expected, actual); 540 } 541 542 @Test 543 public void testMutations() { 544 Class<?> cl; 545 long expected; 546 long actual; 547 548 cl = TimeRange.class; 549 actual = ClassSize.TIMERANGE; 550 expected = ClassSize.estimateBase(cl, false); 551 if (expected != actual) { 552 ClassSize.estimateBase(cl, true); 553 assertEquals(expected, actual); 554 } 555 556 byte[] row = new byte[] { 0 }; 557 cl = Put.class; 558 actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY); 559 expected = ClassSize.estimateBase(cl, false); 560 // The actual TreeMap is not included in the above calculation 561 expected += ClassSize.align(ClassSize.TREEMAP); 562 expected += ClassSize.align(ClassSize.INTEGER); // priority 563 if (expected != actual) { 564 ClassSize.estimateBase(cl, true); 565 assertEquals(expected, actual); 566 } 567 568 cl = Delete.class; 569 actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY); 570 expected = ClassSize.estimateBase(cl, false); 571 // The actual TreeMap is not included in the above calculation 572 expected += ClassSize.align(ClassSize.TREEMAP); 573 expected += ClassSize.align(ClassSize.INTEGER); // priority 574 if (expected != actual) { 575 ClassSize.estimateBase(cl, true); 576 assertEquals(expected, actual); 577 } 578 } 579 580 @Test 581 public void testReferenceSize() { 582 LOG.info("ClassSize.REFERENCE is " + ClassSize.REFERENCE); 583 // oop should be either 4 or 8 584 assertTrue(ClassSize.REFERENCE == 4 || ClassSize.REFERENCE == 8); 585 } 586 587 @Test 588 public void testObjectSize() throws IOException { 589 LOG.info("header:" + ClassSize.OBJECT); 590 LOG.info("array header:" + ClassSize.ARRAY); 591 592 if (ClassSize.is32BitJVM()) { 593 assertEquals(ClassSize.OBJECT, 8); 594 } else { 595 assertTrue(ClassSize.OBJECT == 12 || ClassSize.OBJECT == 16); // depending on CompressedOops 596 } 597 if (ClassSize.useUnsafeLayout()) { 598 assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 4); 599 } else { 600 assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 8); 601 } 602 } 603 604 private long calcFixedOverhead(List<Class<?>> classList) { 605 long overhead = 0; 606 for (Class<?> clazz : classList) { 607 overhead += ClassSize.estimateBase(clazz, false); 608 } 609 return overhead; 610 } 611 612 @Test 613 public void testAutoCalcFixedOverhead() throws InterruptedException { 614 List<Class<?>> classList = Arrays.asList(HFileContext.class, HRegion.class, BlockCacheKey.class, 615 HFileBlock.class, HStore.class, LruBlockCache.class, StoreContext.class); 616 for (int i = 0; i < 10; i++) { 617 // warm up 618 calcFixedOverhead(classList); 619 } 620 long startNs = System.nanoTime(); 621 long overhead = 0; 622 for (int i = 0; i < 100; i++) { 623 overhead += calcFixedOverhead(classList); 624 } 625 long costNs = System.nanoTime() - startNs; 626 LOG.info("overhead = {}, cost {} ns", overhead, costNs); 627 // the single computation cost should be less than 5ms 628 assertThat(costNs, lessThan(TimeUnit.MILLISECONDS.toNanos(5) * classList.size() * 100)); 629 } 630}