1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_INDEXED_DB_INSTANCE_CONNECTION_H_
#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_CONNECTION_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h"
#include "components/services/storage/public/cpp/buckets/bucket_info.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "content/browser/indexed_db/instance/bucket_context_handle.h"
#include "content/browser/indexed_db/instance/database.h"
#include "content/browser/indexed_db/instance/transaction.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace blink {
class IndexedDBKeyRange;
}
namespace content::indexed_db {
class DatabaseCallbacks;
class DatabaseError;
class BucketContext;
// This class maps to an IDB database *connection*:
// https://www.w3.org/TR/IndexedDB/#database-connection
//
// It has a 1:1 relationship with the Blink class IDBDatabase.
//
// It is created and operated on a bucket thread.
class CONTENT_EXPORT Connection : public blink::mojom::IDBDatabase {
public:
// Transfers ownership of an existing `connection` instance to a self owned
// receiver. `Connection` instances begin life owned by a
// `unique_ptr` in a pending state without any bound mojo remotes. IndexedDB
// open database operations use this function to establish the connection
// after the database is ready for use.
static mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase>
MakeSelfOwnedReceiverAndBindRemote(std::unique_ptr<Connection> connection);
Connection(BucketContext& bucket_context,
base::WeakPtr<Database> database,
base::RepeatingClosure on_version_change_ignored,
base::OnceCallback<void(Connection*)> on_close,
std::unique_ptr<DatabaseCallbacks> callbacks,
mojo::Remote<storage::mojom::IndexedDBClientStateChecker>
client_state_checker,
base::UnguessableToken client_token,
int scheduling_priority);
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
~Connection() override;
base::WeakPtr<Connection> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
base::WeakPtr<Database> database() const { return database_; }
DatabaseCallbacks* callbacks() const { return callbacks_.get(); }
const base::UnguessableToken& client_token() const { return client_token_; }
const std::map<int64_t, std::unique_ptr<Transaction>>& transactions() const {
return transactions_;
}
// Unfortunately, for historical reasons, this version of `IsConnected()` is
// not the same as whether `this` is connected via Mojo.
bool IsConnected() const;
// Since `this` is a self-owned mojo receiver (see
// `MakeSelfOwnedReceiverAndBindRemote()`, this accessor is required to
// determine whether the mojo connection is inactive, which is synonymous with
// whether `this` is being destroyed.
bool is_shutting_down() const { return is_shutting_down_; }
int32_t id() const { return id_; }
Transaction* CreateVersionChangeTransaction(
int64_t id,
const std::set<int64_t>& scope,
std::unique_ptr<BackingStore::Transaction> backing_store_transaction);
// Checks if the client is in inactive state and disallow it from activation
// if so. This is called when the client is not supposed to be inactive,
// otherwise it may affect the IndexedDB service (e.g. blocking others from
// acquiring the locks).
void DisallowInactiveClient(
storage::mojom::DisallowInactiveClientReason reason,
base::OnceCallback<void(bool)> callback);
// We ignore calls where the id doesn't exist to facilitate the AbortAll call.
// TODO(dmurph): Change that so this doesn't need to ignore unknown ids.
void RemoveTransaction(int64_t id);
void AbortTransactionAndTearDownOnError(Transaction* transaction,
const DatabaseError& error);
void CloseAndReportForceClose(const std::string& message);
int scheduling_priority() const { return scheduling_priority_; }
// Returns true if `this_one` should skip ahead of `other` when being added to
// the lock manager/scheduler. Two lock requests (which can be associated with
// transactions or new connection requests) will never be reordered if they
// come from the same client (window/worker context).
static bool HasHigherPriorityThan(const PartitionedLockHolder* this_one,
const PartitionedLockHolder& other);
// Returns true if any of the connection's transactions is holding one of the
// lock IDs.
bool IsHoldingLocks(const std::vector<PartitionedLockId>& lock_ids) const;
private:
friend class TransactionTest;
FRIEND_TEST_ALL_PREFIXES(DatabaseTest, ForcedClose);
FRIEND_TEST_ALL_PREFIXES(DatabaseTest, PendingDelete);
FRIEND_TEST_ALL_PREFIXES(TransactionTest, PostedStartTaskRunAfterAbort);
// blink::mojom::IDBDatabase implementation
void RenameObjectStore(int64_t transaction_id,
int64_t object_store_id,
const std::u16string& new_name) override;
void CreateTransaction(
mojo::PendingAssociatedReceiver<blink::mojom::IDBTransaction>
transaction_receiver,
int64_t transaction_id,
const std::vector<int64_t>& object_store_ids,
blink::mojom::IDBTransactionMode mode,
blink::mojom::IDBTransactionDurability durability) override;
void VersionChangeIgnored() override;
void Get(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
blink::IndexedDBKeyRange key_range,
bool key_only,
blink::mojom::IDBDatabase::GetCallback callback) override;
void GetAll(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
blink::IndexedDBKeyRange key_range,
blink::mojom::IDBGetAllResultType result_type,
int64_t max_count,
blink::mojom::IDBCursorDirection direction,
blink::mojom::IDBDatabase::GetAllCallback callback) override;
void SetIndexKeys(int64_t transaction_id,
int64_t object_store_id,
blink::IndexedDBKey primary_key,
std::vector<blink::IndexedDBIndexKeys> index_keys) override;
void SetIndexesReady(int64_t transaction_id,
int64_t object_store_id,
const std::vector<int64_t>& index_ids) override;
void OpenCursor(
int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
blink::IndexedDBKeyRange key_range,
blink::mojom::IDBCursorDirection direction,
bool key_only,
blink::mojom::IDBTaskType task_type,
blink::mojom::IDBDatabase::OpenCursorCallback callback) override;
void Count(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
blink::IndexedDBKeyRange key_range,
CountCallback callback) override;
void DeleteRange(int64_t transaction_id,
int64_t object_store_id,
blink::IndexedDBKeyRange key_range,
DeleteRangeCallback success_callback) override;
void GetKeyGeneratorCurrentNumber(
int64_t transaction_id,
int64_t object_store_id,
GetKeyGeneratorCurrentNumberCallback callback) override;
void Clear(int64_t transaction_id,
int64_t object_store_id,
ClearCallback callback) override;
void CreateIndex(int64_t transaction_id,
int64_t object_store_id,
const blink::IndexedDBIndexMetadata& index) override;
void DeleteIndex(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id) override;
void RenameIndex(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
const std::u16string& new_name) override;
void Abort(int64_t transaction_id) override;
void DidBecomeInactive() override;
void UpdatePriority(int new_priority) override;
// It is an error to call either of these after `IsConnected()`
// is no longer true.
const storage::BucketInfo& GetBucketInfo();
storage::BucketLocator GetBucketLocator();
Transaction* GetTransaction(int64_t id) const;
enum class CloseErrorHandling {
// Returns from the function on the first encounter with an error.
kReturnOnFirstError,
// Continues to call Abort() on all transactions despite any errors.
// The last error encountered is returned.
kAbortAllReturnLastError,
};
// The return value is `callbacks_`, passing ownership.
std::unique_ptr<DatabaseCallbacks> AbortTransactionsAndClose(
CloseErrorHandling error_handling,
const std::string& message);
// Returns the last error that occurred, if there is any.
Status AbortAllTransactionsAndIgnoreErrors(const DatabaseError& error);
Status AbortAllTransactions(const DatabaseError& error);
BucketContext* bucket_context() {
return bucket_context_handle_.bucket_context();
}
const int32_t id_;
// Keeps the factory for this bucket alive.
BucketContextHandle bucket_context_handle_;
base::WeakPtr<Database> database_;
base::RepeatingClosure on_version_change_ignored_;
base::OnceCallback<void(Connection*)> on_close_;
// The connection owns transactions created on this connection. It's important
// to preserve ordering.
std::map<int64_t, std::unique_ptr<Transaction>> transactions_;
// The callbacks_ member is cleared when the connection is closed.
// May be nullptr in unit tests.
std::unique_ptr<DatabaseCallbacks> callbacks_;
mojo::Remote<storage::mojom::IndexedDBClientStateChecker>
client_state_checker_;
// TODO(381086791): Remove the per-reason split when the regression is fixed.
static constexpr size_t kNumKeepActiveReasons =
static_cast<size_t>(
storage::mojom::DisallowInactiveClientReason::kMaxValue) +
1;
std::array<mojo::RemoteSet<storage::mojom::IndexedDBClientKeepActive>,
kNumKeepActiveReasons>
client_keep_active_remotes_;
// Uniquely identifies the document or worker that owns the other side of this
// connection, i.e. the "client" of `client_state_checker_`. Since multiple
// transactions/connections associated with a single client should never cause
// that client to be ineligible for BFCache, this token is used to avoid
// unnecessary calls to `DisallowInactiveClient()`.
base::UnguessableToken client_token_;
SEQUENCE_CHECKER(sequence_checker_);
// The priority for transactions made on this connection. This corresponds to
// the renderer's scheduler throttling state. See `HasHigherPriorityThan()`
// for prioritization logic.
int scheduling_priority_;
bool is_shutting_down_ = false;
base::WeakPtrFactory<Connection> weak_factory_{this};
};
} // namespace content::indexed_db
#endif // CONTENT_BROWSER_INDEXED_DB_INSTANCE_CONNECTION_H_
|