1   /*
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.hadoop.hbase.regionserver.metrics;
21  
22  import static org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics.
23      BOOL_VALUES;
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.fail;
26  
27  import java.util.Collection;
28  import java.util.HashSet;
29  import java.util.Map;
30  import java.util.Random;
31  import java.util.Set;
32  
33  import org.apache.hadoop.hbase.HBaseTestingUtility;
34  import org.apache.hadoop.hbase.MediumTests;
35  import org.apache.hadoop.hbase.io.hfile.BlockType;
36  import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory;
37  import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics.
38      BlockMetricType;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.util.ClassSize;
41  import org.junit.Before;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  import org.junit.runner.RunWith;
45  import org.junit.runners.Parameterized;
46  import org.junit.runners.Parameterized.Parameters;
47  
48  @Category(MediumTests.class)
49  @RunWith(Parameterized.class)
50  public class TestSchemaMetrics {
51  
52    private final String TABLE_NAME = "myTable";
53    private final String CF_NAME = "myColumnFamily";
54  
55    private final boolean useTableName;
56    private Map<String, Long> startingMetrics;
57  
58    @Parameters
59    public static Collection<Object[]> parameters() {
60      return HBaseTestingUtility.BOOLEAN_PARAMETERIZED;
61    }
62  
63    public TestSchemaMetrics(boolean useTableName) {
64      this.useTableName = useTableName;
65      SchemaMetrics.setUseTableNameInTest(useTableName);
66    }
67  
68    @Before
69    public void setUp() {
70      startingMetrics = SchemaMetrics.getMetricsSnapshot();
71    };
72  
73    @Test
74    public void testNaming() {
75      final String metricPrefix = (useTableName ? "tbl." +
76          TABLE_NAME + "." : "") + "cf." + CF_NAME + ".";
77      SchemaMetrics schemaMetrics = SchemaMetrics.getInstance(TABLE_NAME,
78          CF_NAME);
79      SchemaMetrics ALL_CF_METRICS = SchemaMetrics.ALL_SCHEMA_METRICS;
80  
81      // fsReadTimeMetric
82      assertEquals(metricPrefix + "fsRead", schemaMetrics.getBlockMetricName(
83          BlockCategory.ALL_CATEGORIES, false, BlockMetricType.READ_TIME));
84  
85      // compactionReadTimeMetric
86      assertEquals(metricPrefix + "compactionRead",
87          schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, true,
88              BlockMetricType.READ_TIME));
89  
90      // fsBlockReadCntMetric
91      assertEquals(metricPrefix + "fsBlockReadCnt",
92          schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, false,
93              BlockMetricType.READ_COUNT));
94  
95      // fsBlockReadCacheHitCntMetric
96      assertEquals(metricPrefix + "fsBlockReadCacheHitCnt",
97          schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, false,
98              BlockMetricType.CACHE_HIT));
99  
100     // fsBlockReadCacheMissCntMetric
101     assertEquals(metricPrefix + "fsBlockReadCacheMissCnt",
102         schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, false,
103             BlockMetricType.CACHE_MISS));
104 
105     // compactionBlockReadCntMetric
106     assertEquals(metricPrefix + "compactionBlockReadCnt",
107         schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, true,
108             BlockMetricType.READ_COUNT));
109 
110     // compactionBlockReadCacheHitCntMetric
111     assertEquals(metricPrefix + "compactionBlockReadCacheHitCnt",
112         schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, true,
113             BlockMetricType.CACHE_HIT));
114 
115     // compactionBlockReadCacheMissCntMetric
116     assertEquals(metricPrefix + "compactionBlockReadCacheMissCnt",
117         schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, true,
118             BlockMetricType.CACHE_MISS));
119 
120     // fsMetaBlockReadCntMetric
121     assertEquals("fsMetaBlockReadCnt", ALL_CF_METRICS.getBlockMetricName(
122         BlockCategory.META, false, BlockMetricType.READ_COUNT));
123 
124     // fsMetaBlockReadCacheHitCntMetric
125     assertEquals("fsMetaBlockReadCacheHitCnt",
126         ALL_CF_METRICS.getBlockMetricName(BlockCategory.META, false,
127             BlockMetricType.CACHE_HIT));
128 
129     // fsMetaBlockReadCacheMissCntMetric
130     assertEquals("fsMetaBlockReadCacheMissCnt",
131         ALL_CF_METRICS.getBlockMetricName(BlockCategory.META, false,
132             BlockMetricType.CACHE_MISS));
133 
134     // Per-(column family, block type) statistics.
135     assertEquals(metricPrefix + "bt.Index.fsBlockReadCnt",
136         schemaMetrics.getBlockMetricName(BlockCategory.INDEX, false,
137             BlockMetricType.READ_COUNT));
138 
139     assertEquals(metricPrefix + "bt.Data.compactionBlockReadCacheHitCnt",
140         schemaMetrics.getBlockMetricName(BlockCategory.DATA, true,
141             BlockMetricType.CACHE_HIT));
142 
143     // A special case for Meta blocks
144     assertEquals(metricPrefix + "compactionMetaBlockReadCacheHitCnt",
145         schemaMetrics.getBlockMetricName(BlockCategory.META, true,
146             BlockMetricType.CACHE_HIT));
147 
148     // Cache metrics
149     assertEquals(metricPrefix + "blockCacheSize",
150         schemaMetrics.getBlockMetricName(BlockCategory.ALL_CATEGORIES, false,
151             BlockMetricType.CACHE_SIZE));
152 
153     assertEquals(metricPrefix + "bt.Index.blockCacheNumEvicted",
154         schemaMetrics.getBlockMetricName(BlockCategory.INDEX, false,
155             BlockMetricType.EVICTED));
156 
157     assertEquals("bt.Data.blockCacheNumCached",
158         ALL_CF_METRICS.getBlockMetricName(BlockCategory.DATA, false,
159             BlockMetricType.CACHED));
160 
161     assertEquals("blockCacheNumCached", ALL_CF_METRICS.getBlockMetricName(
162         BlockCategory.ALL_CATEGORIES, false, BlockMetricType.CACHED));
163 
164     // "Non-compaction aware" metrics
165     try {
166       ALL_CF_METRICS.getBlockMetricName(BlockCategory.ALL_CATEGORIES, true,
167           BlockMetricType.CACHE_SIZE);
168       fail("Exception expected");
169     } catch (IllegalArgumentException ex) {
170     }
171 
172     // Bloom metrics
173     assertEquals("keyMaybeInBloomCnt", ALL_CF_METRICS.getBloomMetricName(true));
174     assertEquals(metricPrefix + "keyNotInBloomCnt",
175         schemaMetrics.getBloomMetricName(false));
176 
177     schemaMetrics.printMetricNames();
178   }
179 
180   public void checkMetrics() {
181     SchemaMetrics.validateMetricChanges(startingMetrics);
182   }
183 
184   @Test
185   public void testIncrements() {
186     Random rand = new Random(23982737L);
187     for (int i = 1; i <= 3; ++i) {
188       final String tableName = "table" + i;
189       for (int j = 1; j <= 3; ++j) {
190         final String cfName = "cf" + j;
191         SchemaMetrics sm = SchemaMetrics.getInstance(tableName, cfName);
192         for (boolean isInBloom : BOOL_VALUES) {
193           sm.updateBloomMetrics(isInBloom);
194           checkMetrics();
195         }
196 
197         for (BlockCategory blockCat : BlockType.BlockCategory.values()) {
198           if (blockCat == BlockCategory.ALL_CATEGORIES) {
199             continue;
200           }
201 
202           for (boolean isCompaction : BOOL_VALUES) {
203             sm.updateOnCacheHit(blockCat, isCompaction);
204             checkMetrics();
205             sm.updateOnCacheMiss(blockCat, isCompaction, rand.nextInt());
206             checkMetrics();
207           }
208 
209           for (boolean isEviction : BOOL_VALUES) {
210             sm.updateOnCachePutOrEvict(blockCat, (isEviction ? -1 : 1)
211                 * rand.nextInt(1024 * 1024), isEviction);
212           }
213         }
214       }
215     }
216   }
217 
218   @Test
219   public void testGenerateSchemaMetricsPrefix() {
220     String tableName = "table1";
221     int numCF = 3;
222 
223     StringBuilder expected = new StringBuilder();
224     if (useTableName) {
225       expected.append("tbl.");
226       expected.append(tableName);
227       expected.append(".");
228     }
229     expected.append("cf.");
230     Set<byte[]> families = new HashSet<byte[]>();
231     for (int i = 1; i <= numCF; i++) {
232       String cf = "cf" + i;
233       families.add(Bytes.toBytes(cf));
234       expected.append(cf);
235       if (i == numCF) {
236         expected.append(".");
237       } else {
238         expected.append("~");
239       }
240     }
241 
242     String result = SchemaMetrics.generateSchemaMetricsPrefix(tableName,
243         families);
244     assertEquals(expected.toString(), result);
245   }
246 
247 
248   @org.junit.Rule
249   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
250     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
251 }
252