• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 namespace performance_monitor {
23 
24 struct 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 
33 class KeyBuilder;
34 class 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
99 class 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:
Clock()113     Clock() {}
~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 
GetEvents(const base::Time & start,const base::Time & end)137   EventVector GetEvents(const base::Time& start, const base::Time& end) {
138     return GetEvents(EVENT_UNDEFINED, start, end);
139   }
140 
GetEvents(EventType type)141   EventVector GetEvents(EventType type) {
142     return GetEvents(type, base::Time(), clock_->GetTime());
143   }
144 
GetEvents()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 
GetEventTypes()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 
AddMetric(const Metric & metric)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);
GetMaxStatsForActivityAndMetric(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 
GetRecentStatsForActivityAndMetric(MetricType metric_type,Metric * metric)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 
GetStatsForActivityAndMetric(MetricType metric_type,const base::Time & start,const base::Time & end)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 
GetStatsForActivityAndMetric(const std::string & activity,MetricType metric_type)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 
GetStatsForActivityAndMetric(MetricType metric_type)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 
GetStatsForMetricByActivity(MetricType metric_type)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 
path()232   base::FilePath path() const { return path_; }
233 
set_clock(scoped_ptr<Clock> clock)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:
SystemClock()247     SystemClock() {}
~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