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 */
018
019package org.apache.hadoop.hbase.regionserver;
020
021import java.util.concurrent.atomic.AtomicBoolean;
022
023import org.apache.hadoop.hbase.TableName;
024import org.apache.hadoop.hbase.metrics.Interns;
025import org.apache.hadoop.metrics2.MetricsRecordBuilder;
026import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
027import org.apache.yetus.audience.InterfaceAudience;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031@InterfaceAudience.Private
032public class MetricsTableSourceImpl implements MetricsTableSource {
033
034  private static final Logger LOG = LoggerFactory.getLogger(MetricsTableSourceImpl.class);
035
036  private AtomicBoolean closed = new AtomicBoolean(false);
037
038  // Non-final so that we can null out the wrapper
039  // This is just paranoia. We really really don't want to
040  // leak a whole table by way of keeping the
041  // tableWrapper around too long.
042  private MetricsTableWrapperAggregate tableWrapperAgg;
043  private final MetricsTableAggregateSourceImpl agg;
044  private final DynamicMetricsRegistry registry;
045  private final String tableNamePrefix;
046  private final TableName tableName;
047  private final int hashCode;
048
049  public MetricsTableSourceImpl(String tblName,
050      MetricsTableAggregateSourceImpl aggregate, MetricsTableWrapperAggregate tblWrapperAgg) {
051    LOG.debug("Creating new MetricsTableSourceImpl for table ");
052    this.tableName = TableName.valueOf(tblName);
053    this.agg = aggregate;
054    agg.register(tblName, this);
055    this.tableWrapperAgg = tblWrapperAgg;
056    this.registry = agg.getMetricsRegistry();
057    this.tableNamePrefix = "Namespace_" + this.tableName.getNamespaceAsString() +
058        "_table_" + this.tableName.getQualifierAsString() + "_metric_";
059    this.hashCode = this.tableName.hashCode();
060  }
061
062  @Override
063  public void close() {
064    boolean wasClosed = closed.getAndSet(true);
065
066    // Has someone else already closed this for us?
067    if (wasClosed) {
068      return;
069    }
070
071    // Before removing the metrics remove this table from the aggregate table bean.
072    // This should mean that it's unlikely that snapshot and close happen at the same time.
073    agg.deregister(tableName.getNameAsString());
074
075    // While it's un-likely that snapshot and close happen at the same time it's still possible.
076    // So grab the lock to ensure that all calls to snapshot are done before we remove the metrics
077    synchronized (this) {
078      if (LOG.isTraceEnabled()) {
079        LOG.trace("Removing table Metrics for table ");
080      }
081      tableWrapperAgg = null;
082    }
083  }
084  @Override
085  public MetricsTableAggregateSource getAggregateSource() {
086    return agg;
087  }
088
089  @Override
090  public int compareTo(MetricsTableSource source) {
091    if (!(source instanceof MetricsTableSourceImpl)) {
092      return -1;
093    }
094
095    MetricsTableSourceImpl impl = (MetricsTableSourceImpl) source;
096    if (impl == null) {
097      return -1;
098    }
099
100    return Long.compare(hashCode, impl.hashCode);
101  }
102
103  void snapshot(MetricsRecordBuilder mrb, boolean ignored) {
104
105    // If there is a close that started be double extra sure
106    // that we're not getting any locks and not putting data
107    // into the metrics that should be removed. So early out
108    // before even getting the lock.
109    if (closed.get()) {
110      return;
111    }
112
113    // Grab the read
114    // This ensures that removes of the metrics
115    // can't happen while we are putting them back in.
116    synchronized (this) {
117
118      // It's possible that a close happened between checking
119      // the closed variable and getting the lock.
120      if (closed.get()) {
121        return;
122      }
123
124      if (this.tableWrapperAgg != null) {
125        mrb.addCounter(Interns.info(tableNamePrefix + MetricsTableSource.READ_REQUEST_COUNT,
126          MetricsTableSource.READ_REQUEST_COUNT_DESC),
127          tableWrapperAgg.getReadRequestsCount(tableName.getNameAsString()));
128        mrb.addCounter(Interns.info(tableNamePrefix + MetricsTableSource.WRITE_REQUEST_COUNT,
129          MetricsTableSource.WRITE_REQUEST_COUNT_DESC),
130          tableWrapperAgg.getWriteRequestsCount(tableName.getNameAsString()));
131        mrb.addCounter(Interns.info(tableNamePrefix + MetricsTableSource.TOTAL_REQUEST_COUNT,
132          MetricsTableSource.TOTAL_REQUEST_COUNT_DESC),
133          tableWrapperAgg.getTotalRequestsCount(tableName.getNameAsString()));
134        mrb.addGauge(Interns.info(tableNamePrefix + MetricsTableSource.MEMSTORE_SIZE,
135          MetricsTableSource.MEMSTORE_SIZE_DESC),
136          tableWrapperAgg.getMemStoresSize(tableName.getNameAsString()));
137        mrb.addGauge(Interns.info(tableNamePrefix + MetricsTableSource.STORE_FILE_SIZE,
138          MetricsTableSource.STORE_FILE_SIZE_DESC),
139          tableWrapperAgg.getStoreFilesSize(tableName.getNameAsString()));
140        mrb.addGauge(Interns.info(tableNamePrefix + MetricsTableSource.TABLE_SIZE,
141          MetricsTableSource.TABLE_SIZE_DESC),
142          tableWrapperAgg.getTableSize(tableName.getNameAsString()));
143      }
144    }
145  }
146
147  @Override
148  public String getTableName() {
149    return tableName.getNameAsString();
150  }
151
152  @Override
153  public int hashCode() {
154    return hashCode;
155  }
156
157  @Override
158  public boolean equals(Object o) {
159    if (this == o) {
160      return true;
161    }
162
163    if (o == null || getClass() != o.getClass()) {
164      return false;
165    }
166
167    return (compareTo((MetricsTableSourceImpl) o) == 0);
168  }
169
170  public MetricsTableWrapperAggregate getTableWrapper() {
171    return tableWrapperAgg;
172  }
173
174  public String getTableNamePrefix() {
175    return tableNamePrefix;
176  }
177}