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.metrics2.impl; 019 020import java.util.concurrent.ScheduledFuture; 021import java.util.concurrent.TimeUnit; 022import java.util.concurrent.atomic.AtomicBoolean; 023import java.util.concurrent.atomic.AtomicReference; 024import org.apache.hadoop.metrics2.MetricsExecutor; 025import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; 026import org.apache.hadoop.metrics2.lib.MetricsExecutorImpl; 027import org.apache.hadoop.util.StringUtils; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032/** 033 * JMX caches the beans that have been exported; even after the values are removed from hadoop's 034 * metrics system the keys and old values will still remain. This class stops and restarts the 035 * Hadoop metrics system, forcing JMX to clear the cache of exported metrics. This class need to be 036 * in the o.a.h.metrics2.impl namespace as many of the variables/calls used are package private. 037 */ 038@InterfaceAudience.Private 039public final class JmxCacheBuster { 040 private static final Logger LOG = LoggerFactory.getLogger(JmxCacheBuster.class); 041 private static AtomicReference<ScheduledFuture> fut = new AtomicReference<>(null); 042 private static MetricsExecutor executor = new MetricsExecutorImpl(); 043 private static AtomicBoolean stopped = new AtomicBoolean(false); 044 045 private JmxCacheBuster() { 046 // Static only cache. 047 } 048 049 /** 050 * For JMX to forget about all previously exported metrics. 051 */ 052 public static void clearJmxCache() { 053 if (LOG.isTraceEnabled()) { 054 LOG.trace("clearing JMX Cache" + StringUtils.stringifyException(new Exception())); 055 } 056 // If there are more then 100 ms before the executor will run then everything should be merged. 057 ScheduledFuture future = fut.get(); 058 if ((future != null && (!future.isDone() && future.getDelay(TimeUnit.MILLISECONDS) > 100))) { 059 // BAIL OUT 060 return; 061 } 062 if (stopped.get()) { 063 return; 064 } 065 future = executor.getExecutor().schedule(new JmxCacheBusterRunnable(), 5, TimeUnit.SECONDS); 066 fut.set(future); 067 } 068 069 /** 070 * Stops the clearing of JMX metrics and restarting the Hadoop metrics system. This is needed for 071 * some test environments where we manually inject sources or sinks dynamically. 072 */ 073 public static void stop() { 074 stopped.set(true); 075 ScheduledFuture future = fut.get(); 076 future.cancel(false); 077 } 078 079 /** 080 * Restarts the stopped service. 081 * @see #stop() 082 */ 083 public static void restart() { 084 stopped.set(false); 085 } 086 087 final static class JmxCacheBusterRunnable implements Runnable { 088 @Override 089 public void run() { 090 if (LOG.isTraceEnabled()) { 091 LOG.trace("Clearing JMX mbean cache."); 092 } 093 094 // This is pretty extreme but it's the best way that 095 // I could find to get metrics to be removed. 096 try { 097 if (DefaultMetricsSystem.instance() != null) { 098 DefaultMetricsSystem.instance().stop(); 099 // Sleep some time so that the rest of the hadoop metrics 100 // system knows that things are done 101 Thread.sleep(500); 102 DefaultMetricsSystem.instance().start(); 103 } 104 } catch (Exception exception) { 105 LOG.debug("error clearing the jmx it appears the metrics system hasn't been started", 106 exception); 107 } 108 } 109 } 110}