activity_database.h revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2013 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_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_DATABASE_H_
6#define CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_DATABASE_H_
7
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/files/file_path.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/ref_counted_memory.h"
15#include "base/synchronization/lock.h"
16#include "base/timer/timer.h"
17#include "chrome/browser/extensions/activity_log/activity_actions.h"
18#include "content/public/browser/browser_thread.h"
19#include "extensions/common/extension.h"
20#include "sql/connection.h"
21#include "sql/init_status.h"
22
23namespace base {
24class Clock;
25class FilePath;
26}
27
28namespace extensions {
29
30// Encapsulates the SQL connection for the activity log database.  This class
31// holds the database connection and has methods for writing.  All of the
32// methods except the constructor need to be called on the DB thread.
33//
34// Object ownership and lifetime is a bit complicated for ActivityLog,
35// ActivityLogPolicy, and ActivityDatabase:
36//
37//    ActivityLog ----> ActivityLogPolicy ----> ActivityDatabase
38//                         ^                               |
39//                         |                               |
40//                         \--(ActivityDatabase::Delegate)-/
41//
42// The ActivityLogPolicy object contains a pointer to the ActivityDatabase, and
43// the ActivityDatabase contains a pointer back to the ActivityLogPolicy object
44// (as an instance of ActivityDatabase::Delegate).
45//
46// Since some cleanup must happen on the database thread, deletion should occur
47// as follows:
48//   1. ActivityLog calls ActivityLogPolicy::Close()
49//   2. ActivityLogPolicy should call ActivityDatabase::Close() on the database
50//      thread.
51//   3. ActivityDatabase::Close() shuts down the database, then calls
52//      ActivityDatabase::Delegate::OnDatabaseClose().
53//   4. ActivityDatabase::Delegate::OnDatabaseClose() should delete the
54//      ActivityLogPolicy object.
55//   5. ActivityDatabase::Close() finishes running by deleting the
56//      ActivityDatabase object.
57//
58// (This assumes the common case that the ActivityLogPolicy uses an
59// ActivityDatabase and implements the ActivityDatabase::Delegate interface.
60// It is also possible for an ActivityLogPolicy to not use a database at all,
61// in which case ActivityLogPolicy::Close() should directly delete itself.)
62class ActivityDatabase {
63 public:
64  // Interface defining calls that the ActivityDatabase can make into a
65  // ActivityLogPolicy instance to implement policy-specific behavior.  Methods
66  // are always invoked on the database thread.  Classes other than
67  // ActivityDatabase should not call these methods.
68  class Delegate {
69   protected:
70    friend class ActivityDatabase;
71
72    // A Delegate is never directly deleted; it should instead delete itself
73    // after any final cleanup when OnDatabaseClose() is invoked.
74    virtual ~Delegate() {}
75
76    // Initializes the database schema; this gives a policy a chance to create
77    // or update database tables as needed.  Should return true on success.
78    // Will be called from within a database transaction.
79    virtual bool InitDatabase(sql::Connection* db) = 0;
80
81    // Requests that the policy flush any pending actions to the database.
82    // Should return true on success or false on a database error.  Will not be
83    // called from a transaction (the implementation may wish to use a
84    // transaction for the flush).
85    virtual bool FlushDatabase(sql::Connection* db) = 0;
86
87    // Called if the database encounters a permanent error; the policy should
88    // not expect to make any future writes to the database and may want to
89    // discard any queued data.
90    virtual void OnDatabaseFailure() = 0;
91
92    // Called by ActivityDatabase just before the ActivityDatabase object is
93    // deleted.  The database will make no further callbacks after invoking
94    // this method, so it is an appropriate time for the policy to delete
95    // itself.
96    virtual void OnDatabaseClose() = 0;
97  };
98
99  // Value to be passed to AdviseFlush below to force a database flush.
100  static const int kFlushImmediately = -1;
101
102  // Need to call Init to actually use the ActivityDatabase.  The Delegate
103  // provides hooks for an ActivityLogPolicy to control the database schema and
104  // reads/writes.
105  explicit ActivityDatabase(Delegate* delegate);
106
107  // Opens the DB.  This invokes OnDatabaseInit in the delegate to create or
108  // update the database schema if needed.
109  void Init(const base::FilePath& db_name);
110
111  // An ActivityLogPolicy should call this to kill the ActivityDatabase.
112  void Close();
113
114  // Inform the database that there may be additional data which could be
115  // written out.  The size parameter should indicate (approximately) how many
116  // records are queued to be written; the database may use this information to
117  // schedule a flush early if too much data is queueing up.  A value of
118  // kFlushImmediately will force an immediate call into
119  // Delegate::FlushDatabase(); otherwise, it is up to the database to
120  // determine when to flush.
121  void AdviseFlush(int size);
122
123  // Turns off batch I/O writing mode. This should only be used in unit tests,
124  // browser tests, or in our special --enable-extension-activity-log-testing
125  // policy state.
126  void SetBatchModeForTesting(bool batch_mode);
127
128  bool is_db_valid() const { return valid_db_; }
129
130  // A helper method for initializing or upgrading a database table.  The
131  // content_fields array should list the names of all of the columns in the
132  // database. The field_types should specify the types of the corresponding
133  // columns (e.g., INTEGER or LONGVARCHAR). There should be the same number of
134  // field_types as content_fields, since the two arrays should correspond.
135  static bool InitializeTable(sql::Connection* db,
136                              const char* table_name,
137                              const char* content_fields[],
138                              const char* field_types[],
139                              const int num_content_fields);
140
141  // Runs the given callback, passing it a handle to the database connection.
142  // If the database is not valid, the callback is run (to allow it to do any
143  // needed cleanup) but passed a NULL value.
144  void RunOnDatabase(const base::Callback<void(sql::Connection*)>& callback);
145
146 private:
147  // This should never be invoked by another class. Use Close() to order a
148  // suicide.
149  virtual ~ActivityDatabase();
150
151  // Used by the Init() method as a convenience for handling a failed database
152  // initialization attempt. Prints an error and puts us in the soft failure
153  // state.
154  void LogInitFailure();
155
156  // When we're in batched mode (which is on by default), we write to the db
157  // every X minutes instead of on every API call. This prevents the annoyance
158  // of writing to disk multiple times a second.
159  void RecordBatchedActions();
160
161  // If an error is unrecoverable or occurred while we were trying to close
162  // the database properly, we take "emergency" actions: break any outstanding
163  // transactions, raze the database, and close. When next opened, the
164  // database will be empty.
165  void HardFailureClose();
166
167  // Doesn't actually close the DB, but changes bools to prevent further writes
168  // or changes to it.
169  void SoftFailureClose();
170
171  // Handle errors in database writes. For a serious & permanent error, it
172  // invokes HardFailureClose(); for a less serious/permanent error, it invokes
173  // SoftFailureClose().
174  void DatabaseErrorCallback(int error, sql::Statement* stmt);
175
176  // For unit testing only.
177  void RecordBatchedActionsWhileTesting();
178  void SetTimerForTesting(int milliseconds);
179
180  // Retrieve a handle to the raw SQL database.  This is only intended to be
181  // used by ActivityLogDatabasePolicy::GetDatabaseConnection(), and should
182  // only be called on the database thread.
183  sql::Connection* GetSqlConnection();
184
185  // A reference a Delegate for policy-specific database behavior.  See the
186  // top-level comment for ActivityDatabase for comments on cleanup.
187  Delegate* delegate_;
188
189  sql::Connection db_;
190  bool valid_db_;
191  bool batch_mode_;
192  base::TimeDelta batching_period_;
193  base::RepeatingTimer<ActivityDatabase> timer_;
194  bool already_closed_;
195  bool did_init_;
196
197  friend class ActivityLogDatabasePolicy;
198  FRIEND_TEST_ALL_PREFIXES(ActivityDatabaseTest, BatchModeOff);
199  FRIEND_TEST_ALL_PREFIXES(ActivityDatabaseTest, BatchModeOn);
200  FRIEND_TEST_ALL_PREFIXES(ActivityDatabaseTest, BatchModeFlush);
201  DISALLOW_COPY_AND_ASSIGN(ActivityDatabase);
202};
203
204}  // namespace extensions
205#endif  // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_DATABASE_H_
206