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