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    
021    package org.apache.hadoop.metrics.spi;
022    
023    import java.util.Collections;
024    import java.util.HashSet;
025    import java.util.LinkedHashMap;
026    import java.util.Map;
027    import java.util.Set;
028    import java.util.Map.Entry;
029    
030    import org.apache.hadoop.classification.InterfaceAudience;
031    import org.apache.hadoop.classification.InterfaceStability;
032    import org.apache.hadoop.metrics.MetricsException;
033    import org.apache.hadoop.metrics.MetricsRecord;
034    import org.apache.hadoop.metrics.spi.AbstractMetricsContext.MetricMap;
035    import 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
044    public 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    }