HBASE-24033 Add ut for loading the corrupt recovered hfiles (#1322)
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / TestClientClusterMetrics.java
blobdd3bc73b411a9f81627d716667ccdeec95a144e5
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase;
20 import java.io.IOException;
21 import java.security.PrivilegedAction;
22 import java.util.EnumSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.concurrent.CompletableFuture;
27 import java.util.concurrent.atomic.AtomicInteger;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.ClusterMetrics.Option;
31 import org.apache.hadoop.hbase.Waiter.Predicate;
32 import org.apache.hadoop.hbase.client.Admin;
33 import org.apache.hadoop.hbase.client.AsyncAdmin;
34 import org.apache.hadoop.hbase.client.AsyncConnection;
35 import org.apache.hadoop.hbase.client.ClusterConnectionFactory;
36 import org.apache.hadoop.hbase.client.Connection;
37 import org.apache.hadoop.hbase.client.ConnectionFactory;
38 import org.apache.hadoop.hbase.client.Get;
39 import org.apache.hadoop.hbase.client.Put;
40 import org.apache.hadoop.hbase.client.RegionInfoBuilder;
41 import org.apache.hadoop.hbase.client.RegionStatesCount;
42 import org.apache.hadoop.hbase.client.Result;
43 import org.apache.hadoop.hbase.client.Scan;
44 import org.apache.hadoop.hbase.client.Table;
45 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
46 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
47 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
48 import org.apache.hadoop.hbase.coprocessor.MasterObserver;
49 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
50 import org.apache.hadoop.hbase.filter.FilterAllFilter;
51 import org.apache.hadoop.hbase.master.HMaster;
52 import org.apache.hadoop.hbase.regionserver.HRegionServer;
53 import org.apache.hadoop.hbase.security.User;
54 import org.apache.hadoop.hbase.security.UserProvider;
55 import org.apache.hadoop.hbase.testclassification.MediumTests;
56 import org.apache.hadoop.hbase.util.Bytes;
57 import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
58 import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
59 import org.junit.AfterClass;
60 import org.junit.Assert;
61 import org.junit.BeforeClass;
62 import org.junit.ClassRule;
63 import org.junit.Test;
64 import org.junit.experimental.categories.Category;
66 @Category(MediumTests.class)
67 public class TestClientClusterMetrics {
69 @ClassRule
70 public static final HBaseClassTestRule CLASS_RULE =
71 HBaseClassTestRule.forClass(TestClientClusterMetrics.class);
73 private static HBaseTestingUtility UTIL;
74 private static Admin ADMIN;
75 private final static int SLAVES = 5;
76 private final static int MASTERS = 3;
77 private static MiniHBaseCluster CLUSTER;
78 private static HRegionServer DEAD;
79 private static final TableName TABLE_NAME = TableName.valueOf("test");
80 private static final byte[] CF = Bytes.toBytes("cf");
83 @BeforeClass
84 public static void setUpBeforeClass() throws Exception {
85 Configuration conf = HBaseConfiguration.create();
86 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, MyObserver.class.getName());
87 UTIL = new HBaseTestingUtility(conf);
88 StartMiniClusterOption option = StartMiniClusterOption.builder()
89 .numMasters(MASTERS).numRegionServers(SLAVES).numDataNodes(SLAVES).build();
90 UTIL.startMiniCluster(option);
91 CLUSTER = UTIL.getHBaseCluster();
92 CLUSTER.waitForActiveAndReadyMaster();
93 ADMIN = UTIL.getAdmin();
94 // Kill one region server
95 List<RegionServerThread> rsts = CLUSTER.getLiveRegionServerThreads();
96 RegionServerThread rst = rsts.get(rsts.size() - 1);
97 DEAD = rst.getRegionServer();
98 DEAD.stop("Test dead servers metrics");
99 while (rst.isAlive()) {
100 Thread.sleep(500);
104 @Test
105 public void testDefaults() throws Exception {
106 ClusterMetrics origin = ADMIN.getClusterMetrics();
107 ClusterMetrics defaults = ADMIN.getClusterMetrics(EnumSet.allOf(Option.class));
108 Assert.assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
109 Assert.assertEquals(origin.getClusterId(), defaults.getClusterId());
110 Assert.assertEquals(origin.getAverageLoad(), defaults.getAverageLoad(), 0);
111 Assert.assertEquals(origin.getBackupMasterNames().size(),
112 defaults.getBackupMasterNames().size());
113 Assert.assertEquals(origin.getDeadServerNames().size(), defaults.getDeadServerNames().size());
114 Assert.assertEquals(origin.getRegionCount(), defaults.getRegionCount());
115 Assert.assertEquals(origin.getLiveServerMetrics().size(),
116 defaults.getLiveServerMetrics().size());
117 Assert.assertEquals(origin.getMasterInfoPort(), defaults.getMasterInfoPort());
118 Assert.assertEquals(origin.getServersName().size(), defaults.getServersName().size());
119 Assert.assertEquals(ADMIN.getRegionServers().size(), defaults.getServersName().size());
122 @Test
123 public void testAsyncClient() throws Exception {
124 try (AsyncConnection asyncConnect = ConnectionFactory.createAsyncConnection(
125 UTIL.getConfiguration()).get()) {
126 AsyncAdmin asyncAdmin = asyncConnect.getAdmin();
127 CompletableFuture<ClusterMetrics> originFuture =
128 asyncAdmin.getClusterMetrics();
129 CompletableFuture<ClusterMetrics> defaultsFuture =
130 asyncAdmin.getClusterMetrics(EnumSet.allOf(Option.class));
131 ClusterMetrics origin = originFuture.get();
132 ClusterMetrics defaults = defaultsFuture.get();
133 Assert.assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
134 Assert.assertEquals(origin.getClusterId(), defaults.getClusterId());
135 Assert.assertEquals(origin.getHBaseVersion(), defaults.getHBaseVersion());
136 Assert.assertEquals(origin.getClusterId(), defaults.getClusterId());
137 Assert.assertEquals(origin.getAverageLoad(), defaults.getAverageLoad(), 0);
138 Assert.assertEquals(origin.getBackupMasterNames().size(),
139 defaults.getBackupMasterNames().size());
140 Assert.assertEquals(origin.getDeadServerNames().size(), defaults.getDeadServerNames().size());
141 Assert.assertEquals(origin.getRegionCount(), defaults.getRegionCount());
142 Assert.assertEquals(origin.getLiveServerMetrics().size(),
143 defaults.getLiveServerMetrics().size());
144 Assert.assertEquals(origin.getMasterInfoPort(), defaults.getMasterInfoPort());
145 Assert.assertEquals(origin.getServersName().size(), defaults.getServersName().size());
146 origin.getTableRegionStatesCount().forEach(((tableName, regionStatesCount) -> {
147 RegionStatesCount defaultRegionStatesCount = defaults.getTableRegionStatesCount()
148 .get(tableName);
149 Assert.assertEquals(defaultRegionStatesCount, regionStatesCount);
150 }));
154 @Test
155 public void testLiveAndDeadServersStatus() throws Exception {
156 // Count the number of live regionservers
157 List<RegionServerThread> regionserverThreads = CLUSTER.getLiveRegionServerThreads();
158 int numRs = 0;
159 int len = regionserverThreads.size();
160 for (int i = 0; i < len; i++) {
161 if (regionserverThreads.get(i).isAlive()) {
162 numRs++;
165 // Depending on the (random) order of unit execution we may run this unit before the
166 // minicluster is fully up and recovered from the RS shutdown done during test init.
167 Waiter.waitFor(CLUSTER.getConfiguration(), 10 * 1000, 100, new Predicate<Exception>() {
168 @Override
169 public boolean evaluate() throws Exception {
170 ClusterMetrics metrics = ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS));
171 Assert.assertNotNull(metrics);
172 return metrics.getRegionCount() > 0;
175 // Retrieve live servers and dead servers info.
176 EnumSet<Option> options =
177 EnumSet.of(Option.LIVE_SERVERS, Option.DEAD_SERVERS, Option.SERVERS_NAME);
178 ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
179 Assert.assertNotNull(metrics);
180 // exclude a dead region server
181 Assert.assertEquals(SLAVES -1, numRs);
182 // live servers = nums of regionservers
183 // By default, HMaster don't carry any regions so it won't report its load.
184 // Hence, it won't be in the server list.
185 Assert.assertEquals(numRs, metrics.getLiveServerMetrics().size());
186 Assert.assertTrue(metrics.getRegionCount() > 0);
187 Assert.assertNotNull(metrics.getDeadServerNames());
188 Assert.assertEquals(1, metrics.getDeadServerNames().size());
189 ServerName deadServerName = metrics.getDeadServerNames().iterator().next();
190 Assert.assertEquals(DEAD.getServerName(), deadServerName);
191 Assert.assertNotNull(metrics.getServersName());
192 Assert.assertEquals(numRs, metrics.getServersName().size());
195 @Test
196 public void testRegionStatesCount() throws Exception {
197 Table table = UTIL.createTable(TABLE_NAME, CF);
198 table.put(new Put(Bytes.toBytes("k1"))
199 .addColumn(CF, Bytes.toBytes("q1"), Bytes.toBytes("v1")));
200 table.put(new Put(Bytes.toBytes("k2"))
201 .addColumn(CF, Bytes.toBytes("q2"), Bytes.toBytes("v2")));
202 table.put(new Put(Bytes.toBytes("k3"))
203 .addColumn(CF, Bytes.toBytes("q3"), Bytes.toBytes("v3")));
205 ClusterMetrics metrics = ADMIN.getClusterMetrics();
206 Assert.assertEquals(metrics.getTableRegionStatesCount().size(), 2);
207 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
208 .getRegionsInTransition(), 0);
209 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
210 .getOpenRegions(), 1);
211 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
212 .getTotalRegions(), 1);
213 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
214 .getClosedRegions(), 0);
215 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
216 .getSplitRegions(), 0);
217 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
218 .getRegionsInTransition(), 0);
219 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
220 .getOpenRegions(), 1);
221 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
222 .getTotalRegions(), 1);
224 UTIL.deleteTable(TABLE_NAME);
227 @Test
228 public void testRegionStatesWithSplit() throws Exception {
229 int startRowNum = 20;
230 int rowCount = 80;
231 Table table = UTIL.createTable(TABLE_NAME, CF);
232 table.put(new Put(Bytes.toBytes("k1"))
233 .addColumn(CF, Bytes.toBytes("q1"), Bytes.toBytes("v1")));
234 table.put(new Put(Bytes.toBytes("k2"))
235 .addColumn(CF, Bytes.toBytes("q2"), Bytes.toBytes("v2")));
237 insertData(TABLE_NAME, startRowNum, rowCount);
239 ClusterMetrics metrics = ADMIN.getClusterMetrics();
240 Assert.assertEquals(metrics.getTableRegionStatesCount().size(), 2);
241 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
242 .getRegionsInTransition(), 0);
243 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
244 .getOpenRegions(), 1);
245 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
246 .getTotalRegions(), 1);
247 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
248 .getRegionsInTransition(), 0);
249 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
250 .getOpenRegions(), 1);
251 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
252 .getTotalRegions(), 1);
254 int splitRowNum = startRowNum + rowCount / 2;
255 byte[] splitKey = Bytes.toBytes("" + splitRowNum);
257 // Split region of the table
258 ADMIN.split(TABLE_NAME, splitKey);
260 metrics = ADMIN.getClusterMetrics();
261 Assert.assertEquals(metrics.getTableRegionStatesCount().size(), 2);
262 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
263 .getRegionsInTransition(), 0);
264 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
265 .getOpenRegions(), 1);
266 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TableName.META_TABLE_NAME)
267 .getTotalRegions(), 1);
268 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
269 .getRegionsInTransition(), 0);
270 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
271 .getOpenRegions(), 2);
272 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
273 .getTotalRegions(), 3);
274 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
275 .getSplitRegions(), 1);
276 Assert.assertEquals(metrics.getTableRegionStatesCount().get(TABLE_NAME)
277 .getClosedRegions(), 0);
279 UTIL.deleteTable(TABLE_NAME);
282 @Test public void testMasterAndBackupMastersStatus() throws Exception {
283 // get all the master threads
284 List<MasterThread> masterThreads = CLUSTER.getMasterThreads();
285 int numActive = 0;
286 int activeIndex = 0;
287 ServerName activeName = null;
288 HMaster active = null;
289 for (int i = 0; i < masterThreads.size(); i++) {
290 if (masterThreads.get(i).getMaster().isActiveMaster()) {
291 numActive++;
292 activeIndex = i;
293 active = masterThreads.get(activeIndex).getMaster();
294 activeName = active.getServerName();
297 Assert.assertNotNull(active);
298 Assert.assertEquals(1, numActive);
299 Assert.assertEquals(MASTERS, masterThreads.size());
300 // Retrieve master and backup masters infos only.
301 EnumSet<Option> options = EnumSet.of(Option.MASTER, Option.BACKUP_MASTERS);
302 ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
303 Assert.assertTrue(metrics.getMasterName().equals(activeName));
304 Assert.assertEquals(MASTERS - 1, metrics.getBackupMasterNames().size());
307 @Test public void testUserMetrics() throws Exception {
308 Configuration conf = UTIL.getConfiguration();
309 User userFoo = User.createUserForTesting(conf, "FOO_USER_METRIC_TEST", new String[0]);
310 User userBar = User.createUserForTesting(conf, "BAR_USER_METRIC_TEST", new String[0]);
311 User userTest = User.createUserForTesting(conf, "TEST_USER_METRIC_TEST", new String[0]);
312 UTIL.createTable(TABLE_NAME, CF);
313 waitForUsersMetrics(0);
314 long writeMetaMetricBeforeNextuser = getMetaMetrics().getWriteRequestCount();
315 userFoo.runAs(new PrivilegedAction<Void>() {
316 @Override public Void run() {
317 try {
318 doPut();
319 } catch (IOException e) {
320 Assert.fail("Exception:" + e.getMessage());
322 return null;
325 waitForUsersMetrics(1);
326 long writeMetaMetricForUserFoo =
327 getMetaMetrics().getWriteRequestCount() - writeMetaMetricBeforeNextuser;
328 long readMetaMetricBeforeNextuser = getMetaMetrics().getReadRequestCount();
329 userBar.runAs(new PrivilegedAction<Void>() {
330 @Override public Void run() {
331 try {
332 doGet();
333 } catch (IOException e) {
334 Assert.fail("Exception:" + e.getMessage());
336 return null;
339 waitForUsersMetrics(2);
340 long readMetaMetricForUserBar =
341 getMetaMetrics().getReadRequestCount() - readMetaMetricBeforeNextuser;
342 long filteredMetaReqeust = getMetaMetrics().getFilteredReadRequestCount();
343 userTest.runAs(new PrivilegedAction<Void>() {
344 @Override public Void run() {
345 try {
346 Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
347 for (Result result : table.getScanner(new Scan().setFilter(new FilterAllFilter()))) {
348 Assert.fail("Should have filtered all rows");
350 } catch (IOException e) {
351 Assert.fail("Exception:" + e.getMessage());
353 return null;
356 waitForUsersMetrics(3);
357 long filteredMetaReqeustForTestUser =
358 getMetaMetrics().getFilteredReadRequestCount() - filteredMetaReqeust;
359 Map<byte[], UserMetrics> userMap =
360 ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().values()
361 .iterator().next().getUserMetrics();
362 for (byte[] user : userMap.keySet()) {
363 switch (Bytes.toString(user)) {
364 case "FOO_USER_METRIC_TEST":
365 Assert.assertEquals(1,
366 userMap.get(user).getWriteRequestCount() - writeMetaMetricForUserFoo);
367 break;
368 case "BAR_USER_METRIC_TEST":
369 Assert
370 .assertEquals(1, userMap.get(user).getReadRequestCount() - readMetaMetricForUserBar);
371 Assert.assertEquals(0, userMap.get(user).getWriteRequestCount());
372 break;
373 case "TEST_USER_METRIC_TEST":
374 Assert.assertEquals(1,
375 userMap.get(user).getFilteredReadRequests() - filteredMetaReqeustForTestUser);
376 Assert.assertEquals(0, userMap.get(user).getWriteRequestCount());
377 break;
378 default:
379 //current user
380 Assert.assertEquals(UserProvider.instantiate(conf).getCurrent().getName(),
381 Bytes.toString(user));
382 //Read/write count because of Meta operations
383 Assert.assertTrue(userMap.get(user).getReadRequestCount() > 1);
384 break;
387 UTIL.deleteTable(TABLE_NAME);
390 private RegionMetrics getMetaMetrics() throws IOException {
391 for (ServerMetrics serverMetrics : ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS))
392 .getLiveServerMetrics().values()) {
393 RegionMetrics metaMetrics = serverMetrics.getRegionMetrics()
394 .get(RegionInfoBuilder.FIRST_META_REGIONINFO.getRegionName());
395 if (metaMetrics != null) {
396 return metaMetrics;
399 Assert.fail("Should have find meta metrics");
400 return null;
403 private void waitForUsersMetrics(int noOfUsers) throws Exception {
404 //Sleep for metrics to get updated on master
405 Thread.sleep(5000);
406 Waiter.waitFor(CLUSTER.getConfiguration(), 10 * 1000, 100, new Predicate<Exception>() {
407 @Override public boolean evaluate() throws Exception {
408 Map<byte[], UserMetrics> metrics =
409 ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().values()
410 .iterator().next().getUserMetrics();
411 Assert.assertNotNull(metrics);
412 //including current user + noOfUsers
413 return metrics.keySet().size() > noOfUsers;
418 private void doPut() throws IOException {
419 Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
420 table.put(new Put(Bytes.toBytes("a")).addColumn(CF, Bytes.toBytes("col1"), Bytes.toBytes("1")));
424 private void doGet() throws IOException {
425 Table table = createConnection(UTIL.getConfiguration()).getTable(TABLE_NAME);
426 table.get(new Get(Bytes.toBytes("a")).addColumn(CF, Bytes.toBytes("col1")));
430 private Connection createConnection(Configuration conf) throws IOException {
431 User user = UserProvider.instantiate(conf).getCurrent();
432 return ClusterConnectionFactory.createAsyncClusterConnection(conf, null, user).toConnection();
435 @Test
436 public void testOtherStatusInfos() throws Exception {
437 EnumSet<Option> options =
438 EnumSet.of(Option.MASTER_COPROCESSORS, Option.HBASE_VERSION,
439 Option.CLUSTER_ID, Option.BALANCER_ON);
440 ClusterMetrics metrics = ADMIN.getClusterMetrics(options);
441 Assert.assertEquals(1, metrics.getMasterCoprocessorNames().size());
442 Assert.assertNotNull(metrics.getHBaseVersion());
443 Assert.assertNotNull(metrics.getClusterId());
444 Assert.assertTrue(metrics.getAverageLoad() == 0.0);
445 Assert.assertNotNull(metrics.getBalancerOn());
448 @AfterClass
449 public static void tearDownAfterClass() throws Exception {
450 if (ADMIN != null) {
451 ADMIN.close();
453 UTIL.shutdownMiniCluster();
456 @Test
457 public void testObserver() throws IOException {
458 int preCount = MyObserver.PRE_COUNT.get();
459 int postCount = MyObserver.POST_COUNT.get();
460 Assert.assertTrue(ADMIN.getClusterMetrics().getMasterCoprocessorNames().stream()
461 .anyMatch(s -> s.equals(MyObserver.class.getSimpleName())));
462 Assert.assertEquals(preCount + 1, MyObserver.PRE_COUNT.get());
463 Assert.assertEquals(postCount + 1, MyObserver.POST_COUNT.get());
466 private static void insertData(final TableName tableName, int startRow, int rowCount)
467 throws IOException {
468 Table t = UTIL.getConnection().getTable(tableName);
469 Put p;
470 for (int i = 0; i < rowCount; i++) {
471 p = new Put(Bytes.toBytes("" + (startRow + i)));
472 p.addColumn(CF, Bytes.toBytes("val1"), Bytes.toBytes(i));
473 t.put(p);
477 public static class MyObserver implements MasterCoprocessor, MasterObserver {
478 private static final AtomicInteger PRE_COUNT = new AtomicInteger(0);
479 private static final AtomicInteger POST_COUNT = new AtomicInteger(0);
481 @Override public Optional<MasterObserver> getMasterObserver() {
482 return Optional.of(this);
485 @Override public void preGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx)
486 throws IOException {
487 PRE_COUNT.incrementAndGet();
490 @Override public void postGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx,
491 ClusterMetrics metrics) throws IOException {
492 POST_COUNT.incrementAndGet();