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