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.regionserver;
019
020import java.util.Collections;
021import java.util.Map;
022import java.util.concurrent.ConcurrentHashMap;
023import java.util.concurrent.atomic.AtomicBoolean;
024import java.util.concurrent.atomic.LongAdder;
025import org.apache.hadoop.metrics2.MetricHistogram;
026import org.apache.hadoop.metrics2.MetricsCollector;
027import org.apache.hadoop.metrics2.MetricsRecordBuilder;
028import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
029import org.apache.yetus.audience.InterfaceAudience;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033@InterfaceAudience.Private
034public class MetricsUserSourceImpl implements MetricsUserSource {
035  private static final Logger LOG = LoggerFactory.getLogger(MetricsUserSourceImpl.class);
036
037  private final String userNamePrefix;
038
039  private final String user;
040
041  private final String userGetKey;
042  private final String userScanTimeKey;
043  private final String userPutKey;
044  private final String userDeleteKey;
045  private final String userIncrementKey;
046  private final String userAppendKey;
047  private final String userReplayKey;
048
049  private MetricHistogram getHisto;
050  private MetricHistogram scanTimeHisto;
051  private MetricHistogram putHisto;
052  private MetricHistogram deleteHisto;
053  private MetricHistogram incrementHisto;
054  private MetricHistogram appendHisto;
055  private MetricHistogram replayHisto;
056
057  private final int hashCode;
058
059  private AtomicBoolean closed = new AtomicBoolean(false);
060  private final DynamicMetricsRegistry registry;
061
062  private ConcurrentHashMap<String, ClientMetrics> clientMetricsMap;
063
064  static class ClientMetricsImpl implements ClientMetrics {
065    private final String hostName;
066    final LongAdder readRequestsCount = new LongAdder();
067    final LongAdder writeRequestsCount = new LongAdder();
068    final LongAdder filteredRequestsCount = new LongAdder();
069
070    public ClientMetricsImpl(String hostName) {
071      this.hostName = hostName;
072    }
073
074    @Override
075    public void incrementReadRequest() {
076      readRequestsCount.increment();
077    }
078
079    @Override
080    public void incrementWriteRequest() {
081      writeRequestsCount.increment();
082    }
083
084    @Override
085    public String getHostName() {
086      return hostName;
087    }
088
089    @Override
090    public long getReadRequestsCount() {
091      return readRequestsCount.sum();
092    }
093
094    @Override
095    public long getWriteRequestsCount() {
096      return writeRequestsCount.sum();
097    }
098
099    @Override
100    public void incrementFilteredReadRequests() {
101      filteredRequestsCount.increment();
102
103    }
104
105    @Override
106    public long getFilteredReadRequests() {
107      return filteredRequestsCount.sum();
108    }
109  }
110
111  public MetricsUserSourceImpl(String user, MetricsUserAggregateSourceImpl agg) {
112    if (LOG.isDebugEnabled()) {
113      LOG.debug("Creating new MetricsUserSourceImpl for user " + user);
114    }
115
116    this.user = user;
117    this.registry = agg.getMetricsRegistry();
118
119    this.userNamePrefix = "user_" + user + "_metric_";
120
121    hashCode = userNamePrefix.hashCode();
122
123    userGetKey = userNamePrefix + MetricsRegionServerSource.GET_KEY;
124    userScanTimeKey = userNamePrefix + MetricsRegionServerSource.SCAN_TIME_KEY;
125    userPutKey = userNamePrefix + MetricsRegionServerSource.PUT_KEY;
126    userDeleteKey = userNamePrefix + MetricsRegionServerSource.DELETE_KEY;
127    userIncrementKey = userNamePrefix + MetricsRegionServerSource.INCREMENT_KEY;
128    userAppendKey = userNamePrefix + MetricsRegionServerSource.APPEND_KEY;
129    userReplayKey = userNamePrefix + MetricsRegionServerSource.REPLAY_KEY;
130    clientMetricsMap = new ConcurrentHashMap<>();
131    agg.register(this);
132  }
133
134  @Override
135  public void register() {
136    synchronized (this) {
137      getHisto = registry.newTimeHistogram(userGetKey);
138      scanTimeHisto = registry.newTimeHistogram(userScanTimeKey);
139      putHisto = registry.newTimeHistogram(userPutKey);
140      deleteHisto = registry.newTimeHistogram(userDeleteKey);
141      incrementHisto = registry.newTimeHistogram(userIncrementKey);
142      appendHisto = registry.newTimeHistogram(userAppendKey);
143      replayHisto = registry.newTimeHistogram(userReplayKey);
144    }
145  }
146
147  @Override
148  public void deregister() {
149    boolean wasClosed = closed.getAndSet(true);
150
151    // Has someone else already closed this for us?
152    if (wasClosed) {
153      return;
154    }
155
156    if (LOG.isDebugEnabled()) {
157      LOG.debug("Removing user Metrics for user: " + user);
158    }
159
160    synchronized (this) {
161      registry.removeMetric(userGetKey);
162      registry.removeMetric(userScanTimeKey);
163      registry.removeMetric(userPutKey);
164      registry.removeMetric(userDeleteKey);
165      registry.removeMetric(userIncrementKey);
166      registry.removeMetric(userAppendKey);
167      registry.removeMetric(userReplayKey);
168    }
169  }
170
171  @Override
172  public String getUser() {
173    return user;
174  }
175
176  @Override
177  public int compareTo(MetricsUserSource source) {
178    if (source == null) {
179      return -1;
180    }
181    if (!(source instanceof MetricsUserSourceImpl)) {
182      return -1;
183    }
184
185    MetricsUserSourceImpl impl = (MetricsUserSourceImpl) source;
186
187    return Long.compare(hashCode, impl.hashCode);
188  }
189
190  @Override
191  public int hashCode() {
192    return hashCode;
193  }
194
195  @Override
196  public boolean equals(Object obj) {
197    return obj == this
198      || (obj instanceof MetricsUserSourceImpl && compareTo((MetricsUserSourceImpl) obj) == 0);
199  }
200
201  void snapshot(MetricsRecordBuilder mrb, boolean ignored) {
202    // If there is a close that started be double extra sure
203    // that we're not getting any locks and not putting data
204    // into the metrics that should be removed. So early out
205    // before even getting the lock.
206    if (closed.get()) {
207      return;
208    }
209
210    // Grab the read
211    // This ensures that removes of the metrics
212    // can't happen while we are putting them back in.
213    synchronized (this) {
214
215      // It's possible that a close happened between checking
216      // the closed variable and getting the lock.
217      if (closed.get()) {
218        return;
219      }
220    }
221  }
222
223  @Override
224  public void updatePut(long t) {
225    putHisto.add(t);
226  }
227
228  @Override
229  public void updateDelete(long t) {
230    deleteHisto.add(t);
231  }
232
233  @Override
234  public void updateGet(long t) {
235    getHisto.add(t);
236  }
237
238  @Override
239  public void updateIncrement(long t) {
240    incrementHisto.add(t);
241  }
242
243  @Override
244  public void updateAppend(long t) {
245    appendHisto.add(t);
246  }
247
248  @Override
249  public void updateReplay(long t) {
250    replayHisto.add(t);
251  }
252
253  @Override
254  public void updateScanTime(long t) {
255    scanTimeHisto.add(t);
256  }
257
258  @Override
259  public void getMetrics(MetricsCollector metricsCollector, boolean all) {
260    MetricsRecordBuilder mrb = metricsCollector.addRecord(this.userNamePrefix);
261    registry.snapshot(mrb, all);
262  }
263
264  @Override
265  public Map<String, ClientMetrics> getClientMetrics() {
266    return Collections.unmodifiableMap(clientMetricsMap);
267  }
268
269  @Override
270  public ClientMetrics getOrCreateMetricsClient(String client) {
271    ClientMetrics source = clientMetricsMap.get(client);
272    if (source != null) {
273      return source;
274    }
275    source = new ClientMetricsImpl(client);
276    ClientMetrics prev = clientMetricsMap.putIfAbsent(client, source);
277    if (prev != null) {
278      return prev;
279    }
280    return source;
281  }
282
283}