1 // Copyright 2019 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_ORIGIN_STATE_H_
6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_ORIGIN_STATE_H_
7 
8 #include <stdint.h>
9 #include <memory>
10 
11 #include "base/callback.h"
12 #include "base/containers/flat_map.h"
13 #include "base/feature_list.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/sequence_checker.h"
16 #include "base/strings/string16.h"
17 #include "base/time/clock.h"
18 #include "base/timer/timer.h"
19 #include "components/services/storage/indexed_db/scopes/disjoint_range_lock_manager.h"
20 #include "content/browser/indexed_db/indexed_db_origin_state_handle.h"
21 #include "content/browser/indexed_db/indexed_db_task_helper.h"
22 #include "content/common/content_export.h"
23 #include "third_party/leveldatabase/src/include/leveldb/status.h"
24 #include "url/origin.h"
25 
26 namespace content {
27 class IndexedDBBackingStore;
28 class IndexedDBDatabase;
29 class IndexedDBFactoryImpl;
30 class IndexedDBPreCloseTaskQueue;
31 class TransactionalLevelDBFactory;
32 
33 constexpr const char kIDBCloseImmediatelySwitch[] = "idb-close-immediately";
34 
35 // This is an emergency kill switch to use with Finch if the feature needs to be
36 // shut off.
37 CONTENT_EXPORT extern const base::Feature kCompactIDBOnClose;
38 
39 // IndexedDBOriginState manages the per-origin IndexedDB state, and contains the
40 // backing store for the origin.
41 //
42 // This class is expected to manage its own lifetime by using the
43 // |destruct_myself_| closure, which is expected to destroy this object in the
44 // parent IndexedDBFactoryImpl (and remove it from any collections, etc).
45 // However, IndexedDBOriginState should still handle destruction without the use
46 // of that closure when the storage partition is destructed.
47 //
48 // IndexedDBOriginState will keep itself alive while:
49 // * There are handles referencing the factory,
50 // * There are outstanding blob references to this database's blob files, and
51 // * The factory is in an incognito profile.
52 class CONTENT_EXPORT IndexedDBOriginState {
53  public:
54   using TearDownCallback = base::RepeatingCallback<void(leveldb::Status)>;
55   using OriginDBMap =
56       base::flat_map<base::string16, std::unique_ptr<IndexedDBDatabase>>;
57 
58   // Maximum time interval between runs of the IndexedDBSweeper. Sweeping only
59   // occurs after backing store close.
60   // Visible for testing.
61   static constexpr const base::TimeDelta kMaxEarliestGlobalSweepFromNow =
62       base::TimeDelta::FromHours(1);
63   // Maximum time interval between runs of the IndexedDBSweeper for a given
64   // origin. Sweeping only occurs after backing store close.
65   // Visible for testing.
66   static constexpr const base::TimeDelta kMaxEarliestOriginSweepFromNow =
67       base::TimeDelta::FromDays(3);
68 
69   enum class ClosingState {
70     // IndexedDBOriginState isn't closing.
71     kNotClosing,
72     // IndexedDBOriginState is pausing for kBackingStoreGracePeriodSeconds
73     // to
74     // allow new references to open before closing the backing store.
75     kPreCloseGracePeriod,
76     // The |pre_close_task_queue| is running any pre-close tasks.
77     kRunningPreCloseTasks,
78     kClosed,
79   };
80 
81   // Calling |destruct_myself| should destruct this object.
82   // |earliest_global_sweep_time| is expected to outlive this object.
83   IndexedDBOriginState(
84       url::Origin origin,
85       bool persist_for_incognito,
86       base::Clock* clock,
87       TransactionalLevelDBFactory* transactional_leveldb_factory,
88       base::Time* earliest_global_sweep_time,
89       std::unique_ptr<DisjointRangeLockManager> lock_manager,
90       TasksAvailableCallback notify_tasks_callback,
91       TearDownCallback tear_down_callback,
92       std::unique_ptr<IndexedDBBackingStore> backing_store);
93   ~IndexedDBOriginState();
94 
95   void AbortAllTransactions(bool compact);
96 
97   void ForceClose();
98 
IsClosing()99   bool IsClosing() const {
100     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101     return closing_stage_ != ClosingState::kNotClosing;
102   }
103 
closing_stage()104   ClosingState closing_stage() const {
105     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
106     return closing_stage_;
107   }
108 
109   void ReportOutstandingBlobs(bool blobs_outstanding);
110 
111   void StopPersistingForIncognito();
112 
origin()113   const url::Origin& origin() { return origin_; }
backing_store()114   IndexedDBBackingStore* backing_store() {
115     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116     return backing_store_.get();
117   }
databases()118   const OriginDBMap& databases() const {
119     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120     return databases_;
121   }
lock_manager()122   DisjointRangeLockManager* lock_manager() {
123     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
124     return lock_manager_.get();
125   }
pre_close_task_queue()126   IndexedDBPreCloseTaskQueue* pre_close_task_queue() const {
127     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
128     return pre_close_task_queue_.get();
129   }
notify_tasks_callback()130   TasksAvailableCallback notify_tasks_callback() {
131     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
132     return notify_tasks_callback_;
133   }
134 
135   // Note: calling this callback will destroy the IndexedDBOriginState.
tear_down_callback()136   const TearDownCallback& tear_down_callback() { return tear_down_callback_; }
137 
is_running_tasks()138   bool is_running_tasks() const { return running_tasks_; }
is_task_run_scheduled()139   bool is_task_run_scheduled() const { return task_run_scheduled_; }
set_task_run_scheduled()140   void set_task_run_scheduled() { task_run_scheduled_ = true; }
141 
close_timer()142   base::OneShotTimer* close_timer() {
143     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
144     return &close_timer_;
145   }
146 
147   enum class RunTasksResult { kDone, kError, kCanBeDestroyed };
148   std::tuple<RunTasksResult, leveldb::Status> RunTasks();
149 
AsWeakPtr()150   base::WeakPtr<IndexedDBOriginState> AsWeakPtr() {
151     return weak_factory_.GetWeakPtr();
152   }
153 
154  private:
155   friend IndexedDBFactoryImpl;
156   friend IndexedDBOriginStateHandle;
157 
158   // Test needs access to ShouldRunTombstoneSweeper.
159   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTestWithMockTime,
160                            TombstoneSweeperTiming);
161 
162   // Test needs access to CompactionKillSwitchWorks.
163   FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, CompactionKillSwitchWorks);
164 
165   IndexedDBDatabase* AddDatabase(const base::string16& name,
166                                  std::unique_ptr<IndexedDBDatabase> database);
167 
168   // Returns a new handle to this factory. If this object was in its closing
169   // sequence, then that sequence will be halted by this call.
170   IndexedDBOriginStateHandle CreateHandle() WARN_UNUSED_RESULT;
171 
172   void OnHandleDestruction();
173 
174   // Returns true if this factory can be closed (no references, no blobs, and
175   // not persisting for incognito).
176   bool CanCloseFactory();
177 
178   void MaybeStartClosing();
179   void StartClosing();
180   void StartPreCloseTasks();
181 
182   // Executes database operations, and if |true| is returned by this function,
183   // then the current time will be written to the database as the last sweep
184   // time.
185   bool ShouldRunTombstoneSweeper();
186 
187   bool ShouldRunCompaction();
188 
189   SEQUENCE_CHECKER(sequence_checker_);
190 
191   url::Origin origin_;
192 
193   // True if this factory should be remain alive due to the storage partition
194   // being for incognito mode, and our backing store being in-memory. This is
195   // used as closing criteria for this object, see CanCloseFactory.
196   bool persist_for_incognito_;
197   // True if there are blobs referencing this backing store that are still
198   // alive. This is used as closing criteria for this object, see
199   // CanCloseFactory.
200   bool has_blobs_outstanding_ = false;
201   bool skip_closing_sequence_ = false;
202   base::Clock* const clock_;
203   TransactionalLevelDBFactory* const transactional_leveldb_factory_;
204 
205   bool running_tasks_ = false;
206   bool task_run_scheduled_ = false;
207 
208   // This is safe because it is owned by IndexedDBFactoryImpl, which owns this
209   // object.
210   base::Time* earliest_global_sweep_time_;
211   ClosingState closing_stage_ = ClosingState::kNotClosing;
212   base::OneShotTimer close_timer_;
213   const std::unique_ptr<DisjointRangeLockManager> lock_manager_;
214   std::unique_ptr<IndexedDBBackingStore> backing_store_;
215 
216   OriginDBMap databases_;
217   // This is the refcount for the number of IndexedDBOriginStateHandle's given
218   // out for this factory using OpenReference. This is used as closing
219   // criteria for this object, see CanCloseFactory.
220   int64_t open_handles_ = 0;
221 
222   std::unique_ptr<IndexedDBPreCloseTaskQueue> pre_close_task_queue_;
223 
224   TasksAvailableCallback notify_tasks_callback_;
225   TearDownCallback tear_down_callback_;
226 
227   base::WeakPtrFactory<IndexedDBOriginState> weak_factory_{this};
228 
229   DISALLOW_COPY_AND_ASSIGN(IndexedDBOriginState);
230 };
231 
232 }  // namespace content
233 
234 #endif  // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_ORIGIN_STATE_H_
235