From 100030cd51e16ade02a770703c4fd4ac5cc239cf Mon Sep 17 00:00:00 2001 From: mbautin Date: Thu, 27 Oct 2011 14:33:50 -0700 Subject: [PATCH] HBASE-4686 [jira] [89-fb] Fix per-store metrics aggregation Summary: HBASE-4686 Store metrics fix and TestRegionServerMetrics In r1182034 per-Store metrics were broken, because the aggregation of StoreFile metrics over all stores in a region was replaced by overriding them every time. We saw these metrics drop by a factor of numRegions on a production cluster – thanks to Kannan for noticing this! We need to fix the metrics and add a unit test to ensure regressions like this don't happen in the future. Test Plan: EMPTY Reviewers: JIRA --- .../apache/hadoop/hbase/regionserver/HRegion.java | 2 - .../hadoop/hbase/regionserver/HRegionServer.java | 116 +++++++++----------- .../hbase/regionserver/metrics/SchemaMetrics.java | 100 ++++++++++++----- .../apache/hadoop/hbase/HBaseTestingUtility.java | 95 +++++++++++++++- .../regionserver/TestRegionServerMetrics.java | 120 ++++++++++++++++++++ .../regionserver/metrics/TestSchemaMetrics.java | 7 +- 6 files changed, 335 insertions(+), 105 deletions(-) create mode 100644 src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerMetrics.java diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index 6c821c0..d2f0c40 100644 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -183,8 +183,6 @@ public class HRegion implements HeapSize { // , Writable{ final Path regiondir; KeyValue.KVComparator comparator; - private Pair lastCompactInfo = null; - /* * Data structure of write state flags used coordinating flushes, * compactions and closes. diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 4a4436f..9a2531b 100755 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -105,7 +105,6 @@ import org.apache.hadoop.hbase.ipc.HRegionInterface; import org.apache.hadoop.hbase.regionserver.metrics.RegionServerDynamicMetrics; import org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics; import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics; -import org.apache.hadoop.hbase.regionserver.metrics.SchemaConfigured; import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics.StoreMetricType; import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.replication.regionserver.Replication; @@ -126,7 +125,6 @@ import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; /** * HRegionServer makes a set of HRegions available to clients. It checks in with @@ -221,6 +219,8 @@ public class HRegionServer implements HRegionInterface, private final LinkedList reservedSpace = new LinkedList(); private RegionServerMetrics metrics; + + @SuppressWarnings("unused") private RegionServerDynamicMetrics dynamicMetrics; // Compactions @@ -260,6 +260,7 @@ public class HRegionServer implements HRegionInterface, private final HServerAddress address; // The main region server thread. + @SuppressWarnings("unused") private Thread regionServerThread; private final String machineName; @@ -405,7 +406,6 @@ public class HRegionServer implements HRegionInterface, @Override public void process(WatchedEvent event) { EventType type = event.getType(); - KeeperState state = event.getState(); // Ignore events if we're shutting down. if (this.stopRequested.get()) { @@ -1048,24 +1048,6 @@ public class HRegionServer implements HRegionInterface, } } - /** - * Help function for metrics() that increments a map value if it exists. - * - * @param map - * The map to work with - * @param key - * the string key - * @param val - * the value to add or set the map key to - */ - protected void incrMap(Map map, String key, double val) { - if (map.get(key) != null) { - map.get(key).add(val); - } else { - map.put(key, new MutableDouble(val)); - } - } - protected void metrics() { this.metrics.regions.set(this.onlineRegions.size()); this.metrics.incrementRequests(this.requestCount.get()); @@ -1079,19 +1061,13 @@ public class HRegionServer implements HRegionInterface, long totalStaticIndexSize = 0; long totalStaticBloomSize = 0; - long tmpfiles; - long tmpindex; - long tmpfilesize; - long tmpbloomsize; - long tmpstaticsize; - SchemaMetrics schemaMetrics; - // Note that this is a map of Doubles instead of Longs. This is because we // do effective integer division, which would perhaps truncate more than it // should because we do it only on one part of our sum at a time. Rather // than dividing at the end, where it is difficult to know the proper // factor, everything is exact then truncated. - Map tempVals = new HashMap(); + final Map tempVals = + new HashMap(); synchronized (this.onlineRegions) { for (Map.Entry e: this.onlineRegions.entrySet()) { @@ -1100,48 +1076,60 @@ public class HRegionServer implements HRegionInterface, synchronized (r.stores) { stores += r.stores.size(); for(Map.Entry ee: r.stores.entrySet()) { - Store store = ee.getValue(); - tmpfiles = store.getStorefilesCount(); - tmpindex = store.getStorefilesIndexSize(); - tmpfilesize = store.getStorefilesSize(); - tmpbloomsize = store.getTotalStaticBloomSize(); - tmpstaticsize = store.getTotalStaticIndexSize(); - - schemaMetrics = store.getSchemaMetrics(); - schemaMetrics.updateStoreMetric( - StoreMetricType.STORE_FILE_COUNT, - tmpfiles); - - schemaMetrics.updateStoreMetric( - StoreMetricType.STORE_FILE_INDEX_SIZE, - (long) (tmpindex / (1024.0 * 1024))); - - schemaMetrics.updateStoreMetric( - StoreMetricType.STORE_FILE_SIZE_MB, - (long) (tmpfilesize / (1024.0 * 1024))); - - schemaMetrics.updateStoreMetric( - StoreMetricType.STATIC_BLOOM_SIZE_KB, - (long)(tmpbloomsize / 1024.0)); - - schemaMetrics.updateStoreMetric(StoreMetricType.MEMSTORE_SIZE_MB, - (long)(store.getMemStoreSize() / (1024.0 * 1024))); - - schemaMetrics.updateStoreMetric( - StoreMetricType.STATIC_INDEX_SIZE_KB, - (long)(tmpstaticsize / 1024.0)); - - storefiles += tmpfiles; - storefileIndexSize += tmpindex; - totalStaticIndexSize += tmpstaticsize; - totalStaticBloomSize += tmpbloomsize; + final Store store = ee.getValue(); + final SchemaMetrics schemaMetrics = store.getSchemaMetrics(); + + { + long tmpStorefiles = store.getStorefilesCount(); + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.STORE_FILE_COUNT, tmpStorefiles); + storefiles += tmpStorefiles; + } + + + { + long tmpStorefileIndexSize = store.getStorefilesIndexSize(); + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.STORE_FILE_INDEX_SIZE, + (long) (tmpStorefileIndexSize / (1024.0 * 1024))); + storefileIndexSize += tmpStorefileIndexSize; + } + + { + long tmpStorefilesSize = store.getStorefilesSize(); + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.STORE_FILE_SIZE_MB, + (long) (tmpStorefilesSize / (1024.0 * 1024))); + } + + { + long tmpStaticBloomSize = store.getTotalStaticBloomSize(); + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.STATIC_BLOOM_SIZE_KB, + (long) (tmpStaticBloomSize / 1024.0)); + totalStaticBloomSize += tmpStaticBloomSize; + } + + { + long tmpStaticIndexSize = store.getTotalStaticIndexSize(); + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.STATIC_INDEX_SIZE_KB, + (long) (tmpStaticIndexSize / 1024.0)); + totalStaticIndexSize += tmpStaticIndexSize; + } + + schemaMetrics.incrStoreMetricMap(tempVals, + StoreMetricType.MEMSTORE_SIZE_MB, + (long) (store.getMemStoreSize() / (1024.0 * 1024))); } } } } + for (Entry e : tempVals.entrySet()) { HRegion.setNumericMetric(e.getKey(), e.getValue().longValue()); } + this.metrics.stores.set(stores); this.metrics.storefiles.set(storefiles); this.metrics.memstoreSizeMB.set((int)(memstoreSize/(1024*1024))); diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/SchemaMetrics.java b/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/SchemaMetrics.java index 8776ffe..0be98e6 100644 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/SchemaMetrics.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/SchemaMetrics.java @@ -32,11 +32,14 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang.mutable.MutableDouble; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; /** @@ -94,11 +97,11 @@ public class SchemaMetrics { private static final Log LOG = LogFactory.getLog(SchemaMetrics.class); public static enum BlockMetricType { - // Metric configuration: compactionAware | timeVarying - READ_TIME("Read", true, true), - READ_COUNT("BlockReadCnt", true, false), - CACHE_HIT("BlockReadCacheHitCnt", true, false), - CACHE_MISS("BlockReadCacheMissCnt", true, false), + // Metric configuration: compactionAware, timeVarying + READ_TIME("Read", true, true), + READ_COUNT("BlockReadCnt", true, false), + CACHE_HIT("BlockReadCacheHitCnt", true, false), + CACHE_MISS("BlockReadCacheMissCnt", true, false), CACHE_SIZE("blockCacheSize", false, false), CACHED("blockCacheNumCached", false, false), @@ -376,13 +379,28 @@ public class SchemaMetrics { } /** - * Update the store metric to a certain value. - * @param storeMetricType the store metric to update - * @param value the value to update the metric to + * Increment store metrics in a temporary map. Useful when aggregating across + * multiple regions and column families in a region server. + * @param map the map to work with + * @param storeMetricType the store metric type to increment + * @param val the value to add to the metric */ - public void updateStoreMetric(StoreMetricType storeMetricType, long value) { - HRegion.setNumericMetric(storeMetricNames[storeMetricType.ordinal()], - value); + public void incrStoreMetricMap(final Map map, + StoreMetricType storeMetricType, double val) { + final String key = getStoreMetricName(storeMetricType); + if (map.get(key) != null) { + map.get(key).add(val); + } else { + map.put(key, new MutableDouble(val)); + } + + if (this != ALL_SCHEMA_METRICS) { + ALL_SCHEMA_METRICS.incrStoreMetricMap(map, storeMetricType, val); + } + } + + public String getStoreMetricName(StoreMetricType storeMetricType) { + return storeMetricNames[storeMetricType.ordinal()]; } /** @@ -504,17 +522,33 @@ public class SchemaMetrics { // Methods used in testing - private static final String WORD_AND_DOT_RE_STR = "[^.]+\\."; + private static final String regexEscape(String s) { + return s.replace(".", "\\."); + } + + /** + * Assume that table names used in tests don't contain dots, except for the + * META table. + */ + private static final String WORD_AND_DOT_RE_STR = "([^.]+|" + + regexEscape(Bytes.toString(HConstants.META_TABLE_NAME)) + + ")\\."; + + /** "tab.." */ private static final String TABLE_NAME_RE_STR = - "\\b" + TABLE_PREFIX.replace(".", "\\.") + WORD_AND_DOT_RE_STR; + "\\b" + regexEscape(TABLE_PREFIX) + WORD_AND_DOT_RE_STR; + + /** "cf.." */ private static final String CF_NAME_RE_STR = - "\\b" + CF_PREFIX.replace(".", "\\.") + WORD_AND_DOT_RE_STR; - private static final Pattern CF_NAME_RE = Pattern.compile( - CF_NAME_RE_STR); + "\\b" + regexEscape(CF_PREFIX) + WORD_AND_DOT_RE_STR; + private static final Pattern CF_NAME_RE = Pattern.compile(CF_NAME_RE_STR); + + /** "tab..cf.." */ private static final Pattern TABLE_AND_CF_NAME_RE = Pattern.compile( TABLE_NAME_RE_STR + CF_NAME_RE_STR); + private static final Pattern BLOCK_CATEGORY_RE = Pattern.compile( - "\\b" + BLOCK_TYPE_PREFIX.replace(".", "\\.") + "[^.]+\\." + + "\\b" + regexEscape(BLOCK_TYPE_PREFIX) + "[^.]+\\." + // Also remove the special-case block type marker for meta blocks "|" + META_BLOCK_CATEGORY_STR + "(?=" + BlockMetricType.BLOCK_METRIC_TYPE_RE + ")"); @@ -539,7 +573,7 @@ public class SchemaMetrics { for (boolean isCompaction : BOOL_VALUES) { for (BlockMetricType metricType : BlockMetricType.values()) { int i = getBlockMetricIndex(blockCategory, isCompaction, metricType); - System.err.println("blockCategory=" + blockCategory + ", " + LOG.debug("blockCategory=" + blockCategory + ", " + "metricType=" + metricType + ", isCompaction=" + isCompaction + ", metricName=" + blockMetricNames[i]); } @@ -642,24 +676,30 @@ public class SchemaMetrics { final long oldValue = getLong(oldMetrics, metricName); final long newValue = getLong(newMetrics, metricName); final long delta = newValue - oldValue; - if (oldValue != newValue) { - // Debug output for the unit test - System.err.println("Metric=" + metricName + ", delta=" + delta); - } - if (cfm != ALL_SCHEMA_METRICS) { - // Re-calculate values of metrics with no column family (or CF/table) - // specified based on all metrics with CF (or CF/table) specified. - final String aggregateMetricName = - cfTableMetricRE.matcher(metricName).replaceAll(""); - putLong(allCfDeltas, aggregateMetricName, - getLong(allCfDeltas, aggregateMetricName) + delta); + // Re-calculate values of metrics with no column family (or CF/table) + // specified based on all metrics with CF (or CF/table) specified. + if (delta != 0) { + if (cfm != ALL_SCHEMA_METRICS) { + final String aggregateMetricName = + cfTableMetricRE.matcher(metricName).replaceAll(""); + if (!aggregateMetricName.equals(metricName)) { + LOG.debug("Counting " + delta + " units of " + metricName + + " towards " + aggregateMetricName); + + putLong(allCfDeltas, aggregateMetricName, + getLong(allCfDeltas, aggregateMetricName) + delta); + } + } else { + LOG.debug("Metric=" + metricName + ", delta=" + delta); + } } Matcher matcher = BLOCK_CATEGORY_RE.matcher(metricName); if (matcher.find()) { // Only process per-block-category metrics String metricNoBlockCategory = matcher.replaceAll(""); + putLong(allBlockCategoryDeltas, metricNoBlockCategory, getLong(allBlockCategoryDeltas, metricNoBlockCategory) + delta); } @@ -674,7 +714,7 @@ public class SchemaMetrics { if (errors.length() > 0) errors.append("\n"); errors.append("The all-CF metric " + key + " changed by " - + actual + " but the aggregation of per-column-family metrics " + + actual + " but the aggregation of per-CF/table metrics " + "yields " + expected); } } diff --git a/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java b/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java index 7fd8977..27b891b 100644 --- a/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java +++ b/src/test/java/org/apache/hadoop/hbase/HBaseTestingUtility.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.NavigableSet; +import java.util.Random; import java.util.UUID; import org.apache.commons.logging.Log; @@ -63,14 +64,14 @@ import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.Threads; import org.apache.hadoop.hbase.util.Writables; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper; +import org.apache.hadoop.hdfs.DFSClient; +import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.hdfs.server.namenode.NameNode; import org.apache.hadoop.mapred.MiniMRCluster; -import org.apache.zookeeper.ZooKeeper; -import org.apache.hadoop.hdfs.DFSClient; import org.apache.hadoop.security.UnixUserGroupInformation; import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.hdfs.server.namenode.NameNode; -import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.zookeeper.ZooKeeper; import com.google.common.base.Preconditions; @@ -111,6 +112,13 @@ public class HBaseTestingUtility { { Compression.Algorithm.GZ } }); + /** This is for unit tests parameterized with a single boolean. */ + public static final List BOOLEAN_PARAMETERIZED = + Arrays.asList(new Object[][] { + { new Boolean(false) }, + { new Boolean(true) } + }); + /** Compression algorithms to use in testing */ public static final Compression.Algorithm[] COMPRESSION_ALGORITHMS = new Compression.Algorithm[] { @@ -407,6 +415,7 @@ public class HBaseTestingUtility { } } LOG.info("Minicluster is down"); + clusterTestBuildDir = null; } /** @@ -1136,4 +1145,82 @@ public class HBaseTestingUtility { } } + /** Creates a random table with the given parameters */ + public HTable createRandomTable(String tableName, + final Collection families, + final int maxVersions, + final int numColsPerRow, + final int numFlushes, + final int numRegions, + final int numRowsPerFlush) + throws IOException, InterruptedException { + + LOG.info("\n\nCreating random table " + tableName + " with " + numRegions + + " regions, " + numFlushes + " storefiles per region, " + + numRowsPerFlush + " rows per flush, maxVersions=" + maxVersions + + "\n"); + + final Random rand = new Random(tableName.hashCode() * 17L + 12938197137L); + final int numCF = families.size(); + final byte[][] cfBytes = new byte[numCF][]; + final byte[] tableNameBytes = Bytes.toBytes(tableName); + + { + int cfIndex = 0; + for (String cf : families) { + cfBytes[cfIndex++] = Bytes.toBytes(cf); + } + } + + final int actualStartKey = 0; + final int actualEndKey = Integer.MAX_VALUE; + final int keysPerRegion = (actualEndKey - actualStartKey) / numRegions; + final int splitStartKey = actualStartKey + keysPerRegion; + final int splitEndKey = actualEndKey - keysPerRegion; + final String keyFormat = "%08x"; + final HTable table = createTable(tableNameBytes, cfBytes, + maxVersions, + Bytes.toBytes(String.format(keyFormat, splitStartKey)), + Bytes.toBytes(String.format(keyFormat, splitEndKey)), + numRegions); + hbaseCluster.flushcache(HConstants.META_TABLE_NAME); + + for (int iFlush = 0; iFlush < numFlushes; ++iFlush) { + for (int iRow = 0; iRow < numRowsPerFlush; ++iRow) { + final byte[] row = Bytes.toBytes(String.format(keyFormat, + actualStartKey + rand.nextInt(actualEndKey - actualStartKey))); + + Put put = new Put(row); + Delete del = new Delete(row); + for (int iCol = 0; iCol < numColsPerRow; ++iCol) { + final byte[] cf = cfBytes[rand.nextInt(numCF)]; + final long ts = rand.nextInt(); + final byte[] qual = Bytes.toBytes("col" + iCol); + if (rand.nextBoolean()) { + final byte[] value = Bytes.toBytes("value_for_row_" + iRow + + "_cf_" + Bytes.toStringBinary(cf) + "_col_" + iCol + "_ts_" + + ts + "_random_" + rand.nextLong()); + put.add(cf, qual, ts, value); + } else if (rand.nextDouble() < 0.8) { + del.deleteColumn(cf, qual, ts); + } else { + del.deleteColumns(cf, qual, ts); + } + } + + if (!put.isEmpty()) { + table.put(put); + } + + if (!del.isEmpty()) { + table.delete(del); + } + } + LOG.info("Initiating flush #" + iFlush + " for table " + tableName); + table.flushCommits(); + hbaseCluster.flushcache(tableNameBytes); + } + + return table; + } } diff --git a/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerMetrics.java b/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerMetrics.java new file mode 100644 index 0000000..eb2817c --- /dev/null +++ b/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerMetrics.java @@ -0,0 +1,120 @@ +/* + * Copyright 2011 The Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package org.apache.hadoop.hbase.regionserver; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics; +import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics. + StoreMetricType; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test metrics incremented on region server operations. + */ +public class TestRegionServerMetrics { + + private static final Log LOG = + LogFactory.getLog(TestRegionServerMetrics.class.getName()); + + private final static String TABLE_NAME = + TestRegionServerMetrics.class.getSimpleName() + "Table"; + private String[] FAMILIES = new String[] { "cf1", "cf2", "anotherCF" }; + private static final int MAX_VERSIONS = 1; + private static final int NUM_COLS_PER_ROW = 15; + private static final int NUM_FLUSHES = 3; + private static final int NUM_REGIONS = 4; + + private static final SchemaMetrics ALL_METRICS = + SchemaMetrics.ALL_SCHEMA_METRICS; + + private static final HBaseTestingUtility TEST_UTIL = + new HBaseTestingUtility(); + + private Map startingMetrics; + + private final int META_AND_ROOT = 2; + + @Before + public void setUp() throws Exception { + SchemaMetrics.setUseTableNameInTest(true); + startingMetrics = SchemaMetrics.getMetricsSnapshot(); + TEST_UTIL.startMiniCluster(); + } + + @After + public void tearDown() throws IOException { + TEST_UTIL.shutdownMiniCluster(); + SchemaMetrics.validateMetricChanges(startingMetrics); + } + + private void assertStoreMetricEquals(long expected, + SchemaMetrics schemaMetrics, StoreMetricType storeMetricType) { + final String storeMetricName = + schemaMetrics.getStoreMetricName(storeMetricType); + Long startValue = startingMetrics.get(storeMetricName); + assertEquals("Invalid value for store metric " + storeMetricName + + " (type " + storeMetricType + ")", expected, + HRegion.getNumericMetric(storeMetricName) + - (startValue != null ? startValue : 0)); + } + + @Test + public void testMultipleRegions() throws IOException, InterruptedException { + + TEST_UTIL.createRandomTable( + TABLE_NAME, + Arrays.asList(FAMILIES), + MAX_VERSIONS, NUM_COLS_PER_ROW, NUM_FLUSHES, NUM_REGIONS, 1000); + + final HRegionServer rs = + TEST_UTIL.getMiniHBaseCluster().getRegionServer(0); + + assertEquals(NUM_REGIONS + META_AND_ROOT, rs.getOnlineRegions().size()); + + rs.doMetrics(); + for (HRegion r : rs.getOnlineRegions()) { + for (Map.Entry storeEntry : r.getStores().entrySet()) { + LOG.info("For region " + r.getRegionNameAsString() + ", CF " + + Bytes.toStringBinary(storeEntry.getKey()) + " found store files " + + ": " + storeEntry.getValue().getStorefiles()); + } + } + + assertStoreMetricEquals(NUM_FLUSHES * NUM_REGIONS * FAMILIES.length + + META_AND_ROOT, ALL_METRICS, StoreMetricType.STORE_FILE_COUNT); + + for (String cf : FAMILIES) { + SchemaMetrics schemaMetrics = SchemaMetrics.getInstance(TABLE_NAME, cf); + assertStoreMetricEquals(NUM_FLUSHES * NUM_REGIONS, + schemaMetrics, StoreMetricType.STORE_FILE_COUNT); + } + } + +} diff --git a/src/test/java/org/apache/hadoop/hbase/regionserver/metrics/TestSchemaMetrics.java b/src/test/java/org/apache/hadoop/hbase/regionserver/metrics/TestSchemaMetrics.java index c03532a..beaa354 100644 --- a/src/test/java/org/apache/hadoop/hbase/regionserver/metrics/TestSchemaMetrics.java +++ b/src/test/java/org/apache/hadoop/hbase/regionserver/metrics/TestSchemaMetrics.java @@ -20,12 +20,12 @@ package org.apache.hadoop.hbase.regionserver.metrics; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Random; +import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.io.hfile.BlockType; import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory; import org.apache.hadoop.hbase.regionserver.metrics.SchemaMetrics; @@ -55,10 +55,7 @@ public class TestSchemaMetrics { @Parameters public static Collection parameters() { - List params = new ArrayList(); - params.add(new Object[] { new Boolean(false) }); - params.add(new Object[] { new Boolean(true) }); - return params; + return HBaseTestingUtility.BOOLEAN_PARAMETERIZED; } public TestSchemaMetrics(boolean useTableName) { -- 1.7.4.4