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 WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
6#define WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
7
8#include <map>
9#include <set>
10#include <utility>
11
12#include "base/files/file_path.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/observer_list.h"
17#include "base/platform_file.h"
18#include "base/strings/string16.h"
19#include "base/strings/string_util.h"
20#include "base/time/time.h"
21#include "net/base/completion_callback.h"
22#include "webkit/browser/webkit_storage_browser_export.h"
23#include "webkit/common/database/database_connections.h"
24
25namespace base {
26class MessageLoopProxy;
27}
28
29namespace sql {
30class Connection;
31class MetaTable;
32}
33
34namespace quota {
35class QuotaManagerProxy;
36class SpecialStoragePolicy;
37}
38
39namespace webkit_database {
40
41WEBKIT_STORAGE_BROWSER_EXPORT extern const base::FilePath::CharType
42    kDatabaseDirectoryName[];
43WEBKIT_STORAGE_BROWSER_EXPORT extern const base::FilePath::CharType
44    kTrackerDatabaseFileName[];
45
46class DatabasesTable;
47
48// This class is used to store information about all databases in an origin.
49class WEBKIT_STORAGE_BROWSER_EXPORT OriginInfo {
50 public:
51  OriginInfo();
52  OriginInfo(const OriginInfo& origin_info);
53  ~OriginInfo();
54
55  const std::string& GetOriginIdentifier() const { return origin_identifier_; }
56  int64 TotalSize() const { return total_size_; }
57  void GetAllDatabaseNames(std::vector<base::string16>* databases) const;
58  int64 GetDatabaseSize(const base::string16& database_name) const;
59  base::string16 GetDatabaseDescription(
60      const base::string16& database_name) const;
61
62 protected:
63  typedef std::map<base::string16, std::pair<int64, base::string16> >
64      DatabaseInfoMap;
65
66  OriginInfo(const std::string& origin_identifier, int64 total_size);
67
68  std::string origin_identifier_;
69  int64 total_size_;
70  DatabaseInfoMap database_info_;
71};
72
73// This class manages the main database and keeps track of open databases.
74//
75// The data in this class is not thread-safe, so all methods of this class
76// should be called on the same thread. The only exceptions are the ctor(),
77// the dtor() and the database_directory() and quota_manager_proxy() getters.
78//
79// Furthermore, some methods of this class have to read/write data from/to
80// the disk. Therefore, in a multi-threaded application, all methods of this
81// class should be called on the thread dedicated to file operations (file
82// thread in the browser process, for example), if such a thread exists.
83class WEBKIT_STORAGE_BROWSER_EXPORT DatabaseTracker
84    : public base::RefCountedThreadSafe<DatabaseTracker> {
85 public:
86  class Observer {
87   public:
88    virtual void OnDatabaseSizeChanged(const std::string& origin_identifier,
89                                       const base::string16& database_name,
90                                       int64 database_size) = 0;
91    virtual void OnDatabaseScheduledForDeletion(
92        const std::string& origin_identifier,
93        const base::string16& database_name) = 0;
94
95   protected:
96    virtual ~Observer() {}
97  };
98
99  DatabaseTracker(const base::FilePath& profile_path,
100                  bool is_incognito,
101                  quota::SpecialStoragePolicy* special_storage_policy,
102                  quota::QuotaManagerProxy* quota_manager_proxy,
103                  base::MessageLoopProxy* db_tracker_thread);
104
105  void DatabaseOpened(const std::string& origin_identifier,
106                      const base::string16& database_name,
107                      const base::string16& database_details,
108                      int64 estimated_size,
109                      int64* database_size);
110  void DatabaseModified(const std::string& origin_identifier,
111                        const base::string16& database_name);
112  void DatabaseClosed(const std::string& origin_identifier,
113                      const base::string16& database_name);
114  void HandleSqliteError(const std::string& origin_identifier,
115                         const base::string16& database_name,
116                         int error);
117
118  void CloseDatabases(const DatabaseConnections& connections);
119
120  void AddObserver(Observer* observer);
121  void RemoveObserver(Observer* observer);
122
123  void CloseTrackerDatabaseAndClearCaches();
124
125  const base::FilePath& DatabaseDirectory() const { return db_dir_; }
126  base::FilePath GetFullDBFilePath(const std::string& origin_identifier,
127                                   const base::string16& database_name);
128
129  // virtual for unit-testing only
130  virtual bool GetOriginInfo(const std::string& origin_id, OriginInfo* info);
131  virtual bool GetAllOriginIdentifiers(std::vector<std::string>* origin_ids);
132  virtual bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info);
133
134  // Safe to call on any thread.
135  quota::QuotaManagerProxy* quota_manager_proxy() const {
136    return quota_manager_proxy_.get();
137  }
138
139  bool IsDatabaseScheduledForDeletion(const std::string& origin_identifier,
140                                      const base::string16& database_name);
141
142  // Deletes a single database. Returns net::OK on success, net::FAILED on
143  // failure, or net::ERR_IO_PENDING and |callback| is invoked upon completion,
144  // if non-NULL.
145  int DeleteDatabase(const std::string& origin_identifier,
146                     const base::string16& database_name,
147                     const net::CompletionCallback& callback);
148
149  // Delete any databases that have been touched since the cutoff date that's
150  // supplied, omitting any that match IDs within |protected_origins|.
151  // Returns net::OK on success, net::FAILED if not all databases could be
152  // deleted, and net::ERR_IO_PENDING and |callback| is invoked upon completion,
153  // if non-NULL. Protected origins, according the the SpecialStoragePolicy,
154  // are not deleted by this method.
155  int DeleteDataModifiedSince(const base::Time& cutoff,
156                              const net::CompletionCallback& callback);
157
158  // Delete all databases that belong to the given origin. Returns net::OK on
159  // success, net::FAILED if not all databases could be deleted, and
160  // net::ERR_IO_PENDING and |callback| is invoked upon completion, if non-NULL.
161  // virtual for unit testing only
162  virtual int DeleteDataForOrigin(const std::string& origin_identifier,
163                                  const net::CompletionCallback& callback);
164
165  bool IsIncognitoProfile() const { return is_incognito_; }
166
167  void GetIncognitoFileHandle(const base::string16& vfs_file_path,
168                              base::PlatformFile* file_handle) const;
169  void SaveIncognitoFileHandle(const base::string16& vfs_file_path,
170                               const base::PlatformFile& file_handle);
171  bool CloseIncognitoFileHandle(const base::string16& vfs_file_path);
172  bool HasSavedIncognitoFileHandle(const base::string16& vfs_file_path) const;
173
174  // Shutdown the database tracker, deleting database files if the tracker is
175  // used for an incognito profile.
176  void Shutdown();
177  // Disables the exit-time deletion of session-only data.
178  void SetForceKeepSessionState();
179
180 private:
181  friend class base::RefCountedThreadSafe<DatabaseTracker>;
182  friend class MockDatabaseTracker;  // for testing
183
184  typedef std::map<std::string, std::set<base::string16> > DatabaseSet;
185  typedef std::vector<std::pair<net::CompletionCallback, DatabaseSet> >
186      PendingDeletionCallbacks;
187  typedef std::map<base::string16, base::PlatformFile> FileHandlesMap;
188  typedef std::map<std::string, base::string16> OriginDirectoriesMap;
189
190  class CachedOriginInfo : public OriginInfo {
191   public:
192    CachedOriginInfo() : OriginInfo(std::string(), 0) {}
193    void SetOriginIdentifier(const std::string& origin_identifier) {
194      origin_identifier_ = origin_identifier;
195    }
196    void SetDatabaseSize(const base::string16& database_name, int64 new_size) {
197      int64 old_size = 0;
198      if (database_info_.find(database_name) != database_info_.end())
199        old_size = database_info_[database_name].first;
200      database_info_[database_name].first = new_size;
201      if (new_size != old_size)
202        total_size_ += new_size - old_size;
203    }
204    void SetDatabaseDescription(const base::string16& database_name,
205                                const base::string16& description) {
206      database_info_[database_name].second = description;
207    }
208  };
209
210  // virtual for unit-testing only.
211  virtual ~DatabaseTracker();
212
213  // Deletes the directory that stores all DBs in incognito mode, if it exists.
214  void DeleteIncognitoDBDirectory();
215
216  // Deletes session-only databases. Blocks databases from being created/opened.
217  void ClearSessionOnlyOrigins();
218
219  bool DeleteClosedDatabase(const std::string& origin_identifier,
220                            const base::string16& database_name);
221
222  // Delete all files belonging to the given origin given that no database
223  // connections within this origin are open, or if |force| is true, delete
224  // the meta data and rename the associated directory.
225  bool DeleteOrigin(const std::string& origin_identifier, bool force);
226  void DeleteDatabaseIfNeeded(const std::string& origin_identifier,
227                              const base::string16& database_name);
228
229  bool LazyInit();
230  bool UpgradeToCurrentVersion();
231  void InsertOrUpdateDatabaseDetails(const std::string& origin_identifier,
232                                     const base::string16& database_name,
233                                     const base::string16& database_details,
234                                     int64 estimated_size);
235
236  void ClearAllCachedOriginInfo();
237  CachedOriginInfo* MaybeGetCachedOriginInfo(
238      const std::string& origin_identifier,
239      bool create_if_needed);
240  CachedOriginInfo* GetCachedOriginInfo(
241      const std::string& origin_identifier) {
242    return MaybeGetCachedOriginInfo(origin_identifier, true);
243  }
244
245  int64 GetDBFileSize(const std::string& origin_identifier,
246                      const base::string16& database_name);
247  int64 SeedOpenDatabaseInfo(const std::string& origin_identifier,
248                             const base::string16& database_name,
249                             const base::string16& description);
250  int64 UpdateOpenDatabaseInfoAndNotify(const std::string& origin_identifier,
251                                        const base::string16& database_name,
252                                        const base::string16* opt_description);
253  int64 UpdateOpenDatabaseSizeAndNotify(const std::string& origin_identifier,
254                                        const base::string16& database_name) {
255    return UpdateOpenDatabaseInfoAndNotify(
256        origin_identifier, database_name, NULL);
257  }
258
259
260  void ScheduleDatabaseForDeletion(const std::string& origin_identifier,
261                                   const base::string16& database_name);
262  // Schedule a set of open databases for deletion. If non-null, callback is
263  // invoked upon completion.
264  void ScheduleDatabasesForDeletion(const DatabaseSet& databases,
265                                    const net::CompletionCallback& callback);
266
267  // Returns the directory where all DB files for the given origin are stored.
268  base::string16 GetOriginDirectory(const std::string& origin_identifier);
269
270  bool is_initialized_;
271  const bool is_incognito_;
272  bool force_keep_session_state_;
273  bool shutting_down_;
274  const base::FilePath profile_path_;
275  const base::FilePath db_dir_;
276  scoped_ptr<sql::Connection> db_;
277  scoped_ptr<DatabasesTable> databases_table_;
278  scoped_ptr<sql::MetaTable> meta_table_;
279  ObserverList<Observer, true> observers_;
280  std::map<std::string, CachedOriginInfo> origins_info_map_;
281  DatabaseConnections database_connections_;
282
283  // The set of databases that should be deleted but are still opened
284  DatabaseSet dbs_to_be_deleted_;
285  PendingDeletionCallbacks deletion_callbacks_;
286
287  // Apps and Extensions can have special rights.
288  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
289
290  scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
291
292  // The database tracker thread we're supposed to run file IO on.
293  scoped_refptr<base::MessageLoopProxy> db_tracker_thread_;
294
295  // When in incognito mode, store a DELETE_ON_CLOSE handle to each
296  // main DB and journal file that was accessed. When the incognito profile
297  // goes away (or when the browser crashes), all these handles will be
298  // closed, and the files will be deleted.
299  FileHandlesMap incognito_file_handles_;
300
301  // In a non-incognito profile, all DBs in an origin are stored in a directory
302  // named after the origin. In an incognito profile though, we do not want the
303  // directory structure to reveal the origins visited by the user (in case the
304  // browser process crashes and those directories are not deleted). So we use
305  // this map to assign directory names that do not reveal this information.
306  OriginDirectoriesMap incognito_origin_directories_;
307  int incognito_origin_directories_generator_;
308
309  FRIEND_TEST_ALL_PREFIXES(DatabaseTracker, TestHelper);
310};
311
312}  // namespace webkit_database
313
314#endif  // WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
315