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