001/*
002 * MetricsRecordImpl.java
003 *
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *     http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020
021package org.apache.hadoop.metrics.spi;
022
023import java.util.Collections;
024import java.util.HashSet;
025import java.util.LinkedHashMap;
026import java.util.Map;
027import java.util.Set;
028import java.util.Map.Entry;
029
030import org.apache.hadoop.classification.InterfaceAudience;
031import org.apache.hadoop.classification.InterfaceStability;
032import org.apache.hadoop.metrics.MetricsException;
033import org.apache.hadoop.metrics.MetricsRecord;
034import org.apache.hadoop.metrics.spi.AbstractMetricsContext.MetricMap;
035import org.apache.hadoop.metrics.spi.AbstractMetricsContext.TagMap;
036
037/**
038 * An implementation of MetricsRecord.  Keeps a back-pointer to the context
039 * from which it was created, and delegates back to it on <code>update</code>
040 * and <code>remove()</code>.
041 */
042@InterfaceAudience.Public
043@InterfaceStability.Evolving
044public class MetricsRecordImpl implements MetricsRecord {
045    
046  private TagMap tagTable = new TagMap();
047  private Map<String,MetricValue> metricTable = new LinkedHashMap<String,MetricValue>();
048    
049  private String recordName;
050  private AbstractMetricsContext context;
051    
052    
053  /** Creates a new instance of FileRecord */
054  protected MetricsRecordImpl(String recordName, AbstractMetricsContext context)
055  {
056    this.recordName = recordName;
057    this.context = context;
058  }
059    
060  /**
061   * Returns the record name. 
062   *
063   * @return the record name
064   */
065  public String getRecordName() {
066    return recordName;
067  }
068    
069  /**
070   * Sets the named tag to the specified value.
071   *
072   * @param tagName name of the tag
073   * @param tagValue new value of the tag
074   * @throws MetricsException if the tagName conflicts with the configuration
075   */
076  public void setTag(String tagName, String tagValue) {
077    if (tagValue == null) {
078      tagValue = "";
079    }
080    tagTable.put(tagName, tagValue);
081  }
082    
083  /**
084   * Sets the named tag to the specified value.
085   *
086   * @param tagName name of the tag
087   * @param tagValue new value of the tag
088   * @throws MetricsException if the tagName conflicts with the configuration
089   */
090  public void setTag(String tagName, int tagValue) {
091    tagTable.put(tagName, Integer.valueOf(tagValue));
092  }
093    
094  /**
095   * Sets the named tag to the specified value.
096   *
097   * @param tagName name of the tag
098   * @param tagValue new value of the tag
099   * @throws MetricsException if the tagName conflicts with the configuration
100   */
101  public void setTag(String tagName, long tagValue) {
102    tagTable.put(tagName, Long.valueOf(tagValue));
103  }
104    
105  /**
106   * Sets the named tag to the specified value.
107   *
108   * @param tagName name of the tag
109   * @param tagValue new value of the tag
110   * @throws MetricsException if the tagName conflicts with the configuration
111   */
112  public void setTag(String tagName, short tagValue) {
113    tagTable.put(tagName, Short.valueOf(tagValue));
114  }
115    
116  /**
117   * Sets the named tag to the specified value.
118   *
119   * @param tagName name of the tag
120   * @param tagValue new value of the tag
121   * @throws MetricsException if the tagName conflicts with the configuration
122   */
123  public void setTag(String tagName, byte tagValue) {
124    tagTable.put(tagName, Byte.valueOf(tagValue));
125  }
126    
127  /**
128   * Removes any tag of the specified name.
129   */
130  public void removeTag(String tagName) {
131    tagTable.remove(tagName);
132  }
133  
134  /**
135   * Sets the named metric to the specified value.
136   *
137   * @param metricName name of the metric
138   * @param metricValue new value of the metric
139   * @throws MetricsException if the metricName or the type of the metricValue 
140   * conflicts with the configuration
141   */
142  public void setMetric(String metricName, int metricValue) {
143    setAbsolute(metricName, Integer.valueOf(metricValue));
144  }
145    
146  /**
147   * Sets the named metric to the specified value.
148   *
149   * @param metricName name of the metric
150   * @param metricValue new value of the metric
151   * @throws MetricsException if the metricName or the type of the metricValue 
152   * conflicts with the configuration
153   */
154  public void setMetric(String metricName, long metricValue) {
155    setAbsolute(metricName, Long.valueOf(metricValue));
156  }
157    
158  /**
159   * Sets the named metric to the specified value.
160   *
161   * @param metricName name of the metric
162   * @param metricValue new value of the metric
163   * @throws MetricsException if the metricName or the type of the metricValue 
164   * conflicts with the configuration
165   */
166  public void setMetric(String metricName, short metricValue) {
167    setAbsolute(metricName, Short.valueOf(metricValue));
168  }
169    
170  /**
171   * Sets the named metric to the specified value.
172   *
173   * @param metricName name of the metric
174   * @param metricValue new value of the metric
175   * @throws MetricsException if the metricName or the type of the metricValue 
176   * conflicts with the configuration
177   */
178  public void setMetric(String metricName, byte metricValue) {
179    setAbsolute(metricName, Byte.valueOf(metricValue));
180  }
181    
182  /**
183   * Sets the named metric to the specified value.
184   *
185   * @param metricName name of the metric
186   * @param metricValue new value of the metric
187   * @throws MetricsException if the metricName or the type of the metricValue 
188   * conflicts with the configuration
189   */
190  public void setMetric(String metricName, float metricValue) {
191    setAbsolute(metricName, new Float(metricValue));
192  }
193    
194  /**
195   * Increments the named metric by the specified value.
196   *
197   * @param metricName name of the metric
198   * @param metricValue incremental value
199   * @throws MetricsException if the metricName or the type of the metricValue 
200   * conflicts with the configuration
201   */
202  public void incrMetric(String metricName, int metricValue) {
203    setIncrement(metricName, Integer.valueOf(metricValue));
204  }
205    
206  /**
207   * Increments the named metric by the specified value.
208   *
209   * @param metricName name of the metric
210   * @param metricValue incremental value
211   * @throws MetricsException if the metricName or the type of the metricValue 
212   * conflicts with the configuration
213   */
214  public void incrMetric(String metricName, long metricValue) {
215    setIncrement(metricName, Long.valueOf(metricValue));
216  }
217    
218  /**
219   * Increments the named metric by the specified value.
220   *
221   * @param metricName name of the metric
222   * @param metricValue incremental value
223   * @throws MetricsException if the metricName or the type of the metricValue 
224   * conflicts with the configuration
225   */
226  public void incrMetric(String metricName, short metricValue) {
227    setIncrement(metricName, Short.valueOf(metricValue));
228  }
229    
230  /**
231   * Increments the named metric by the specified value.
232   *
233   * @param metricName name of the metric
234   * @param metricValue incremental value
235   * @throws MetricsException if the metricName or the type of the metricValue 
236   * conflicts with the configuration
237   */
238  public void incrMetric(String metricName, byte metricValue) {
239    setIncrement(metricName, Byte.valueOf(metricValue));
240  }
241    
242  /**
243   * Increments the named metric by the specified value.
244   *
245   * @param metricName name of the metric
246   * @param metricValue incremental value
247   * @throws MetricsException if the metricName or the type of the metricValue 
248   * conflicts with the configuration
249   */
250  public void incrMetric(String metricName, float metricValue) {
251    setIncrement(metricName, new Float(metricValue));
252  }
253    
254  private void setAbsolute(String metricName, Number metricValue) {
255    metricTable.put(metricName, new MetricValue(metricValue, MetricValue.ABSOLUTE));
256  }
257    
258  private void setIncrement(String metricName, Number metricValue) {
259    metricTable.put(metricName, new MetricValue(metricValue, MetricValue.INCREMENT));
260  }
261    
262  /**
263   * Updates the table of buffered data which is to be sent periodically.
264   * If the tag values match an existing row, that row is updated; 
265   * otherwise, a new row is added.
266   */
267  public void update() {
268    context.update(this);
269  }
270    
271  /**
272   * Removes the row, if it exists, in the buffered data table having tags 
273   * that equal the tags that have been set on this record. 
274   */
275  public void remove() {
276    context.remove(this);
277  }
278
279  TagMap getTagTable() {
280    return tagTable;
281  }
282
283  Map<String, MetricValue> getMetricTable() {
284    return metricTable;
285  }
286
287  public Set<String> getTagNames() {
288    return Collections.unmodifiableSet(tagTable.keySet());
289  }
290
291  public OutputRecord createOutputRecord() {
292    Set<Entry<String, MetricValue>> entrySet = new HashSet<Entry<String, MetricValue>>(metricTable.entrySet());
293    TagMap copyTagMap = new TagMap(tagTable);
294    MetricMap metricMap = new MetricMap();
295    for (Entry<String, MetricValue> entry : entrySet) {
296      String metricName = entry.getKey ();
297      MetricValue updateValue = entry.getValue ();
298      Number updateNumber = updateValue.getNumber();
299      Number currentNumber = metricMap.get(metricName);
300      if (currentNumber == null || updateValue.isAbsolute()) {
301        metricMap.put(metricName, updateNumber);
302      }
303      else {
304        Number newNumber = sum(updateNumber, currentNumber);
305        metricMap.put(metricName, newNumber);
306      }
307    }
308
309    OutputRecord retRecord = new OutputRecord(copyTagMap, metricMap);
310    return retRecord;
311  }
312  
313  private Number sum(Number a, Number b) {
314    if (a instanceof Integer) {
315      return Integer.valueOf(a.intValue() + b.intValue());
316    }
317    else if (a instanceof Float) {
318      return new Float(a.floatValue() + b.floatValue());
319    }
320    else if (a instanceof Short) {
321      return Short.valueOf((short)(a.shortValue() + b.shortValue()));
322    }
323    else if (a instanceof Byte) {
324      return Byte.valueOf((byte)(a.byteValue() + b.byteValue()));
325    }
326    else if (a instanceof Long) {
327      return Long.valueOf((a.longValue() + b.longValue()));
328    }
329    else {
330      // should never happen
331      throw new MetricsException("Invalid number type");
332    }
333  }
334}