database.h revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_
6#define CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_
7
8#include <set>
9#include <string>
10#include <vector>
11
12#include "base/files/file_path.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/linked_ptr.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/time/time.h"
17#include "chrome/browser/performance_monitor/constants.h"
18#include "chrome/browser/performance_monitor/event.h"
19#include "chrome/browser/performance_monitor/metric.h"
20#include "third_party/leveldatabase/src/include/leveldb/db.h"
21
22namespace performance_monitor {
23
24struct TimeRange {
25  TimeRange();
26  TimeRange(base::Time start_time, base::Time end_time);
27  ~TimeRange();
28
29  base::Time start;
30  base::Time end;
31};
32
33class KeyBuilder;
34class DatabaseTestHelper;
35
36// The class supporting all performance monitor storage. This class wraps
37// multiple leveldb::DB objects. All methods must be called from a background
38// thread. Callers should use BrowserThread::PostBlockingPoolSequencedTask using
39// performance_monitor::kDBSequenceToken as the sequence token.
40//
41// Different schemas are used for the different leveldb::DB's based off of the
42// structure of the data and the common ways that it will need to be accessed.
43// The following specifies the schema of each type of leveldb::DB. Delimiters
44// are denoted with a '-'.
45//
46// State DB:
47// Stores information about the configuration or 'state' of the browser. Things
48// like browser version go in here.
49// Key: Unique Identifier
50// Value: State Value
51//
52// Active Interval DB:
53// Stores information about when there is data in the database. When the
54// database is constructed, the time is noted as the start of the active
55// interval. Then, every write operation the current time is marked as the end
56// of the current active interval. If the database has no write operations for
57// a certain amount of time, then the database is considered inactive for that
58// time period and a new start time is noted. Having the key be the beginning
59// of the active interval allows for efficient upserts to the current active
60// interval. If the end of the active interval was in the key, then every update
61// to the active interval would have to remove a key and insert a new one.
62// Key: Beginning of ActiveInterval
63// Value: End of ActiveInterval
64//
65// Event DB:
66// Stores all events. A time and type is enough to uniquely identify an event.
67// Using the time that the event took place as the beginning of the key allows
68// us to efficiently answer the question: "What are all the events that took
69// place in this time range?".
70// Key: Time - Type
71// Value: Event in JSON
72//
73// Recent DB:
74// Stores the most recent metric statistics to go into the database. There is
75// only ever one entry per (metric, activity) pair. |recent_map_| keeps an
76// in-memory version of this database with a mapping from a concatenation of
77// metric and activity to the key used in the recent db. |recent_map_| allows us
78// to quickly find the key that must be replaced in the recent db. This
79// database becomes useful when it is necessary to find all the active metrics
80// within a timerange. Without it, all the metric databases would need to be
81// searched to see if that metric is active.
82// Key: Time - Metric - Activity
83// Value: Statistic
84//
85// Max Value DB:
86// Stores the max metric statistics that have been inserted into the database.
87// There is only ever one entry per (metric, activity) pair. |max_value_map_|
88// keeps an in-memory version of this database with a mapping from a
89// concatenation of metric and activity to the max metric.
90// Key: Metric - Activity
91// Value: Statistic
92//
93// Metric DB:
94// Stores the statistics for different metrics. Having the time before the
95// activity ensures that the search space can only be as large as the time
96// interval.
97// Key: Metric - Time - Activity
98// Value: Statistic
99class Database {
100 public:
101  typedef std::set<EventType> EventTypeSet;
102  typedef std::vector<linked_ptr<Event> > EventVector;
103  typedef std::set<MetricType> MetricTypeSet;
104  typedef std::vector<Metric> MetricVector;
105  typedef std::map<std::string, linked_ptr<MetricVector> > MetricVectorMap;
106
107  static const char kDatabaseSequenceToken[];
108
109  // The class that the database will use to infer time. Abstracting out the
110  // time mechanism allows for easy testing and mock data insetion.
111  class Clock {
112   public:
113    Clock() {}
114    virtual ~Clock() {}
115    virtual base::Time GetTime() = 0;
116  };
117
118  virtual ~Database();
119
120  static scoped_ptr<Database> Create(base::FilePath path);
121
122  // A "state" value is anything that can only have one value at a time, and
123  // usually describes the state of the browser eg. version.
124  bool AddStateValue(const std::string& key, const std::string& value);
125
126  std::string GetStateValue(const std::string& key);
127
128  // Add an event to the database.
129  bool AddEvent(const Event& event);
130
131  // Retrieve the events from the database. These methods populate the provided
132  // vector, and will search on the given criteria.
133  EventVector GetEvents(EventType type,
134                        const base::Time& start,
135                        const base::Time& end);
136
137  EventVector GetEvents(const base::Time& start, const base::Time& end) {
138    return GetEvents(EVENT_UNDEFINED, start, end);
139  }
140
141  EventVector GetEvents(EventType type) {
142    return GetEvents(type, base::Time(), clock_->GetTime());
143  }
144
145  EventVector GetEvents() {
146    return GetEvents(EVENT_UNDEFINED, base::Time(), clock_->GetTime());
147  }
148
149  EventTypeSet GetEventTypes(const base::Time& start, const base::Time& end);
150
151  EventTypeSet GetEventTypes() {
152    return GetEventTypes(base::Time(), clock_->GetTime());
153  }
154
155  // Add a metric instance to the database.
156  bool AddMetric(const std::string& activity, const Metric& metric);
157
158  bool AddMetric(const Metric& metric) {
159    return AddMetric(kProcessChromeAggregate, metric);
160  }
161
162  // Get the metrics that are active for the given process between |start|
163  // (inclusive) and |end| (exclusive).
164  MetricTypeSet GetActiveMetrics(const base::Time& start,
165                                 const base::Time& end);
166
167  // Get the activities that are active for the given metric after |start|.
168  std::set<std::string> GetActiveActivities(MetricType metric_type,
169                                            const base::Time& start);
170
171  // Get the max value for the given metric in the db.
172  double GetMaxStatsForActivityAndMetric(const std::string& activity,
173                                         MetricType metric_type);
174  double GetMaxStatsForActivityAndMetric(MetricType metric_type) {
175    return GetMaxStatsForActivityAndMetric(kProcessChromeAggregate,
176                                           metric_type);
177  }
178
179  // Populate info with the most recent activity. Return false if populate
180  // was unsuccessful.
181  bool GetRecentStatsForActivityAndMetric(const std::string& activity,
182                                          MetricType metric_type,
183                                          Metric* metric);
184
185  bool GetRecentStatsForActivityAndMetric(MetricType metric_type,
186                                           Metric* metric) {
187    return GetRecentStatsForActivityAndMetric(kProcessChromeAggregate,
188                                              metric_type,
189                                              metric);
190  }
191
192  // Query given |metric_type| and |activity|.
193  scoped_ptr<MetricVector> GetStatsForActivityAndMetric(
194      const std::string& activity,
195      MetricType metric_type,
196      const base::Time& start,
197      const base::Time& end);
198
199  scoped_ptr<MetricVector> GetStatsForActivityAndMetric(
200      MetricType metric_type, const base::Time& start, const base::Time& end) {
201    return GetStatsForActivityAndMetric(kProcessChromeAggregate, metric_type,
202                                        start, end);
203  }
204
205  scoped_ptr<MetricVector> GetStatsForActivityAndMetric(
206      const std::string& activity, MetricType metric_type) {
207    return GetStatsForActivityAndMetric(activity, metric_type, base::Time(),
208                                        clock_->GetTime());
209  }
210
211  scoped_ptr<MetricVector> GetStatsForActivityAndMetric(
212      MetricType metric_type) {
213    return GetStatsForActivityAndMetric(kProcessChromeAggregate, metric_type,
214                                        base::Time(), clock_->GetTime());
215  }
216
217  // Query given |metric_type|. The returned map is keyed by activity.
218  MetricVectorMap GetStatsForMetricByActivity(MetricType metric_type,
219                                              const base::Time& start,
220                                              const base::Time& end);
221
222  MetricVectorMap GetStatsForMetricByActivity(MetricType metric_type) {
223    return GetStatsForMetricByActivity(
224        metric_type, base::Time(), clock_->GetTime());
225  }
226
227  // Returns the active time intervals that overlap with the time interval
228  // defined by |start| and |end|.
229  std::vector<TimeRange> GetActiveIntervals(const base::Time& start,
230                                            const base::Time& end);
231
232  base::FilePath path() const { return path_; }
233
234  void set_clock(scoped_ptr<Clock> clock) {
235    clock_ = clock.Pass();
236  }
237
238 private:
239  friend class DatabaseTestHelper;
240
241  typedef std::map<std::string, std::string> RecentMap;
242  typedef std::map<std::string, double> MaxValueMap;
243
244  // By default, the database uses a clock that simply returns the current time.
245  class SystemClock : public Clock {
246   public:
247    SystemClock() {}
248    virtual ~SystemClock() {}
249    virtual base::Time GetTime() OVERRIDE;
250  };
251
252  explicit Database(const base::FilePath& path);
253
254  bool InitDBs();
255
256  // Attempts to open a database, and tries to fix it if it is corrupt or
257  // damaged (if |fix_if_damaged| is true). Returns a scoped_ptr to the
258  // database on success, or NULL on failure.
259  scoped_ptr<leveldb::DB> SafelyOpenDatabase(
260      const leveldb::Options& options,
261      const std::string& path,
262      bool fix_if_damaged);
263
264  bool Close();
265
266  // Load recent info from the db into recent_map_.
267  void LoadRecents();
268  // Load max values from the db into the max_value_map_.
269  void LoadMaxValues();
270
271  // Mark the database as being active for the current time.
272  void UpdateActiveInterval();
273  // Updates the max_value_map_ and max_value_db_ if the value is greater than
274  // the current max value for the given activity and metric.
275  bool UpdateMaxValue(const std::string& activity,
276                      MetricType metric,
277                      const std::string& value);
278
279  scoped_ptr<KeyBuilder> key_builder_;
280
281  // A mapping of id,metric to the last inserted key for those parameters
282  // is maintained to prevent having to search through the recent db every
283  // insert.
284  RecentMap recent_map_;
285
286  MaxValueMap max_value_map_;
287
288  // The directory where all the databases will reside.
289  base::FilePath path_;
290
291  // The key for the beginning of the active interval.
292  std::string start_time_key_;
293
294  // The last time the database had a transaction.
295  base::Time last_update_time_;
296
297  scoped_ptr<Clock> clock_;
298
299  scoped_ptr<leveldb::DB> recent_db_;
300
301  scoped_ptr<leveldb::DB> max_value_db_;
302
303  scoped_ptr<leveldb::DB> state_db_;
304
305  scoped_ptr<leveldb::DB> active_interval_db_;
306
307  scoped_ptr<leveldb::DB> metric_db_;
308
309  scoped_ptr<leveldb::DB> event_db_;
310
311  leveldb::ReadOptions read_options_;
312  leveldb::WriteOptions write_options_;
313
314  // Indicates whether or not the database successfully initialized. If false,
315  // the Create() call will return NULL.
316  bool valid_;
317
318  DISALLOW_COPY_AND_ASSIGN(Database);
319};
320
321}  // namespace performance_monitor
322
323#endif  // CHROME_BROWSER_PERFORMANCE_MONITOR_DATABASE_H_
324