This project has retired. For details please refer to its Attic page.
ChukwaHBaseStore xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.chukwa.datastore;
19  
20  import java.io.IOException;
21  import java.net.URI;
22  import java.net.URISyntaxException;
23  import java.nio.ByteBuffer;
24  import java.nio.charset.Charset;
25  import java.util.ArrayList;
26  import java.util.Calendar;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Set;
32  import java.util.TimeZone;
33  import java.util.UUID;
34  import java.util.concurrent.CopyOnWriteArraySet;
35  import java.util.concurrent.TimeUnit;
36  
37  import org.apache.hadoop.chukwa.hicc.bean.Chart;
38  import org.apache.hadoop.chukwa.hicc.bean.Dashboard;
39  import org.apache.hadoop.chukwa.hicc.bean.HeatMapPoint;
40  import org.apache.hadoop.chukwa.hicc.bean.Heatmap;
41  import org.apache.hadoop.chukwa.hicc.bean.LineOptions;
42  import org.apache.hadoop.chukwa.hicc.bean.Series;
43  import org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData;
44  import org.apache.hadoop.chukwa.hicc.bean.Widget;
45  import org.apache.hadoop.chukwa.hicc.rest.Examples;
46  import org.apache.hadoop.chukwa.util.ExceptionUtil;
47  import org.apache.hadoop.chukwa.util.HBaseUtil;
48  import org.apache.hadoop.hbase.Cell;
49  import org.apache.hadoop.hbase.CellUtil;
50  import org.apache.hadoop.hbase.TableName;
51  import org.apache.hadoop.hbase.client.Connection;
52  import org.apache.hadoop.hbase.client.ConnectionFactory;
53  import org.apache.hadoop.hbase.client.Delete;
54  import org.apache.hadoop.hbase.client.Get;
55  import org.apache.hadoop.hbase.client.Put;
56  import org.apache.hadoop.hbase.client.Result;
57  import org.apache.hadoop.hbase.client.ResultScanner;
58  import org.apache.hadoop.hbase.client.Scan;
59  import org.apache.hadoop.hbase.client.Table;
60  import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
61  import org.apache.hadoop.hbase.filter.Filter;
62  import org.apache.hadoop.hbase.util.Bytes;
63  import org.apache.log4j.Logger;
64  import org.json.simple.JSONObject;
65  import org.json.simple.JSONValue;
66  
67  import com.google.gson.Gson;
68  
69  public class ChukwaHBaseStore {
70    static Logger LOG = Logger.getLogger(ChukwaHBaseStore.class);
71    static int MINUTES_IN_HOUR = 60;
72    static double RESOLUTION = 360;
73    static int MINUTE = 60000; //60 milliseconds
74    final static int SECOND = (int) TimeUnit.SECONDS.toMillis(1);
75    private final static Charset UTF8 = Charset.forName("UTF-8");
76  
77    final static byte[] COLUMN_FAMILY = "t".getBytes(UTF8);
78    final static byte[] ANNOTATION_FAMILY = "a".getBytes(UTF8);
79    final static byte[] KEY_NAMES = "k".getBytes(UTF8);
80    final static byte[] CHART_TYPE = "chart_meta".getBytes(UTF8);
81    final static byte[] CHART_FAMILY = "c".getBytes(UTF8);
82    final static byte[] COMMON_FAMILY = "c".getBytes(UTF8);
83    final static byte[] WIDGET_TYPE = "widget_meta".getBytes(UTF8);
84    final static byte[] DASHBOARD_TYPE = "dashboard_meta".getBytes(UTF8);
85    private static final String CHUKWA = "chukwa";
86    private static final String CHUKWA_META = "chukwa_meta";
87    private static long MILLISECONDS_IN_DAY = 86400000L;
88    private static Connection connection = null;
89  
90    public ChukwaHBaseStore() {
91      super();
92    }
93  
94    public static synchronized void getHBaseConnection() throws IOException {
95      if (connection == null || connection.isClosed()) {
96        connection = ConnectionFactory.createConnection();
97      }
98    }
99    
100   public static synchronized void closeHBase() {
101     try {
102       if(connection != null) {
103         connection.close();
104       }
105     } catch(IOException e) {
106       LOG.warn("Unable to release HBase connection.");
107     }
108   }
109   
110   /**
111    * Scan chukwa table for a particular metric group and metric name based on
112    * time ranges.
113    * 
114    * @param metricGroup metric group name
115    * @param metric metric name
116    * @param source source of the metric
117    * @param startTime start time
118    * @param endTime end time
119    * @return Series object
120    */
121   public static Series getSeries(String metricGroup, String metric,
122       String source, long startTime, long endTime) {
123     String fullMetricName = new StringBuilder(metricGroup).append(".")
124         .append(metric).toString();
125     return getSeries(fullMetricName, source, startTime, endTime);
126   }
127 
128   /**
129    * Scan chukwa table for a full metric name based on time ranges.
130    * 
131    * @param metric metric group name and metric name combined
132    * @param source source of the metric
133    * @param startTime start time
134    * @param endTime end time
135    * @return Series object
136    */
137   public static synchronized Series getSeries(String metric, String source, long startTime,
138       long endTime) {
139     String seriesName = new StringBuilder(metric).append(":").append(source).toString();
140     Series series = new Series(seriesName);
141     try {
142       // Swap start and end if the values are inverted.
143       if (startTime > endTime) {
144         long temp = endTime;
145         startTime = endTime;
146         endTime = temp;
147       }
148 
149       getHBaseConnection();
150       Table table = connection.getTable(TableName.valueOf(CHUKWA));
151       Scan scan = new Scan();
152       Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
153       c.setTimeInMillis(startTime);
154       int startDay = c.get(Calendar.DAY_OF_YEAR);
155       c.setTimeInMillis(endTime);
156       int endDay = c.get(Calendar.DAY_OF_YEAR);
157       long currentDay = startTime;
158       for (int i = startDay; i <= endDay; i++) {
159         byte[] rowKey = HBaseUtil.buildKey(currentDay, metric, source);
160 
161         scan.addFamily(COLUMN_FAMILY);
162         scan.setStartRow(rowKey);
163         scan.setStopRow(rowKey);
164         scan.setTimeRange(startTime, endTime);
165         scan.setBatch(10000);
166 
167         ResultScanner results = table.getScanner(scan);
168         Iterator<Result> it = results.iterator();
169 
170         while (it.hasNext()) {
171           Result result = it.next();
172           for (Cell kv : result.rawCells()) {
173             byte[] key = CellUtil.cloneQualifier(kv);
174             long timestamp = ByteBuffer.wrap(key).getLong();
175             double value = Double
176                 .parseDouble(new String(CellUtil.cloneValue(kv), UTF8));
177             series.add(timestamp, value);
178           }
179         }
180         results.close();
181         currentDay = currentDay + (i * MILLISECONDS_IN_DAY);
182       }
183       table.close();
184     } catch (IOException e) {
185       closeHBase();
186       LOG.error(ExceptionUtil.getStackTrace(e));
187     }
188     return series;
189   }
190 
191   public static Set<String> getMetricNames(String metricGroup) {
192     Set<String> familyNames = new CopyOnWriteArraySet<String>();
193     try {
194       getHBaseConnection();
195       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
196       Get get = new Get(metricGroup.getBytes(UTF8));
197       Result result = table.get(get);
198       for (Cell kv : result.rawCells()) {
199         JSONObject json = (JSONObject) JSONValue.parse(new String(CellUtil.cloneValue(kv), UTF8));
200         if (json.get("type").equals("metric")) {
201           familyNames.add(new String(CellUtil.cloneQualifier(kv), UTF8));
202         }
203       }
204       table.close();
205     } catch (Exception e) {
206       closeHBase();
207       LOG.error(ExceptionUtil.getStackTrace(e));
208     }
209     return familyNames;
210 
211   }
212 
213   public static Set<String> getMetricGroups() {
214     Set<String> metricGroups = new CopyOnWriteArraySet<String>();
215     try {
216       getHBaseConnection();
217       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
218       Scan scan = new Scan();
219       scan.addFamily(KEY_NAMES);
220       ResultScanner rs = table.getScanner(scan);
221       Iterator<Result> it = rs.iterator();
222       while (it.hasNext()) {
223         Result result = it.next();
224         metricGroups.add(new String(result.getRow(), UTF8));
225       }
226       table.close();
227     } catch (Exception e) {
228       closeHBase();
229       LOG.error(ExceptionUtil.getStackTrace(e));
230     }
231     return metricGroups;
232   }
233 
234   public static Set<String> getSourceNames(String dataType) {
235     Set<String> pk = new HashSet<String>();
236     try {
237       getHBaseConnection();
238       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
239       Scan scan = new Scan();
240       scan.addFamily(KEY_NAMES);
241       ResultScanner rs = table.getScanner(scan);
242       Iterator<Result> it = rs.iterator();
243       while (it.hasNext()) {
244         Result result = it.next();
245         for (Cell cell : result.rawCells()) {
246           JSONObject json = (JSONObject) JSONValue.parse(new String(CellUtil.cloneValue(cell), UTF8));
247           if (json!=null && json.get("type")!=null && json.get("type").equals("source")) {
248             pk.add(new String(CellUtil.cloneQualifier(cell), UTF8));
249           }
250         }
251       }
252       rs.close();
253       table.close();
254     } catch (Exception e) {
255       closeHBase();
256       LOG.error(ExceptionUtil.getStackTrace(e));
257     }
258     return pk;
259   }
260 
261   public static Heatmap getHeatmap(String metricGroup, String metric,
262       long startTime, long endTime, double max, double scale, int width, int height) {
263     Heatmap heatmap = new Heatmap();
264     Set<String> sources = getSourceNames(metricGroup);
265     Set<String> metrics = getMetricNames(metricGroup);
266     List<Get> series = new ArrayList<Get>();
267     String fullName = new StringBuilder(metricGroup).append(".").append(metric).toString();
268     try {
269       getHBaseConnection();
270       Table table = connection.getTable(TableName.valueOf(CHUKWA));
271       Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
272       c.setTimeInMillis(startTime);
273       int startDay = c.get(Calendar.DAY_OF_YEAR);
274       c.setTimeInMillis(endTime);
275       int endDay = c.get(Calendar.DAY_OF_YEAR);
276       long currentDay = startTime;
277       for (int i = startDay; i <= endDay; i++) {
278         for (String m : metrics) {
279           if (m.startsWith(fullName)) {
280             for (String source : sources) {
281               byte[] rowKey = HBaseUtil.buildKey(currentDay, m, source);
282               Get serie = new Get(rowKey);
283               serie.addFamily(COLUMN_FAMILY);
284               serie.setTimeRange(startTime, endTime);
285               series.add(serie);
286             }
287           }
288         }
289         currentDay = currentDay + (i * MILLISECONDS_IN_DAY);
290       }
291       long timeRange = (endTime - startTime);
292       Result[] rs = table.get(series);
293       int index = 1;
294       // Series display in y axis
295       int y = 0;
296       HashMap<String, Integer> keyMap = new HashMap<String, Integer>();
297       for (Result result : rs) {
298         for(Cell cell : result.rawCells()) {
299           byte[] dest = new byte[5];
300           System.arraycopy(CellUtil.cloneRow(cell), 3, dest, 0, 5);
301           String source = new String(dest, UTF8);
302           long time = cell.getTimestamp();
303           // Time display in x axis
304           long delta = time - startTime;
305           double f = (double) delta / timeRange;
306           f = (double) f * width;
307           int x = (int) Math.round(f);
308           if (keyMap.containsKey(source)) {
309             y = keyMap.get(source);
310           } else {
311             keyMap.put(source, Integer.valueOf(index));
312             y = index;
313             index++;
314           }
315           double v = Double.parseDouble(new String(CellUtil.cloneValue(cell), UTF8));
316           heatmap.put(x, y, v);
317           if (v > max) {
318             max = v;
319           }
320         }
321       }
322       table.close();
323       int radius = height / index;
324       // Usually scale max from 0 to 100 for visualization
325       heatmap.putMax(scale);
326       for (HeatMapPoint point : heatmap.getHeatmap()) {
327         double round = point.count / max * scale;
328         round = Math.round(round * 100.0) / 100.0;
329         point.put(point.x, point.y * radius, round);
330       }
331       heatmap.putRadius(radius);
332       heatmap.putSeries(index -1);
333     } catch (IOException e) {
334       closeHBase();
335       LOG.error(ExceptionUtil.getStackTrace(e));
336     }
337     return heatmap;
338   }
339 
340   /**
341    * Scan chukwa table and find cluster tag from annotation column family from a
342    * range of entries.
343    * 
344    * @param startTime start time in epoch
345    * @param endTime start time in epoch
346    * @return Set of cluster names
347    */
348   public static Set<String> getClusterNames(long startTime, long endTime) {
349     Set<String> clusters = new HashSet<String>();
350     try {
351       getHBaseConnection();
352       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
353       Scan scan = new Scan();
354       scan.addFamily(KEY_NAMES);
355       ResultScanner rs = table.getScanner(scan);
356       Iterator<Result> it = rs.iterator();
357       while (it.hasNext()) {
358         Result result = it.next();
359         for (Cell cell : result.rawCells()) {
360           JSONObject json = (JSONObject) JSONValue.parse(new String(CellUtil.cloneValue(cell), UTF8));
361           if (json.get("type").equals("cluster")) {
362             clusters.add(new String(CellUtil.cloneQualifier(cell), UTF8));
363           }
364         }
365       }
366       table.close();
367     } catch (Exception e) {
368       closeHBase();
369       LOG.error(ExceptionUtil.getStackTrace(e));
370     }
371     return clusters;
372   }
373 
374   /**
375    * Get a chart from HBase by ID.
376    * 
377    * @param id Chart ID
378    * @return Chart object
379    */
380   public static Chart getChart(String id) {
381     Chart chart = null;
382     try {
383       getHBaseConnection();
384       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
385       Get get = new Get(CHART_TYPE);
386       Result r = table.get(get);
387       byte[] value = r.getValue(CHART_FAMILY, id.getBytes(UTF8));
388       Gson gson = new Gson();
389       if(value!=null) {
390         chart = gson.fromJson(new String(value, UTF8), Chart.class);
391       }
392       table.close();
393     } catch (Exception e) {
394       closeHBase();
395       LOG.error(ExceptionUtil.getStackTrace(e));
396     }
397     return chart;
398   }
399 
400   /**
401    * Update a chart in HBase by ID.
402    * 
403    * @param id Chart ID
404    * @param chart Chart Object
405    */
406   public static void putChart(String id, Chart chart) {
407     try {
408       getHBaseConnection();
409       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
410       Put put = new Put(CHART_TYPE);
411       Gson gson = new Gson();
412       String buffer = gson.toJson(chart);
413       put.addColumn(CHART_FAMILY, id.getBytes(UTF8), buffer.getBytes(UTF8));
414       table.put(put);
415       table.close();
416     } catch (Exception e) {
417       closeHBase();
418       LOG.error(ExceptionUtil.getStackTrace(e));
419     }
420     
421   }
422 
423   /**
424    * Create a chart in HBase by specifying parameters.
425    * @param id is unique chart identifier
426    * @param title is searchable name of the chart
427    * @param metrics is list of metric names to render chart
428    * @param source is data source name
429    * @param yunitType is y axis unit type
430    * @return Chart ID
431    * @throws URISyntaxException if metrics name can not compose valid URL syntax
432    */
433   public static synchronized String createChart(String id,
434       String title, String[] metrics, String source, String yunitType) throws URISyntaxException {
435     Chart chart = new Chart(id);
436     chart.setYUnitType(yunitType);
437     chart.setTitle(title);
438     ArrayList<SeriesMetaData> series = new ArrayList<SeriesMetaData>();
439     for(String metric : metrics) {
440       SeriesMetaData s = new SeriesMetaData();
441       s.setLabel(metric + "/" + source);
442       s.setUrl(new URI("/hicc/v1/metrics/series/" + metric + "/"
443         + source));
444       LineOptions l = new LineOptions();
445       s.setLineOptions(l);
446       series.add(s);
447     }
448     chart.setSeries(series);
449     return createChart(chart);
450     
451   }
452 
453   /**
454    * Create a chart in HBase by specifying parameters.
455    * @param id is unique chart identifier
456    * @param title is searchable name of the chart
457    * @param metrics is list of metric names to render ring chart
458    * @param source is data source name
459    * @param suffixLabel is text label to append to metric values
460    * @param direction sets the threshold to have either upper limit or lower limit
461    * @return Chart ID
462    * @throws URISyntaxException if metrics name can not compose valid URL syntax
463    */
464   public static synchronized String createCircle(String id,
465       String title, String[] metrics, String source, String suffixLabel, String direction) throws URISyntaxException {
466     Chart chart = new Chart(id);
467     chart.setSuffixText(suffixLabel);
468     chart.setTitle(title);
469     chart.setThreshold(direction);
470     ArrayList<SeriesMetaData> series = new ArrayList<SeriesMetaData>();
471     for(String metric : metrics) {
472       SeriesMetaData s = new SeriesMetaData();
473       s.setLabel(metric + "/" + source);
474       s.setUrl(new URI("/hicc/v1/metrics/series/" + metric + "/"
475         + source));
476       series.add(s);
477     }
478     chart.setSeries(series);
479     return createChart(chart);
480     
481   }
482 
483   /**
484    * Create a tile in HBase by specifying parameters.
485    * @param id is unique tile identifier
486    * @param title is searchable name of the tile widget
487    * @param bannerText is description of the tile widget
488    * @param suffixLabel is text label to append to metric values
489    * @param metrics is list of metric names to render tile widget
490    * @param source is data source name
491    * @param icon is emoji symbol to render beside tile widget
492    * @return Widget ID
493    * @throws URISyntaxException if metrics name can not compose valid URL syntax
494    */
495   public static synchronized String createTile(String id, String title, 
496       String bannerText, String suffixLabel, String[] metrics, String source, 
497       String icon) throws URISyntaxException {
498     Chart chart = new Chart(id);
499     chart.setTitle(title);
500     chart.setBannerText(bannerText);
501     chart.setSuffixText(suffixLabel);
502     chart.setIcon(icon);
503     List<SeriesMetaData> smd = new ArrayList<SeriesMetaData>();
504     for (String metric : metrics) {
505       SeriesMetaData series = new SeriesMetaData();
506       series.setUrl(new URI("/hicc/v1/metrics/series/" + metric + "/" + source));
507       smd.add(series);
508     }
509     chart.setSeries(smd);
510     return createChart(chart);
511   }
512 
513   /**
514    * Create a chart in HBase.
515    * 
516    * @param chart is a chukwa Chart object
517    * @return id of newly created chart
518    */
519   public static synchronized String createChart(Chart chart) {
520     String id = chart.getId();
521     try {
522       getHBaseConnection();
523       if (id != null) {
524         // Check if there is existing chart with same id.
525         Chart test = getChart(id);
526         if (test != null) {
527           // If id already exists, randomly generate an id.
528           id = String.valueOf(UUID.randomUUID());
529         }
530       } else {
531         // If id is not provided, randomly generate an id.
532         id = String.valueOf(UUID.randomUUID());
533       }
534       chart.setId(id);
535       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
536       Put put = new Put(CHART_TYPE);
537       Gson gson = new Gson();
538       String buffer = gson.toJson(chart);
539       put.addColumn(CHART_FAMILY, id.getBytes(UTF8), buffer.getBytes(UTF8));
540       table.put(put);
541       table.close();
542     } catch (Exception e) {
543       closeHBase();
544       LOG.error(ExceptionUtil.getStackTrace(e));
545       id = null;
546     }
547     return id;
548   }
549 
550   /**
551    * Return data for multiple series of metrics stored in HBase.
552    * 
553    * @param series is SeriesMetaData object
554    * @param startTime sets the start time of metrics
555    * @param endTime sets the end time of metrics
556    * @return A list of Series meta data
557    */
558   public static synchronized ArrayList<org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData> getChartSeries(ArrayList<org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData> series, long startTime, long endTime) {
559     ArrayList<org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData> list = new ArrayList<org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData>();
560     try {
561       // Swap start and end if the values are inverted.
562       if (startTime > endTime) {
563         long temp = endTime;
564         startTime = endTime;
565         endTime = temp;
566       }
567       // Figure out the time range and determine the best resolution
568       // to fetch the data
569       long range = (endTime - startTime)
570         / (long) (MINUTES_IN_HOUR * MINUTE);
571       long sampleRate = 1;
572       if (range <= 1) {
573         sampleRate = 5;
574       } else if(range <= 24) {
575         sampleRate = 240;
576       } else if (range <= 720) {
577         sampleRate = 7200;
578       } else if(range >= 720) {
579         sampleRate = 87600;
580       }
581       double smoothing = (endTime - startTime)
582           / (double) (sampleRate * SECOND ) / (double) RESOLUTION;
583 
584       getHBaseConnection();
585       Table table = connection.getTable(TableName.valueOf(CHUKWA));
586       Scan scan = new Scan();
587       Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
588       c.setTimeInMillis(startTime);
589       int startDay = c.get(Calendar.DAY_OF_YEAR);
590       c.setTimeInMillis(endTime);
591       int endDay = c.get(Calendar.DAY_OF_YEAR);
592       for (org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData s : series) {
593         org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData clone = (org.apache.hadoop.chukwa.hicc.bean.SeriesMetaData) s.clone();
594         long currentDay = startTime;
595         String[] parts = s.getUrl().toString().split("/");
596         String metric = parts[5];
597         String source = parts[6];
598         ArrayList<ArrayList<Number>> data = new ArrayList<ArrayList<Number>>();
599         for (int i = startDay; i <= endDay; i++) {
600           byte[] rowKey = HBaseUtil.buildKey(currentDay, metric, source);
601           scan.addFamily(COLUMN_FAMILY);
602           scan.setStartRow(rowKey);
603           scan.setStopRow(rowKey);
604           scan.setTimeRange(startTime, endTime);
605           scan.setBatch(10000);
606 
607           ResultScanner results = table.getScanner(scan);
608           Iterator<Result> it = results.iterator();
609           double filteredValue = 0.0d;
610           long lastTime = startTime;
611           long totalElapsedTime = 0;
612           int initial = 0;
613           
614           while (it.hasNext()) {
615             Result result = it.next();
616             for (Cell kv : result.rawCells()) {
617               byte[] key = CellUtil.cloneQualifier(kv);
618               long timestamp = ByteBuffer.wrap(key).getLong();
619               double value = Double.parseDouble(new String(CellUtil.cloneValue(kv),
620                   UTF8));
621               if(initial==0) {
622                 filteredValue = value;
623               }
624               long elapsedTime = (timestamp - lastTime) / SECOND;
625               lastTime = timestamp;
626               // Determine if there is any gap, if there is gap in data, reset
627               // calculation.
628               if (elapsedTime > (sampleRate * 5)) {
629                 filteredValue = 0.0d;
630               } else {
631                 if (smoothing != 0.0d) {
632                   // Apply low pass filter to calculate
633                   filteredValue = filteredValue + (double) ((double) elapsedTime * (double) ((double) (value - filteredValue) / smoothing));
634                 } else {
635                   // Use original value
636                   filteredValue = value;
637                 }
638               }
639               totalElapsedTime = totalElapsedTime + elapsedTime;
640               if (totalElapsedTime >= sampleRate) {
641                 ArrayList<Number> points = new ArrayList<Number>();
642                 points.add(timestamp);
643                 points.add(filteredValue);
644                 data.add(points);
645                 totalElapsedTime = 0;
646               }
647             }
648             initial++;
649           }
650           results.close();
651           currentDay = currentDay + (i * MILLISECONDS_IN_DAY);
652         }
653         clone.setData(data);
654         list.add(clone);
655       }
656       table.close();
657     } catch (IOException|CloneNotSupportedException e) {
658       closeHBase();
659       LOG.error(ExceptionUtil.getStackTrace(e));
660     }
661     return list;
662   }
663 
664   /**
665    * List widgets stored in HBase.
666    * 
667    * @param limit sets the number of widgets to return
668    * @param offset sets the starting point to return widgets
669    * @return List of Widgets
670    */
671   public static synchronized List<Widget> listWidget(int limit, int offset) {
672     ArrayList<Widget> list = new ArrayList<Widget>();
673     try {
674       getHBaseConnection();
675       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
676       Scan scan = new Scan();
677       scan.setStartRow(WIDGET_TYPE);
678       scan.setStopRow(WIDGET_TYPE);
679       ResultScanner rs = table.getScanner(scan);
680       Iterator<Result> it = rs.iterator();
681       int c = 0;
682       while(it.hasNext()) {
683         Result result = it.next();
684         for(Cell kv : result.rawCells()) {
685           if(c > limit) {
686             break;
687           }
688           if(c < offset) {
689             continue;
690           }
691           Gson gson = new Gson();
692           Widget widget = gson.fromJson(new String(CellUtil.cloneValue(kv), UTF8), Widget.class);
693           list.add(widget);
694           c++;
695         }
696       }
697       rs.close();
698       table.close();
699     } catch (Exception e) {
700       closeHBase();
701       LOG.error(ExceptionUtil.getStackTrace(e));
702     }
703     return list;
704   }
705 
706   public static synchronized List<String> getData(ArrayList<SeriesMetaData> series, long startTime, long endTime) {
707     ArrayList<String> data = new ArrayList<String>();
708     try {
709       getHBaseConnection();
710       Table table = connection.getTable(TableName.valueOf(CHUKWA));
711       Scan scan = new Scan();
712       for(SeriesMetaData s : series) {
713         String snapshot = "";
714         String[] parts = s.getUrl().toString().split("/");
715         String metric = parts[5];
716         String source = parts[6];
717         long currentDay = startTime;
718         byte[] rowKey = HBaseUtil.buildKey(currentDay, metric, source);
719         scan.addFamily(COLUMN_FAMILY);
720         scan.setStartRow(rowKey);
721         scan.setStopRow(rowKey);
722         scan.setTimeRange(startTime, endTime);
723         scan.setBatch(10000);
724         ResultScanner rs = table.getScanner(scan);
725         Iterator<Result> it = rs.iterator();
726         while(it.hasNext()) {
727           Result result = it.next();
728           for(Cell kv : result.rawCells()) {
729             snapshot = new String(CellUtil.cloneValue(kv));
730             if(snapshot.matches("-?\\d+(\\.\\d+)?")) {
731               int endOffset = snapshot.length();
732               if(snapshot.length() - snapshot.indexOf(".") > 2) {
733                 endOffset = snapshot.indexOf(".") + 2;
734               }
735               snapshot = snapshot.substring(0, endOffset);
736             }
737           }
738         }
739         data.add(snapshot);
740         rs.close();
741       }
742       table.close();
743     } catch(Exception e) {
744       closeHBase();
745       LOG.error(ExceptionUtil.getStackTrace(e));
746     }
747     return data;
748   }
749 
750   /**
751    * Find widget by title prefix in HBase.
752    * 
753    * @param query is prefix query of widget title.
754    * @return List of Widgets
755    */
756   public static synchronized List<Widget> searchWidget(String query) {
757     ArrayList<Widget> list = new ArrayList<Widget>();
758     try {
759       getHBaseConnection();
760       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
761       Filter filter = new ColumnPrefixFilter(Bytes.toBytes(query));
762       Scan scan = new Scan();
763       scan.setStartRow(WIDGET_TYPE);
764       scan.setStopRow(WIDGET_TYPE);
765       scan.setFilter(filter);
766       ResultScanner rs = table.getScanner(scan);
767       Iterator<Result> it = rs.iterator();
768       while(it.hasNext()) {
769         Result result = it.next();
770         for(Cell kv : result.rawCells()) {
771           Gson gson = new Gson();
772           Widget widget = gson.fromJson(new String(CellUtil.cloneValue(kv), UTF8), Widget.class);
773           list.add(widget);
774         }
775       }
776       rs.close();
777       table.close();
778     } catch (Exception e) {
779       closeHBase();
780       LOG.error(ExceptionUtil.getStackTrace(e));
781     }
782     return list;
783   }
784 
785   /**
786    * View a widget information in HBase.
787    * 
788    * @param title is title of the widget.
789    * @return List of Widgets
790    */
791   public static synchronized Widget viewWidget(String title) {
792     Widget w = null;
793     try {
794       getHBaseConnection();
795       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
796       Get widget = new Get(WIDGET_TYPE);
797       widget.addColumn(COMMON_FAMILY, title.getBytes(UTF8));
798       Result rs = table.get(widget);
799       byte[] buffer = rs.getValue(COMMON_FAMILY, title.getBytes(UTF8));
800       Gson gson = new Gson();
801       w = gson.fromJson(new String(buffer, UTF8), Widget.class);
802       table.close();
803     } catch (Exception e) {
804       closeHBase();
805       LOG.error(ExceptionUtil.getStackTrace(e));
806     }
807     return w;
808   }
809 
810   /**
811    * Create a widget in HBase.
812    * 
813    * @param widget is chukwa Widget object
814    * @return true if widget is created
815    */
816   public static synchronized boolean createWidget(Widget widget) {
817     boolean created = false;
818     try {
819       widget.tokenize();
820       getHBaseConnection();
821       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
822       Get widgetTest = new Get(WIDGET_TYPE);
823       widgetTest.addColumn(COMMON_FAMILY, widget.getTitle().getBytes(UTF8));
824       if (table.exists(widgetTest)) {
825         LOG.warn("Widget: " + widget.getTitle() + " already exists.");
826         created = false;
827       } else {
828         Put put = new Put(WIDGET_TYPE);
829         Gson gson = new Gson();
830         String buffer = gson.toJson(widget);
831         put.addColumn(COMMON_FAMILY, widget.getTitle().getBytes(UTF8), buffer.getBytes(UTF8));
832         table.put(put);
833         created = true;
834       }
835       table.close();
836     } catch (Exception e) {
837       closeHBase();
838       LOG.error(ExceptionUtil.getStackTrace(e));
839     }
840     return created;
841   }
842 
843   /**
844    * Update a widget in HBase.
845    * 
846    * @param title is searchable title in a widget
847    * @param widget is Chukwa Widget object
848    * @return true if widget has been updated
849    */
850   public static synchronized boolean updateWidget(String title, Widget widget) {
851     boolean result = false;
852     try {
853       getHBaseConnection();
854       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
855       Delete oldWidget = new Delete(WIDGET_TYPE);
856       oldWidget.addColumn(COMMON_FAMILY, title.getBytes(UTF8));
857       table.delete(oldWidget);
858       Put put = new Put(WIDGET_TYPE);
859       Gson gson = new Gson();
860       String buffer = gson.toJson(widget);
861       put.addColumn(COMMON_FAMILY, title.getBytes(UTF8), buffer.getBytes(UTF8));
862       table.put(put);
863       table.close();
864       result = true;
865     } catch (Exception e) {
866       closeHBase();
867       LOG.error(ExceptionUtil.getStackTrace(e));
868       LOG.error("Error in updating widget, original title: " + 
869         title + " new title:" + widget.getTitle());
870     }
871     return result;
872   }
873 
874   /**
875    * Delete a widget in HBase.
876    * 
877    * @param title is searchable title in a widget
878    * @return true if widget has been deleted
879    */
880   public static synchronized boolean deleteWidget(String title) {
881     boolean result = false;
882     try {
883       getHBaseConnection();
884       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
885       Delete oldWidget = new Delete(WIDGET_TYPE);
886       oldWidget.addColumn(COMMON_FAMILY, title.getBytes(UTF8));
887       table.delete(oldWidget);
888       table.close();
889       result = true;
890     } catch (Exception e) {
891       closeHBase();
892       LOG.error(ExceptionUtil.getStackTrace(e));
893       LOG.error("Error in deleting widget: "+ title);
894     }
895     return result;
896   }
897 
898   public static boolean isDefaultExists() {
899     boolean exists = false;
900     try {
901       getHBaseConnection();
902       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
903       Get dashboardTest = new Get(DASHBOARD_TYPE);
904       dashboardTest.addColumn(COMMON_FAMILY, "default".getBytes(UTF8));
905       exists = table.exists(dashboardTest);
906       table.close();
907     } catch (Exception e) {
908       closeHBase();
909       LOG.error(ExceptionUtil.getStackTrace(e));
910     }
911     return exists;
912   }
913 
914   public static void populateDefaults() {
915     boolean defaultExists = isDefaultExists();
916     try {
917       if(defaultExists) {
918         return;
919       }
920       // Populate example chart widgets
921       createChart(Examples.SYSTEM_LOAD_AVERAGE);
922       createChart(Examples.CPU_UTILIZATION);
923       createChart(Examples.MEMORY_UTILIZATION);
924       createChart(Examples.DISK_UTILIZATION);
925       createChart(Examples.NETWORK_UTILIZATION);
926       createChart(Examples.SWAP_UTILIZATION);
927       
928       // Namenode heap usage
929       createChart(Examples.NAMENODE_MEMORY);
930       
931       // HDFS Usage
932       createChart(Examples.HDFS_USAGE);
933 
934       // Resource Manager Memory
935       createChart(Examples.RESOURCE_MANAGER_MEMORY);
936 
937       // Node Managers Health
938       createChart(Examples.NODE_MANAGER_HEALTH);
939 
940       // High Availability State
941       createChart(Examples.HDFS_HA);
942 
943       // HDFS Load
944       createChart(Examples.HDFS_LOAD);
945 
946       // Namenode RPC Latency
947       createChart(Examples.NAMENODE_RPC_LATENCY);
948 
949       // Datanode Health
950       createChart(Examples.DATANODES);
951 
952       // HBase Master Memory
953       createChart(Examples.HBASE_MASTER_MEMORY);
954 
955       // Populate default widgets
956       createWidget(Examples.SYSTEM_LOAD_AVERAGE_WIDGET);
957       createWidget(Examples.WELCOME_PAGE_WIDGET);
958       createWidget(Examples.TRIAL_DOWNLOAD_WIDGET);
959       createWidget(Examples.CLUSTER_RUNNING_WIDGET);
960       createWidget(Examples.USER_WORKING_WIDGET);
961       createWidget(Examples.APP_RUNNING_WIDGET);
962       createWidget(Examples.TRIAL_ABANDON_RATE_WIDGET);
963       createWidget(Examples.CLUSTERS_HEALTH_WIDGET);
964       createWidget(Examples.TOP_ACTIVE_CLUSTERS_WIDGET);
965       createWidget(Examples.TOP_APP_WIDGET);
966       
967       // User widgets
968       createWidget(Examples.APP_USAGE_WIDGET);
969       createWidget(Examples.QUICK_LINKS_WIDGET);
970       createWidget(Examples.LOG_SEARCH_WIDGET);
971       createWidget(Examples.YARN_APP_WIDGET);
972       createWidget(Examples.HDFS_WIDGET);
973       createWidget(Examples.HBASE_TABLE_WIDGET);
974       createWidget(Examples.TOP_USER_WIDGET);
975 
976       // System widgets
977       createWidget(Examples.HDFS_HA_STATE_WIDGET);
978       createWidget(Examples.HDFS_LOAD_WIDGET);
979       createWidget(Examples.HDFS_NAMENODE_LATENCY_WIDGET);
980       createWidget(Examples.DATANODES_HEALTH_WIDGET);
981       createWidget(Examples.NODE_MANAGERS_HEALTH_WIDGET);
982       createWidget(Examples.HDFS_REMAINING_WIDGET);
983       createWidget(Examples.NAMENODE_MEMORY_WIDGET);
984       createWidget(Examples.RESOURCE_MANAGER_MEMORY_WIDGET);
985       createWidget(Examples.HBASE_MASTER_MOMORY_WIDGET);
986       createWidget(Examples.CPU_UTILIZATION_WIDGET);
987       createWidget(Examples.MEMORY_UTILIZATION_WIDGET);
988       createWidget(Examples.SWAP_UTILIZATION_WIDGET);
989       createWidget(Examples.DISK_UTILIZATION_WIDGET);
990       createWidget(Examples.NETWORK_UTILIZATION_WIDGET);
991       createWidget(Examples.CPU_HEAPMAP_WIDGET);
992       createWidget(Examples.HDFS_UI_WIDGET);
993       createWidget(Examples.HBASE_MASTER_UI_WIDGET);
994       
995       // Populate default dashboard
996       updateDashboard("default", "", Examples.DEFAULT_DASHBOARD);
997       updateDashboard("user", "", Examples.USER_DASHBOARD);
998       updateDashboard("system", "", Examples.SYSTEM_DASHBOARD);
999     } catch (Throwable ex) {
1000       LOG.error(ExceptionUtil.getStackTrace(ex));
1001     }
1002   }
1003 
1004   public static synchronized Dashboard getDashboard(String id, String user) {
1005     Dashboard dash = null;
1006     String key = new StringBuilder().append(id).
1007         append("|").append(user).toString();
1008     try {
1009       getHBaseConnection();
1010       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
1011       Get dashboard = new Get(DASHBOARD_TYPE);
1012       dashboard.addColumn(COMMON_FAMILY, key.getBytes(UTF8));
1013       Result rs = table.get(dashboard);
1014       byte[] buffer = rs.getValue(COMMON_FAMILY, key.getBytes(UTF8));
1015       if(buffer == null) {
1016         // If user dashboard is not found, use default dashboard.
1017         key = new StringBuilder().append(id).append("|").toString();
1018         dashboard = new Get(DASHBOARD_TYPE);
1019         dashboard.addColumn(COMMON_FAMILY, key.getBytes(UTF8));
1020         rs = table.get(dashboard);
1021         buffer = rs.getValue(COMMON_FAMILY, key.getBytes(UTF8));        
1022       }
1023       Gson gson = new Gson();
1024       dash = gson.fromJson(new String(buffer, UTF8), Dashboard.class);
1025       table.close();
1026     } catch (Exception e) {
1027       closeHBase();
1028       LOG.error(ExceptionUtil.getStackTrace(e));
1029       LOG.error("Error retrieving dashboard, id: " + 
1030         id + " user:" + user);
1031     }
1032     return dash;
1033   }
1034 
1035   public static boolean updateDashboard(String id, String user, Dashboard dash) {
1036     boolean result = false;
1037     String key = new StringBuilder().append(id).
1038         append("|").append(user).toString();
1039     try {
1040       getHBaseConnection();
1041       Table table = connection.getTable(TableName.valueOf(CHUKWA_META));
1042       Put put = new Put(DASHBOARD_TYPE);
1043       Gson gson = new Gson();
1044       String buffer = gson.toJson(dash);
1045       put.addColumn(COMMON_FAMILY, key.getBytes(UTF8), buffer.getBytes(UTF8));
1046       table.put(put);
1047       table.close();
1048       result = true;
1049     } catch (Exception e) {
1050       closeHBase();
1051       LOG.error(ExceptionUtil.getStackTrace(e));
1052       LOG.error("Error in updating dashboard, id: " + 
1053         id + " user:" + user);
1054     }
1055     return result;
1056   }
1057 
1058 }