1 // Copyright (c) 2014 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 CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_H_
6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <set>
12 #include <tuple>
13 #include <utility>
14 #include <vector>
15 
16 #include "base/callback.h"
17 #include "base/containers/flat_map.h"
18 #include "base/gtest_prod_util.h"
19 #include "base/macros.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/sequence_checker.h"
22 #include "base/strings/string16.h"
23 #include "base/time/clock.h"
24 #include "base/time/time.h"
25 #include "base/trace_event/memory_dump_provider.h"
26 #include "components/services/storage/indexed_db/scopes/leveldb_scopes_factory.h"
27 #include "components/services/storage/public/mojom/native_file_system_context.mojom-forward.h"
28 #include "content/browser/indexed_db/indexed_db_backing_store.h"
29 #include "content/browser/indexed_db/indexed_db_data_loss_info.h"
30 #include "content/browser/indexed_db/indexed_db_database_error.h"
31 #include "content/browser/indexed_db/indexed_db_factory.h"
32 #include "content/browser/indexed_db/indexed_db_origin_state_handle.h"
33 #include "content/browser/indexed_db/indexed_db_task_helper.h"
34 #include "storage/browser/blob/mojom/blob_storage_context.mojom-forward.h"
35 #include "third_party/leveldatabase/src/include/leveldb/status.h"
36 #include "url/origin.h"
37 
38 namespace base {
39 class FilePath;
40 class SequencedTaskRunner;
41 }
42 namespace url {
43 class Origin;
44 }
45 
46 namespace content {
47 class TransactionalLevelDBFactory;
48 class TransactionalLevelDBDatabase;
49 class IndexedDBClassFactory;
50 class IndexedDBContextImpl;
51 class IndexedDBFactoryImpl;
52 class IndexedDBOriginState;
53 
54 class CONTENT_EXPORT IndexedDBFactoryImpl
55     : public IndexedDBFactory,
56       base::trace_event::MemoryDumpProvider {
57  public:
58   IndexedDBFactoryImpl(IndexedDBContextImpl* context,
59                        IndexedDBClassFactory* indexed_db_class_factory,
60                        base::Clock* clock);
61   ~IndexedDBFactoryImpl() override;
62 
63   // content::IndexedDBFactory overrides:
64   void GetDatabaseInfo(scoped_refptr<IndexedDBCallbacks> callbacks,
65                        const url::Origin& origin,
66                        const base::FilePath& data_directory) override;
67   void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
68                         const url::Origin& origin,
69                         const base::FilePath& data_directory) override;
70   void Open(const base::string16& name,
71             std::unique_ptr<IndexedDBPendingConnection> connection,
72             const url::Origin& origin,
73             const base::FilePath& data_directory) override;
74 
75   void DeleteDatabase(const base::string16& name,
76                       scoped_refptr<IndexedDBCallbacks> callbacks,
77                       const url::Origin& origin,
78                       const base::FilePath& data_directory,
79                       bool force_close) override;
80 
81   void AbortTransactionsAndCompactDatabase(
82       base::OnceCallback<void(leveldb::Status)> callback,
83       const url::Origin& origin) override;
84   void AbortTransactionsForDatabase(
85       base::OnceCallback<void(leveldb::Status)> callback,
86       const url::Origin& origin) override;
87 
88   void HandleBackingStoreFailure(const url::Origin& origin) override;
89   void HandleBackingStoreCorruption(
90       const url::Origin& origin,
91       const IndexedDBDatabaseError& error) override;
92 
93   std::vector<IndexedDBDatabase*> GetOpenDatabasesForOrigin(
94       const url::Origin& origin) const override;
95 
96   // TODO(dmurph): This eventually needs to be async, to support scopes
97   // multithreading.
98   void ForceClose(const url::Origin& origin,
99                   bool delete_in_memory_store) override;
100 
101   void ForceSchemaDowngrade(const url::Origin& origin) override;
102   V2SchemaCorruptionStatus HasV2SchemaCorruption(
103       const url::Origin& origin) override;
104 
105   // Called by the IndexedDBContext destructor so the factory can do cleanup.
106   void ContextDestroyed() override;
107 
108   // Called by the IndexedDBActiveBlobRegistry.
109   void ReportOutstandingBlobs(const url::Origin& origin,
110                               bool blobs_outstanding) override;
111 
112   // Called by IndexedDBBackingStore when blob files have been cleaned.
113   void BlobFilesCleaned(const url::Origin& origin) override;
114 
115   size_t GetConnectionCount(const url::Origin& origin) const override;
116 
117   void NotifyIndexedDBContentChanged(
118       const url::Origin& origin,
119       const base::string16& database_name,
120       const base::string16& object_store_name) override;
121 
122   int64_t GetInMemoryDBSize(const url::Origin& origin) const override;
123 
124   base::Time GetLastModified(const url::Origin& origin) const override;
125 
126   std::vector<url::Origin> GetOpenOrigins() const;
127 
128   IndexedDBOriginState* GetOriginFactory(const url::Origin& origin) const;
129 
130   // On an OK status, the factory handle is populated. Otherwise (when status is
131   // not OK), the |IndexedDBDatabaseError| will be populated. If the status was
132   // corruption, the |IndexedDBDataLossInfo| will also be populated.
133   std::tuple<IndexedDBOriginStateHandle,
134              leveldb::Status,
135              IndexedDBDatabaseError,
136              IndexedDBDataLossInfo,
137              /*was_cold_open=*/bool>
138   GetOrOpenOriginFactory(const url::Origin& origin,
139                          const base::FilePath& data_directory,
140                          bool create_if_missing);
141 
142   void OnDatabaseError(const url::Origin& origin,
143                        leveldb::Status s,
144                        const char* message);
145 
146  protected:
147   // Used by unittests to allow subclassing of IndexedDBBackingStore.
148   virtual std::unique_ptr<IndexedDBBackingStore> CreateBackingStore(
149       IndexedDBBackingStore::Mode backing_store_mode,
150       TransactionalLevelDBFactory* leveldb_factory,
151       const url::Origin& origin,
152       const base::FilePath& blob_path,
153       std::unique_ptr<TransactionalLevelDBDatabase> db,
154       storage::mojom::BlobStorageContext* blob_storage_context,
155       storage::mojom::NativeFileSystemContext* native_file_system_context,
156       IndexedDBBackingStore::BlobFilesCleanedCallback blob_files_cleaned,
157       IndexedDBBackingStore::ReportOutstandingBlobsCallback
158           report_outstanding_blobs,
159       scoped_refptr<base::SequencedTaskRunner> idb_task_runner,
160       scoped_refptr<base::SequencedTaskRunner> io_task_runner);
161 
context()162   IndexedDBContextImpl* context() const { return context_; }
163 
164  private:
165   friend class IndexedDBBrowserTest;
166   friend class IndexedDBOriginState;
167 
168   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
169                            BackingStoreReleasedOnForcedClose);
170   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
171                            BackingStoreReleaseDelayedOnClose);
172   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, BackingStoreRunPreCloseTasks);
173   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
174                            BackingStoreCloseImmediatelySwitch);
175   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, BackingStoreNoSweeping);
176   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, DatabaseFailedOpen);
177   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
178                            DeleteDatabaseClosesBackingStore);
179   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
180                            ForceCloseReleasesBackingStore);
181   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
182                            GetDatabaseNamesClosesBackingStore);
183   FRIEND_TEST_ALL_PREFIXES(IndexedDBTest,
184                            ForceCloseOpenDatabasesOnCommitFailure);
185 
186   // |path_base| is the directory that will contain the database directory, the
187   // blob directory, and any data loss info. |database_path| is the directory
188   // for the leveldb database, and |blob_path| is the directory to store blob
189   // files. If |path_base| is empty, then an in-memory database is opened.
190   std::tuple<std::unique_ptr<IndexedDBBackingStore>,
191              leveldb::Status,
192              IndexedDBDataLossInfo,
193              bool /* is_disk_full */>
194   OpenAndVerifyIndexedDBBackingStore(const url::Origin& origin,
195                                      base::FilePath data_directory,
196                                      base::FilePath database_path,
197                                      base::FilePath blob_path,
198                                      LevelDBScopesOptions scopes_options,
199                                      LevelDBScopesFactory* scopes_factory,
200                                      bool is_first_attempt,
201                                      bool create_if_missing);
202 
203   void RemoveOriginState(const url::Origin& origin);
204 
205   // Called when the database has been deleted on disk.
206   void OnDatabaseDeleted(const url::Origin& origin);
207 
208   void MaybeRunTasksForOrigin(const url::Origin& origin);
209   void RunTasksForOrigin(base::WeakPtr<IndexedDBOriginState> origin_state);
210 
211   // Testing helpers, so unit tests don't need to grovel through internal
212   // state.
213   bool IsDatabaseOpen(const url::Origin& origin,
214                       const base::string16& name) const;
215   bool IsBackingStoreOpen(const url::Origin& origin) const;
216   bool IsBackingStorePendingClose(const url::Origin& origin) const;
217 
218   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
219                     base::trace_event::ProcessMemoryDump* pmd) override;
220 
221   SEQUENCE_CHECKER(sequence_checker_);
222   // Raw pointer is safe because IndexedDBContextImpl owns this object.
223   IndexedDBContextImpl* context_;
224   IndexedDBClassFactory* const class_factory_;
225   base::Clock* const clock_;
226   base::Time earliest_sweep_;
227 
228   base::flat_map<url::Origin, std::unique_ptr<IndexedDBOriginState>>
229       factories_per_origin_;
230 
231   std::set<url::Origin> backends_opened_since_startup_;
232 
233   // Weak pointers from this factory are used to bind the RemoveOriginState()
234   // function, which deletes the IndexedDBOriginState object. This allows those
235   // weak pointers to be invalidated during force close & shutdown to prevent
236   // re-entry (see ContextDestroyed()).
237   base::WeakPtrFactory<IndexedDBFactoryImpl>
238       origin_state_destruction_weak_factory_{this};
239   base::WeakPtrFactory<IndexedDBFactoryImpl> weak_factory_{this};
240   DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryImpl);
241 };
242 
243 }  // namespace content
244 
245 #endif  // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_H_
246