Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 5 | #include "content/browser/indexed_db/instance/database.h" |
dcheng | 531cca9 | 2016-04-09 03:03:23 | [diff] [blame] | 6 | |
Chase Phillips | 93a43cd | 2019-03-22 17:15:52 | [diff] [blame] | 7 | #include <math.h> |
Evan Stade | 8707309 | 2024-01-12 03:53:23 | [diff] [blame] | 8 | |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 9 | #include <algorithm> |
Numfor Mbiziwo-Tiapo | 7baae9f | 2020-08-13 20:39:36 | [diff] [blame] | 10 | #include <cstddef> |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 11 | #include <cstdint> |
| 12 | #include <memory> |
| 13 | #include <optional> |
| 14 | #include <string> |
| 15 | #include <tuple> |
Chase Phillips | c07c4f39 | 2018-11-12 22:05:55 | [diff] [blame] | 16 | #include <utility> |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 17 | #include <vector> |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 18 | |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 19 | #include "base/check.h" |
| 20 | #include "base/check_op.h" |
Lei Zhang | de19767 | 2021-04-29 08:11:24 | [diff] [blame] | 21 | #include "base/containers/contains.h" |
Mingyu Lei | 2753e43 | 2023-01-13 13:48:42 | [diff] [blame] | 22 | #include "base/containers/flat_set.h" |
Evan Stade | b7741938 | 2025-03-17 09:24:23 | [diff] [blame] | 23 | #include "base/debug/dump_without_crashing.h" |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 24 | #include "base/functional/bind.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 25 | #include "base/functional/callback_forward.h" |
Mingyu Lei | 4b68337 | 2023-01-25 07:44:51 | [diff] [blame] | 26 | #include "base/functional/callback_helpers.h" |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 27 | #include "base/logging.h" |
Daniel Murphy | 7797b8c | 2019-03-07 00:08:44 | [diff] [blame] | 28 | #include "base/memory/weak_ptr.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 29 | #include "base/notreached.h" |
palakj | dbb2725 | 2016-06-09 19:01:24 | [diff] [blame] | 30 | #include "base/numerics/safe_conversions.h" |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 31 | #include "base/strings/stringprintf.h" |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 32 | #include "base/strings/utf_string_conversions.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 33 | #include "base/trace_event/trace_event.h" |
Evan Stade | 5808daf | 2025-05-21 21:41:33 | [diff] [blame] | 34 | #include "base/types/expected_macros.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 35 | #include "base/unguessable_token.h" |
Mingyu Lei | 2753e43 | 2023-01-13 13:48:42 | [diff] [blame] | 36 | #include "components/services/storage/indexed_db/locks/partitioned_lock_id.h" |
Nathan Memmott | aecdf345 | 2022-10-10 17:53:37 | [diff] [blame] | 37 | #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 38 | #include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 39 | #include "components/services/storage/privileged/mojom/indexed_db_internals_types.mojom.h" |
Marijn Kruisselbrink | a6d9daf | 2020-01-31 02:13:03 | [diff] [blame] | 40 | #include "content/browser/indexed_db/indexed_db_external_object.h" |
[email protected] | 120875f | 2014-03-19 23:08:52 | [diff] [blame] | 41 | #include "content/browser/indexed_db/indexed_db_value.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 42 | #include "content/browser/indexed_db/instance/backing_store.h" |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 43 | #include "content/browser/indexed_db/instance/bucket_context.h" |
| 44 | #include "content/browser/indexed_db/instance/bucket_context_handle.h" |
| 45 | #include "content/browser/indexed_db/instance/callback_helpers.h" |
| 46 | #include "content/browser/indexed_db/instance/connection.h" |
| 47 | #include "content/browser/indexed_db/instance/cursor.h" |
| 48 | #include "content/browser/indexed_db/instance/database_callbacks.h" |
| 49 | #include "content/browser/indexed_db/instance/factory_client.h" |
| 50 | #include "content/browser/indexed_db/instance/index_writer.h" |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 51 | #include "content/browser/indexed_db/instance/pending_connection.h" |
| 52 | #include "content/browser/indexed_db/instance/transaction.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 53 | #include "content/browser/indexed_db/status.h" |
Tom Sepez | 36c46c0 | 2025-07-11 21:43:56 | [diff] [blame] | 54 | #include "ipc/constants.mojom.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 55 | #include "mojo/public/cpp/bindings/associated_remote.h" |
| 56 | #include "mojo/public/cpp/bindings/pending_associated_receiver.h" |
| 57 | #include "mojo/public/cpp/bindings/pending_associated_remote.h" |
| 58 | #include "mojo/public/cpp/bindings/remote.h" |
Chase Phillips | 850b96f7 | 2018-08-24 19:44:16 | [diff] [blame] | 59 | #include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h" |
Chase Phillips | 33d161d6 | 2018-08-28 19:44:12 | [diff] [blame] | 60 | #include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h" |
| 61 | #include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h" |
Ari Chivukula | 30ca2ae | 2021-06-10 19:22:35 | [diff] [blame] | 62 | #include "third_party/blink/public/common/storage_key/storage_key.h" |
Henrique Ferreiro | da0a55c | 2019-11-12 14:06:04 | [diff] [blame] | 63 | #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h" |
[email protected] | 41db22974 | 2014-05-31 22:17:51 | [diff] [blame] | 64 | #include "third_party/leveldatabase/env_chromium.h" |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 65 | |
Chase Phillips | 33d161d6 | 2018-08-28 19:44:12 | [diff] [blame] | 66 | using blink::IndexedDBDatabaseMetadata; |
Chase Phillips | 68ecf551 | 2018-08-16 01:59:13 | [diff] [blame] | 67 | using blink::IndexedDBIndexKeys; |
Chase Phillips | 33d161d6 | 2018-08-28 19:44:12 | [diff] [blame] | 68 | using blink::IndexedDBIndexMetadata; |
Chase Phillips | 68ecf551 | 2018-08-16 01:59:13 | [diff] [blame] | 69 | using blink::IndexedDBKey; |
Chase Phillips | 850b96f7 | 2018-08-24 19:44:16 | [diff] [blame] | 70 | using blink::IndexedDBKeyPath; |
Chase Phillips | 33d161d6 | 2018-08-28 19:44:12 | [diff] [blame] | 71 | using blink::IndexedDBKeyRange; |
| 72 | using blink::IndexedDBObjectStoreMetadata; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 73 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 74 | namespace content::indexed_db { |
jsbell | a5dd3ef | 2015-04-23 00:24:19 | [diff] [blame] | 75 | namespace { |
| 76 | |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 77 | // `backing_store_db` can be null only if `mode` is VersionChange. |
| 78 | std::vector<PartitionedLockManager::PartitionedLockRequest> |
| 79 | BuildLockRequestsForLevelDb(const std::u16string& database_name, |
| 80 | const BackingStore::Database* backing_store_db, |
| 81 | blink::mojom::IDBTransactionMode mode, |
| 82 | const std::set<int64_t>& scope) { |
| 83 | // NB: LevelDB lock IDs are potentially persisted to disk - see |
| 84 | // `LevelDBPartitionedLock`. |
| 85 | const constexpr int kDatabaseLockPartition = 0; |
| 86 | PartitionedLockId database_lock_id{kDatabaseLockPartition, |
| 87 | base::UTF16ToUTF8(database_name)}; |
| 88 | if (mode == blink::mojom::IDBTransactionMode::VersionChange) { |
| 89 | return {{std::move(database_lock_id), |
| 90 | PartitionedLockManager::LockType::kExclusive}}; |
| 91 | } |
| 92 | CHECK(backing_store_db); |
| 93 | std::vector<PartitionedLockManager::PartitionedLockRequest> lock_requests; |
| 94 | lock_requests.reserve(1 + scope.size()); |
| 95 | lock_requests.emplace_back(std::move(database_lock_id), |
| 96 | PartitionedLockManager::LockType::kShared); |
| 97 | const constexpr int kObjectStoreLockPartition = 1; |
| 98 | const auto object_store_lock_type = |
| 99 | mode == blink::mojom::IDBTransactionMode::ReadOnly |
| 100 | ? PartitionedLockManager::LockType::kShared |
| 101 | : PartitionedLockManager::LockType::kExclusive; |
| 102 | for (int64_t object_store_id : scope) { |
| 103 | lock_requests.emplace_back( |
| 104 | PartitionedLockId{ |
| 105 | kObjectStoreLockPartition, |
| 106 | backing_store_db->GetObjectStoreLockIdKey(object_store_id)}, |
| 107 | object_store_lock_type); |
| 108 | } |
| 109 | return lock_requests; |
| 110 | } |
| 111 | |
| 112 | std::vector<PartitionedLockManager::PartitionedLockRequest> |
| 113 | BuildLockRequestsForSqlite(uint32_t database_id, |
| 114 | blink::mojom::IDBTransactionMode mode, |
| 115 | const std::set<int64_t>& scope) { |
| 116 | // TODO(crbug.com/427608926): Refactor `PartitionedLockId` to not need `key` |
| 117 | // to be a string. |
| 118 | const constexpr int kMetadataLockPartition = 0; |
| 119 | PartitionedLockId metadata_lock_id{kMetadataLockPartition, |
| 120 | base::StringPrintf("%u", database_id)}; |
| 121 | if (mode == blink::mojom::IDBTransactionMode::VersionChange) { |
| 122 | return {{std::move(metadata_lock_id), |
| 123 | PartitionedLockManager::LockType::kExclusive}}; |
| 124 | } |
| 125 | std::vector<PartitionedLockManager::PartitionedLockRequest> lock_requests{ |
| 126 | {std::move(metadata_lock_id), PartitionedLockManager::LockType::kShared}}; |
| 127 | if (mode == blink::mojom::IDBTransactionMode::ReadWrite) { |
| 128 | const constexpr int kWriteOperationsLockPartition = 1; |
| 129 | lock_requests.emplace_back( |
| 130 | PartitionedLockId{kWriteOperationsLockPartition, |
| 131 | base::StringPrintf("%u", database_id)}, |
| 132 | PartitionedLockManager::LockType::kExclusive); |
| 133 | } |
| 134 | lock_requests.reserve(lock_requests.size() + scope.size()); |
| 135 | const constexpr int kObjectStoreLockPartition = 2; |
| 136 | const auto object_store_lock_type = |
| 137 | mode == blink::mojom::IDBTransactionMode::ReadOnly |
| 138 | ? PartitionedLockManager::LockType::kShared |
| 139 | : PartitionedLockManager::LockType::kExclusive; |
| 140 | for (int64_t object_store_id : scope) { |
| 141 | lock_requests.emplace_back( |
| 142 | PartitionedLockId{ |
| 143 | kObjectStoreLockPartition, |
| 144 | base::StringPrintf("%u|%lld", database_id, object_store_id)}, |
| 145 | object_store_lock_type); |
| 146 | } |
| 147 | return lock_requests; |
| 148 | } |
Evan Stade | e24c007 | 2025-06-18 18:29:17 | [diff] [blame] | 149 | |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 150 | // Values returned to the IDB client may contain a primary key value generated |
| 151 | // by IDB. This is optional and only done when using a key generator. This key |
| 152 | // value cannot (at least easily) be amended to the object being written to the |
| 153 | // database, so they are kept separately, and sent back with the original data |
| 154 | // so that the render process can amend the returned object. |
| 155 | blink::mojom::IDBReturnValuePtr ConvertValueToReturnValue( |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 156 | Transaction& transaction, |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 157 | IndexedDBValue value, |
| 158 | blink::IndexedDBKey primary_key, |
| 159 | blink::IndexedDBKeyPath key_path) { |
| 160 | auto mojo_value = blink::mojom::IDBReturnValue::New(); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 161 | if (primary_key.IsValid()) { |
| 162 | mojo_value->primary_key = std::move(primary_key); |
| 163 | mojo_value->key_path = std::move(key_path); |
| 164 | } |
Evan Stade | 2bc92e8 | 2025-06-04 19:07:36 | [diff] [blame] | 165 | mojo_value->value = transaction.BuildMojoValue(std::move(value)); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 166 | return mojo_value; |
| 167 | } |
| 168 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 169 | // Returns an `IDBReturnValuePtr` created from the cursor's current position. |
| 170 | blink::mojom::IDBReturnValuePtr ExtractReturnValueFromCursorValue( |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 171 | Transaction& transaction, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 172 | const IndexedDBObjectStoreMetadata& object_store_metadata, |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 173 | BackingStore::Cursor& cursor) { |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 174 | IndexedDBValue value(std::move(cursor.GetValue())); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 175 | |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 176 | const bool is_generated_key = !value.empty() && |
| 177 | object_store_metadata.auto_increment && |
| 178 | !object_store_metadata.key_path.IsNull(); |
| 179 | blink::IndexedDBKey primary_key; |
| 180 | blink::IndexedDBKeyPath key_path; |
| 181 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 182 | if (is_generated_key) { |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 183 | primary_key = cursor.GetPrimaryKey().Clone(); |
| 184 | key_path = object_store_metadata.key_path; |
Adrienne Walker | 7c30dd6 | 2020-07-27 11:00:06 | [diff] [blame] | 185 | } |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 186 | |
Evan Stade | 2bc92e8 | 2025-06-04 19:07:36 | [diff] [blame] | 187 | return ConvertValueToReturnValue(transaction, std::move(value), |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 188 | std::move(primary_key), std::move(key_path)); |
Adrienne Walker | 7c30dd6 | 2020-07-27 11:00:06 | [diff] [blame] | 189 | } |
| 190 | |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 191 | blink::mojom::IDBErrorPtr CreateIDBErrorPtr(blink::mojom::IDBException code, |
| 192 | const std::string& message, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 193 | Transaction* transaction) { |
Chase Phillips | 2da03875 | 2019-05-22 23:32:36 | [diff] [blame] | 194 | transaction->IncrementNumErrorsSent(); |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 195 | return blink::mojom::IDBError::New(code, base::UTF8ToUTF16(message)); |
Chase Phillips | 2da03875 | 2019-05-22 23:32:36 | [diff] [blame] | 196 | } |
| 197 | |
jsbell | a5dd3ef | 2015-04-23 00:24:19 | [diff] [blame] | 198 | } // namespace |
| 199 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 200 | Database::OpenCursorOperationParams::OpenCursorOperationParams() = default; |
| 201 | Database::OpenCursorOperationParams::~OpenCursorOperationParams() = default; |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 202 | |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 203 | Database::Database(uint32_t id_for_locks, |
| 204 | const std::u16string& name, |
| 205 | BucketContext& bucket_context) |
| 206 | : id_for_locks_(id_for_locks), |
Evan Stade | e24c007 | 2025-06-18 18:29:17 | [diff] [blame] | 207 | name_(name), |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 208 | bucket_context_(bucket_context), |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 209 | connection_coordinator_(this, bucket_context) {} |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 210 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 211 | Database::~Database() = default; |
Daniel Murphy | 4c0f9c1 | 2019-05-23 01:14:35 | [diff] [blame] | 212 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 213 | BackingStore* Database::backing_store() { |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 214 | return bucket_context_->backing_store(); |
| 215 | } |
| 216 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 217 | PartitionedLockManager& Database::lock_manager() { |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 218 | return bucket_context_->lock_manager(); |
| 219 | } |
| 220 | |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 221 | int64_t Database::version() const { |
| 222 | return backing_store_db_ ? metadata().version |
| 223 | : blink::IndexedDBDatabaseMetadata::NO_VERSION; |
| 224 | } |
| 225 | |
| 226 | bool Database::IsInitialized() const { |
| 227 | return backing_store_db_ != nullptr; |
| 228 | } |
| 229 | |
Evan Stade | e2a6816 | 2025-07-08 17:22:54 | [diff] [blame] | 230 | StatusOr<int64_t> Database::DeleteDatabase(std::vector<PartitionedLock> locks, |
| 231 | base::OnceClosure on_complete) { |
| 232 | if (!backing_store_db_) { |
| 233 | return blink::IndexedDBDatabaseMetadata::DEFAULT_VERSION; |
| 234 | } |
| 235 | |
| 236 | const int64_t old_version = version(); |
| 237 | Status s = backing_store_db_->DeleteDatabase(std::move(locks), |
| 238 | std::move(on_complete)); |
| 239 | backing_store_db_.reset(); |
| 240 | if (!s.ok()) { |
| 241 | return base::unexpected(s); |
| 242 | } |
| 243 | return old_version; |
| 244 | } |
| 245 | |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 246 | std::vector<PartitionedLockManager::PartitionedLockRequest> |
| 247 | Database::BuildLockRequestsForTransaction( |
| 248 | blink::mojom::IDBTransactionMode mode, |
| 249 | const std::set<int64_t>& scope) const { |
| 250 | return bucket_context_->ShouldUseSqlite() |
| 251 | ? BuildLockRequestsForSqlite(id_for_locks_, mode, scope) |
| 252 | : BuildLockRequestsForLevelDb(name_, backing_store_db_.get(), mode, |
| 253 | scope); |
| 254 | } |
| 255 | |
Evan Stade | 8c6ddfd | 2025-01-06 17:41:10 | [diff] [blame] | 256 | bool Database::OnlyHasOneClient() const { |
| 257 | if (connections_.empty()) { |
| 258 | return true; |
| 259 | } |
| 260 | |
| 261 | const base::UnguessableToken& token = (*connections_.begin())->client_token(); |
| 262 | return std::all_of(connections_.begin(), connections_.end(), |
| 263 | [&token](Connection* connection) { |
| 264 | return connection->client_token() == token; |
| 265 | }); |
| 266 | } |
| 267 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 268 | void Database::RequireBlockingTransactionClientsToBeActive( |
| 269 | Transaction* current_transaction, |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 270 | std::vector<PartitionedLockManager::PartitionedLockRequest>& |
| 271 | lock_requests) { |
Evan Stade | 8c6ddfd | 2025-01-06 17:41:10 | [diff] [blame] | 272 | if (OnlyHasOneClient()) { |
| 273 | return; |
| 274 | } |
| 275 | |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 276 | std::vector<PartitionedLockId> blocked_lock_ids = |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 277 | lock_manager().GetUnacquirableLocks(lock_requests); |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 278 | |
| 279 | if (blocked_lock_ids.empty()) { |
| 280 | return; |
| 281 | } |
| 282 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 283 | for (Connection* connection : connections_) { |
Abhishek Shanthkumar | 0d9abbe3 | 2024-06-07 01:28:00 | [diff] [blame] | 284 | if (connection->client_token() == |
| 285 | current_transaction->connection()->client_token()) { |
Evan Stade | 2db7aa7 | 2024-02-01 17:07:27 | [diff] [blame] | 286 | continue; |
| 287 | } |
| 288 | |
Evan Stade | 8707309 | 2024-01-12 03:53:23 | [diff] [blame] | 289 | // If any of the connection's transactions is holding one of the blocked |
| 290 | // lock IDs, require that client to be active. |
Patrick Monette | d32aa3d | 2024-11-13 21:12:31 | [diff] [blame] | 291 | if (connection->IsHoldingLocks(blocked_lock_ids)) { |
Mingyu Lei | 4b68337 | 2023-01-25 07:44:51 | [diff] [blame] | 292 | connection->DisallowInactiveClient( |
| 293 | storage::mojom::DisallowInactiveClientReason:: |
Evan Stade | 2db7aa7 | 2024-02-01 17:07:27 | [diff] [blame] | 294 | kTransactionIsAcquiringLocks, |
Mingyu Lei | 2768295 | 2023-05-04 08:13:21 | [diff] [blame] | 295 | base::DoNothing()); |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 296 | } |
| 297 | } |
| 298 | } |
| 299 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 300 | void Database::RegisterAndScheduleTransaction(Transaction* transaction) { |
| 301 | TRACE_EVENT1("IndexedDB", "Database::RegisterAndScheduleTransaction", |
Mingyu Lei | 2753e43 | 2023-01-13 13:48:42 | [diff] [blame] | 302 | "txn.id", transaction->id()); |
Evan Stade | 8707309 | 2024-01-12 03:53:23 | [diff] [blame] | 303 | // Locks for version change transactions are covered by `ConnectionRequest`. |
| 304 | DCHECK_NE(transaction->mode(), |
| 305 | blink::mojom::IDBTransactionMode::VersionChange); |
Mingyu Lei | 2753e43 | 2023-01-13 13:48:42 | [diff] [blame] | 306 | std::vector<PartitionedLockManager::PartitionedLockRequest> lock_requests = |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 307 | BuildLockRequestsForTransaction(transaction->mode(), |
| 308 | transaction->scope()); |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 309 | |
Mingyu Lei | ac9bde4 | 2023-06-22 09:56:24 | [diff] [blame] | 310 | RequireBlockingTransactionClientsToBeActive(transaction, lock_requests); |
Mingyu Lei | 5cff96b | 2023-01-13 17:09:51 | [diff] [blame] | 311 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 312 | lock_manager().AcquireLocks( |
Evan Stade | d9055a7 | 2024-08-22 23:11:27 | [diff] [blame] | 313 | std::move(lock_requests), *transaction->mutable_locks_receiver(), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 314 | base::BindOnce(&Transaction::Start, transaction->AsWeakPtr()), |
| 315 | base::BindRepeating(&Connection::HasHigherPriorityThan, |
Evan Stade | 8e75d40 | 2024-09-04 00:42:43 | [diff] [blame] | 316 | transaction->mutable_locks_receiver())); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 317 | } |
| 318 | |
Evan Stade | 4c8bfd6 | 2025-05-08 15:52:36 | [diff] [blame] | 319 | Status Database::RunTasks() { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 320 | // First execute any pending tasks in the connection coordinator. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 321 | ConnectionCoordinator::ExecuteTaskResult task_state; |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 322 | Status status; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 323 | do { |
| 324 | std::tie(task_state, status) = |
| 325 | connection_coordinator_.ExecuteTask(!connections_.empty()); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 326 | } while (task_state == ConnectionCoordinator::ExecuteTaskResult::kMoreTasks); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 327 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 328 | if (task_state == ConnectionCoordinator::ExecuteTaskResult::kError) { |
Evan Stade | 4c8bfd6 | 2025-05-08 15:52:36 | [diff] [blame] | 329 | CHECK(!status.ok()); |
| 330 | return status; |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 331 | } |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 332 | |
| 333 | bool transactions_removed = true; |
| 334 | |
| 335 | // Finally, execute transactions that have tasks & remove those that are |
| 336 | // complete. |
| 337 | while (transactions_removed) { |
| 338 | transactions_removed = false; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 339 | Transaction* finished_upgrade_transaction = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 340 | bool upgrade_transaction_commmitted = false; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 341 | for (Connection* connection : connections_) { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 342 | std::vector<int64_t> txns_to_remove; |
| 343 | for (const auto& id_txn_pair : connection->transactions()) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 344 | Transaction* txn = id_txn_pair.second.get(); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 345 | // Determine if the transaction's task queue should be processed. |
| 346 | switch (txn->state()) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 347 | case Transaction::FINISHED: |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 348 | if (txn->mode() == |
| 349 | blink::mojom::IDBTransactionMode::VersionChange) { |
| 350 | finished_upgrade_transaction = txn; |
| 351 | upgrade_transaction_commmitted = !txn->aborted(); |
| 352 | } |
| 353 | txns_to_remove.push_back(id_txn_pair.first); |
| 354 | continue; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 355 | case Transaction::CREATED: |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 356 | continue; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 357 | case Transaction::STARTED: |
| 358 | case Transaction::COMMITTING: |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 359 | break; |
| 360 | } |
| 361 | |
| 362 | // Process the queue for transactions that are STARTED or COMMITTING. |
| 363 | // Add transactions that can be removed to a queue. |
Evan Stade | 630ca5c4 | 2025-08-14 15:10:27 | [diff] [blame] | 364 | StatusOr<Transaction::RunTasksResult> task_result = txn->RunTasks(); |
| 365 | if (!task_result.has_value()) { |
| 366 | return task_result.error(); |
| 367 | } |
| 368 | |
| 369 | switch (task_result.value()) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 370 | case Transaction::RunTasksResult::kCommitted: |
| 371 | case Transaction::RunTasksResult::kAborted: |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 372 | if (txn->mode() == |
| 373 | blink::mojom::IDBTransactionMode::VersionChange) { |
| 374 | DCHECK(!finished_upgrade_transaction); |
| 375 | finished_upgrade_transaction = txn; |
| 376 | upgrade_transaction_commmitted = !txn->aborted(); |
| 377 | } |
| 378 | txns_to_remove.push_back(txn->id()); |
| 379 | break; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 380 | case Transaction::RunTasksResult::kNotFinished: |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 381 | continue; |
| 382 | } |
| 383 | } |
| 384 | // Do the removals. |
| 385 | for (int64_t id : txns_to_remove) { |
| 386 | connection->RemoveTransaction(id); |
| 387 | transactions_removed = true; |
| 388 | } |
| 389 | if (finished_upgrade_transaction) { |
| 390 | connection_coordinator_.OnUpgradeTransactionFinished( |
| 391 | upgrade_transaction_commmitted); |
| 392 | } |
| 393 | } |
| 394 | } |
Evan Stade | 4c8bfd6 | 2025-05-08 15:52:36 | [diff] [blame] | 395 | return Status::OK(); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 396 | } |
| 397 | |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 398 | Status Database::ForceCloseAndRunTasks(const std::string& message) { |
Evan Stade | 6b4d5a6 | 2025-05-29 20:53:53 | [diff] [blame] | 399 | if (!bucket_context_->ShouldUseSqlite()) { |
| 400 | DCHECK(!force_closing_); |
| 401 | } else if (force_closing_) { |
| 402 | // Re-entrancy can validly occur if there's an error in the code below, |
| 403 | // e.g. in `CloseAndReportForceClose`. |
| 404 | return Status::OK(); |
| 405 | } |
| 406 | |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 407 | force_closing_ = true; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 408 | for (Connection* connection : connections_) { |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 409 | connection->CloseAndReportForceClose(message); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 410 | } |
| 411 | connections_.clear(); |
Evan Stade | e2eb7ee | 2025-05-21 21:41:46 | [diff] [blame] | 412 | IDB_RETURN_IF_ERROR(connection_coordinator_.PruneTasksForForceClose(message)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 413 | connection_coordinator_.OnNoConnections(); |
| 414 | |
| 415 | // Execute any pending tasks in the connection coordinator. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 416 | ConnectionCoordinator::ExecuteTaskResult task_state; |
Evan Stade | e2eb7ee | 2025-05-21 21:41:46 | [diff] [blame] | 417 | Status status; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 418 | do { |
| 419 | std::tie(task_state, status) = connection_coordinator_.ExecuteTask(false); |
| 420 | DCHECK(task_state != |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 421 | ConnectionCoordinator::ExecuteTaskResult::kPendingAsyncWork) |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 422 | << "There are no more connections, so all tasks should be able to " |
| 423 | "complete synchronously."; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 424 | } while (task_state != ConnectionCoordinator::ExecuteTaskResult::kDone && |
| 425 | task_state != ConnectionCoordinator::ExecuteTaskResult::kError); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 426 | DCHECK(connections_.empty()); |
Evan Stade | 68334f9 | 2024-02-08 17:09:27 | [diff] [blame] | 427 | bucket_context_->QueueRunTasks(); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 428 | return status; |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 429 | } |
| 430 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 431 | void Database::ScheduleOpenConnection( |
| 432 | std::unique_ptr<PendingConnection> connection) { |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 433 | connection_coordinator_.ScheduleOpenConnection(std::move(connection)); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 434 | } |
| 435 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 436 | void Database::ScheduleDeleteDatabase( |
| 437 | std::unique_ptr<FactoryClient> factory_client, |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 438 | base::OnceClosure on_deletion_complete) { |
Daniel Murphy | ede9159 | 2019-08-12 19:50:22 | [diff] [blame] | 439 | connection_coordinator_.ScheduleDeleteDatabase( |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 440 | std::move(factory_client), std::move(on_deletion_complete)); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 441 | } |
| 442 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 443 | Status Database::VersionChangeOperation(int64_t version, |
| 444 | Transaction* transaction) { |
| 445 | TRACE_EVENT1("IndexedDB", "Database::VersionChangeOperation", "txn.id", |
| 446 | transaction->id()); |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 447 | int64_t old_version = metadata().version; |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 448 | DCHECK_GT(version, old_version); |
| 449 | |
Evan Stade | e2eb7ee | 2025-05-21 21:41:46 | [diff] [blame] | 450 | IDB_RETURN_IF_ERROR( |
| 451 | transaction->BackingStoreTransaction()->SetDatabaseVersion(version)); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 452 | |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 453 | connection_coordinator_.BindVersionChangeTransactionReceiver(); |
Daniel Murphy | ede9159 | 2019-08-12 19:50:22 | [diff] [blame] | 454 | connection_coordinator_.OnUpgradeTransactionStarted(old_version); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 455 | return Status::OK(); |
| 456 | } |
| 457 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 458 | Status Database::GetOperation(int64_t object_store_id, |
| 459 | int64_t index_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 460 | IndexedDBKeyRange key_range, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 461 | CursorType cursor_type, |
| 462 | blink::mojom::IDBDatabase::GetCallback callback, |
| 463 | Transaction* transaction) { |
| 464 | TRACE_EVENT1("IndexedDB", "Database::GetOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 465 | transaction->id()); |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 466 | |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 467 | if (!IsObjectStoreIdAndMaybeIndexIdInMetadata(object_store_id, index_id)) { |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 468 | std::move(callback).Run(blink::mojom::IDBDatabaseGetResult::NewErrorResult( |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 469 | CreateIDBErrorPtr(blink::mojom::IDBException::kUnknownError, |
| 470 | "Bad request", transaction))); |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 471 | return Status::InvalidArgument("Invalid object_store_id and/or index_id."); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 472 | } |
| 473 | |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 474 | const IndexedDBObjectStoreMetadata& object_store_metadata = |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 475 | GetObjectStoreMetadata(object_store_id); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 476 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 477 | IndexedDBKey key; |
| 478 | if (key_range.IsOnlyKey()) { |
| 479 | key = std::move(key_range).TakeOnlyKey(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 480 | } else { |
Evan Stade | a496adc | 2025-05-21 21:42:43 | [diff] [blame] | 481 | StatusOr<std::unique_ptr<BackingStore::Cursor>> backing_store_cursor; |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 482 | if (index_id == IndexedDBIndexMetadata::kInvalidId) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 483 | // ObjectStore Retrieval Operation |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 484 | if (cursor_type == CursorType::kKeyOnly) { |
Evan Stade | e07c68a6 | 2025-04-11 15:21:56 | [diff] [blame] | 485 | backing_store_cursor = |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 486 | transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 487 | object_store_id, key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 488 | blink::mojom::IDBCursorDirection::Next); |
jsbell | 1e5f0bc | 2016-08-30 03:20:44 | [diff] [blame] | 489 | } else { |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 490 | backing_store_cursor = |
| 491 | transaction->BackingStoreTransaction()->OpenObjectStoreCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 492 | object_store_id, key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 493 | blink::mojom::IDBCursorDirection::Next); |
jsbell | 1e5f0bc | 2016-08-30 03:20:44 | [diff] [blame] | 494 | } |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 495 | } else if (cursor_type == CursorType::kKeyOnly) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 496 | // Index Value Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 497 | backing_store_cursor = |
| 498 | transaction->BackingStoreTransaction()->OpenIndexKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 499 | object_store_id, index_id, key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 500 | blink::mojom::IDBCursorDirection::Next); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 501 | } else { |
| 502 | // Index Referenced Value Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 503 | backing_store_cursor = |
| 504 | transaction->BackingStoreTransaction()->OpenIndexCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 505 | object_store_id, index_id, key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 506 | blink::mojom::IDBCursorDirection::Next); |
[email protected] | b05831e | 2014-04-16 18:32:19 | [diff] [blame] | 507 | } |
| 508 | |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 509 | if (!backing_store_cursor.has_value()) { |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 510 | std::move(callback).Run( |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 511 | blink::mojom::IDBDatabaseGetResult::NewErrorResult(CreateIDBErrorPtr( |
| 512 | blink::mojom::IDBException::kUnknownError, |
| 513 | "Corruption detected, unable to continue", transaction))); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 514 | return backing_store_cursor.error(); |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 515 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 516 | |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 517 | if (!*backing_store_cursor) { |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 518 | // This means we've run out of data. |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 519 | std::move(callback).Run( |
| 520 | blink::mojom::IDBDatabaseGetResult::NewEmpty(true)); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 521 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 522 | } |
| 523 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 524 | key = std::move(**backing_store_cursor).TakeKey(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 525 | } |
| 526 | |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 527 | if (index_id == IndexedDBIndexMetadata::kInvalidId) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 528 | // Object Store Retrieval Operation |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 529 | ASSIGN_OR_RETURN( |
| 530 | IndexedDBValue value, |
| 531 | transaction->BackingStoreTransaction()->GetRecord(object_store_id, key), |
| 532 | [&callback, transaction](const Status& status) { |
| 533 | std::move(callback).Run( |
| 534 | blink::mojom::IDBDatabaseGetResult::NewErrorResult( |
| 535 | CreateIDBErrorPtr(blink::mojom::IDBException::kUnknownError, |
| 536 | "Unknown error", transaction))); |
| 537 | return status; |
| 538 | }); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 539 | |
| 540 | if (value.empty()) { |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 541 | std::move(callback).Run( |
| 542 | blink::mojom::IDBDatabaseGetResult::NewEmpty(true)); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 543 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 544 | } |
| 545 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 546 | if (cursor_type == CursorType::kKeyOnly) { |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 547 | std::move(callback).Run( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 548 | blink::mojom::IDBDatabaseGetResult::NewKey(std::move(key))); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 549 | return Status::OK(); |
jsbell | 1e5f0bc | 2016-08-30 03:20:44 | [diff] [blame] | 550 | } |
| 551 | |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 552 | blink::IndexedDBKey primary_key; |
| 553 | blink::IndexedDBKeyPath key_path; |
| 554 | |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 555 | if (object_store_metadata.auto_increment && |
| 556 | !object_store_metadata.key_path.IsNull()) { |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 557 | primary_key = std::move(key); |
| 558 | key_path = object_store_metadata.key_path; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 559 | } |
| 560 | |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 561 | blink::mojom::IDBReturnValuePtr mojo_value = |
| 562 | ConvertValueToReturnValue(*transaction, std::move(value), |
| 563 | std::move(primary_key), std::move(key_path)); |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 564 | std::move(callback).Run( |
| 565 | blink::mojom::IDBDatabaseGetResult::NewValue(std::move(mojo_value))); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 566 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 567 | } |
| 568 | |
| 569 | // From here we are dealing only with indexes. |
Evan Stade | 8df643b | 2025-05-29 22:38:53 | [diff] [blame] | 570 | ASSIGN_OR_RETURN( |
| 571 | IndexedDBKey primary_key, |
Abhishek Shanthkumar | e6f4cf5 | 2025-06-17 20:40:45 | [diff] [blame] | 572 | transaction->BackingStoreTransaction()->GetFirstPrimaryKeyForIndexKey( |
Evan Stade | 8df643b | 2025-05-29 22:38:53 | [diff] [blame] | 573 | object_store_id, index_id, key), |
| 574 | [&callback, transaction](const Status& status) { |
| 575 | std::move(callback).Run( |
| 576 | blink::mojom::IDBDatabaseGetResult::NewErrorResult( |
| 577 | CreateIDBErrorPtr(blink::mojom::IDBException::kUnknownError, |
| 578 | "Unknown error", transaction))); |
| 579 | return status; |
| 580 | }); |
dmurph | 9d00e05d | 2016-12-01 23:00:34 | [diff] [blame] | 581 | |
Evan Stade | 8df643b | 2025-05-29 22:38:53 | [diff] [blame] | 582 | if (!primary_key.IsValid()) { |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 583 | std::move(callback).Run(blink::mojom::IDBDatabaseGetResult::NewEmpty(true)); |
Evan Stade | 8df643b | 2025-05-29 22:38:53 | [diff] [blame] | 584 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 585 | } |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 586 | if (cursor_type == CursorType::kKeyOnly) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 587 | // Index Value Retrieval Operation |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 588 | std::move(callback).Run( |
Evan Stade | 8df643b | 2025-05-29 22:38:53 | [diff] [blame] | 589 | blink::mojom::IDBDatabaseGetResult::NewKey(std::move(primary_key))); |
| 590 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 591 | } |
| 592 | |
| 593 | // Index Referenced Value Retrieval Operation |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 594 | ASSIGN_OR_RETURN( |
| 595 | IndexedDBValue value, |
| 596 | transaction->BackingStoreTransaction()->GetRecord(object_store_id, |
| 597 | primary_key), |
| 598 | [&callback, transaction](const Status& status) { |
| 599 | std::move(callback).Run( |
| 600 | blink::mojom::IDBDatabaseGetResult::NewErrorResult( |
| 601 | CreateIDBErrorPtr(blink::mojom::IDBException::kUnknownError, |
| 602 | "Unknown error", transaction))); |
| 603 | return status; |
| 604 | }); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 605 | |
| 606 | if (value.empty()) { |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 607 | std::move(callback).Run(blink::mojom::IDBDatabaseGetResult::NewEmpty(true)); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 608 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 609 | } |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 610 | |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 611 | blink::IndexedDBKey primary_key_return; |
| 612 | blink::IndexedDBKeyPath key_path_return; |
| 613 | |
| 614 | if (object_store_metadata.auto_increment && |
| 615 | !object_store_metadata.key_path.IsNull()) { |
| 616 | primary_key_return = std::move(primary_key); |
| 617 | key_path_return = object_store_metadata.key_path; |
| 618 | } |
| 619 | |
| 620 | blink::mojom::IDBReturnValuePtr mojo_value = ConvertValueToReturnValue( |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 621 | *transaction, std::move(value), std::move(primary_key_return), |
| 622 | std::move(key_path_return)); |
Chase Phillips | c746777 | 2019-06-04 01:02:53 | [diff] [blame] | 623 | std::move(callback).Run( |
| 624 | blink::mojom::IDBDatabaseGetResult::NewValue(std::move(mojo_value))); |
Evan Stade | 295d0ab | 2025-06-02 15:27:54 | [diff] [blame] | 625 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 626 | } |
| 627 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 628 | Transaction::Operation Database::CreateGetAllOperation( |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 629 | int64_t object_store_id, |
| 630 | int64_t index_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 631 | blink::IndexedDBKeyRange key_range, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 632 | blink::mojom::IDBGetAllResultType result_type, |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 633 | int64_t max_count, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 634 | blink::mojom::IDBCursorDirection direction, |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 635 | blink::mojom::IDBDatabase::GetAllCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 636 | Transaction* transaction) { |
| 637 | return BindWeakOperation(&Database::GetAllOperation, AsWeakPtr(), |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 638 | object_store_id, index_id, std::move(key_range), |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 639 | result_type, max_count, direction, |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 640 | std::make_unique<GetAllResultSinkWrapper>( |
| 641 | transaction->AsWeakPtr(), std::move(callback))); |
| 642 | } |
| 643 | |
Chase Phillips | 7027bd5 | 2018-08-30 17:31:55 | [diff] [blame] | 644 | static_assert(sizeof(size_t) >= sizeof(int32_t), |
| 645 | "Size of size_t is less than size of int32"); |
| 646 | static_assert(blink::mojom::kIDBMaxMessageOverhead <= INT32_MAX, |
| 647 | "kIDBMaxMessageOverhead is more than INT32_MAX"); |
| 648 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 649 | Database::GetAllResultSinkWrapper::GetAllResultSinkWrapper( |
| 650 | base::WeakPtr<Transaction> transaction, |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 651 | blink::mojom::IDBDatabase::GetAllCallback callback) |
| 652 | : transaction_(transaction), callback_(std::move(callback)) {} |
| 653 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 654 | Database::GetAllResultSinkWrapper::~GetAllResultSinkWrapper() { |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 655 | if (!callback_) { |
| 656 | return; |
| 657 | } |
| 658 | |
| 659 | if (transaction_) { |
| 660 | transaction_->IncrementNumErrorsSent(); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 661 | // If we're reaching this line because the Connection has been |
Evan Stade | 278881c | 2024-06-14 05:33:04 | [diff] [blame] | 662 | // disconnected from its remote, then `result_sink_` won't have been |
| 663 | // successfully associated, and invoking any methods on it will CHECK. |
| 664 | // See crbug.com/346955148. |
| 665 | // TODO(crbug.com/347047640): remove this workaround when 347047640 is |
| 666 | // fixed. |
| 667 | if (!transaction_->connection()->is_shutting_down()) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 668 | DatabaseError error(blink::mojom::IDBException::kIgnorableAbortError, |
| 669 | "Backend aborted error"); |
Evan Stade | 278881c | 2024-06-14 05:33:04 | [diff] [blame] | 670 | Get()->OnError( |
| 671 | blink::mojom::IDBError::New(error.code(), error.message())); |
| 672 | } |
| 673 | } else { |
| 674 | // Make sure `callback_` is invoked because the Mojo client is waiting for a |
| 675 | // response. |
| 676 | Get(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 677 | } |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 678 | } |
| 679 | |
| 680 | mojo::AssociatedRemote<blink::mojom::IDBDatabaseGetAllResultSink>& |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 681 | Database::GetAllResultSinkWrapper::Get() { |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 682 | if (!result_sink_) { |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 683 | mojo::PendingAssociatedReceiver<blink::mojom::IDBDatabaseGetAllResultSink> |
| 684 | pending_receiver; |
| 685 | if (use_dedicated_receiver_for_testing_) { |
| 686 | pending_receiver = result_sink_.BindNewEndpointAndPassDedicatedReceiver(); |
| 687 | } else { |
| 688 | pending_receiver = result_sink_.BindNewEndpointAndPassReceiver(); |
| 689 | } |
| 690 | std::move(callback_).Run(std::move(pending_receiver)); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 691 | } |
| 692 | return result_sink_; |
| 693 | } |
| 694 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 695 | Status Database::GetAllOperation( |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 696 | int64_t object_store_id, |
| 697 | int64_t index_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 698 | IndexedDBKeyRange key_range, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 699 | blink::mojom::IDBGetAllResultType result_type, |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 700 | int64_t max_count, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 701 | blink::mojom::IDBCursorDirection direction, |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 702 | std::unique_ptr<GetAllResultSinkWrapper> result_sink, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 703 | Transaction* transaction) { |
| 704 | TRACE_EVENT1("IndexedDB", "Database::GetAllOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 705 | transaction->id()); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 706 | |
Joshua Bell | 60124c1 | 2020-01-28 23:10:37 | [diff] [blame] | 707 | if (!IsObjectStoreIdAndMaybeIndexIdInMetadata(object_store_id, index_id)) { |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 708 | result_sink->Get()->OnError(CreateIDBErrorPtr( |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 709 | blink::mojom::IDBException::kUnknownError, "Bad request", transaction)); |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 710 | return Status::InvalidArgument("Invalid object_store_id."); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 711 | } |
| 712 | |
cmumford | ca3da523 | 2015-05-15 23:09:34 | [diff] [blame] | 713 | DCHECK_GT(max_count, 0); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 714 | |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 715 | const IndexedDBObjectStoreMetadata& object_store_metadata = |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 716 | GetObjectStoreMetadata(object_store_id); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 717 | |
Evan Stade | a496adc | 2025-05-21 21:42:43 | [diff] [blame] | 718 | StatusOr<std::unique_ptr<BackingStore::Cursor>> cursor; |
cmumford | 75696ff6 | 2015-05-19 22:21:57 | [diff] [blame] | 719 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 720 | if (result_type == blink::mojom::IDBGetAllResultType::Keys) { |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 721 | // Retrieving keys |
| 722 | if (index_id == IndexedDBIndexMetadata::kInvalidId) { |
| 723 | // Object Store: Key Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 724 | cursor = transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 725 | object_store_id, key_range, direction); |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 726 | } else { |
| 727 | // Index Value: (Primary Key) Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 728 | cursor = transaction->BackingStoreTransaction()->OpenIndexKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 729 | object_store_id, index_id, key_range, direction); |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 730 | } |
cmumford | 75696ff6 | 2015-05-19 22:21:57 | [diff] [blame] | 731 | } else { |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 732 | // Retrieving values |
| 733 | if (index_id == IndexedDBIndexMetadata::kInvalidId) { |
| 734 | // Object Store: Value Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 735 | cursor = transaction->BackingStoreTransaction()->OpenObjectStoreCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 736 | object_store_id, key_range, direction); |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 737 | } else { |
| 738 | // Object Store: Referenced Value Retrieval Operation |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 739 | cursor = transaction->BackingStoreTransaction()->OpenIndexCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 740 | object_store_id, index_id, key_range, direction); |
cmumford | 5065ab7 | 2015-06-03 00:51:49 | [diff] [blame] | 741 | } |
cmumford | 75696ff6 | 2015-05-19 22:21:57 | [diff] [blame] | 742 | } |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 743 | |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 744 | if (!cursor.has_value()) { |
| 745 | DLOG(ERROR) << "Unable to open cursor operation: " |
| 746 | << cursor.error().ToString(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 747 | result_sink->Get()->OnError(CreateIDBErrorPtr( |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 748 | blink::mojom::IDBException::kUnknownError, |
| 749 | "Corruption detected, unable to continue", transaction)); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 750 | return cursor.error(); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 751 | } |
| 752 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 753 | std::vector<blink::mojom::IDBRecordPtr> found_records; |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 754 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 755 | auto send_records = [&](bool done) { |
| 756 | result_sink->Get()->ReceiveResults(std::move(found_records), done); |
| 757 | found_records.clear(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 758 | }; |
| 759 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 760 | // No records found. |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 761 | if (!*cursor) { |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 762 | send_records(/*done=*/true); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 763 | return Status::OK(); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 764 | } |
| 765 | |
| 766 | bool did_first_seek = false; |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 767 | |
Adrienne Walker | 7c30dd6 | 2020-07-27 11:00:06 | [diff] [blame] | 768 | // Max idbvalue size before blob wrapping is 64k, so make an assumption |
| 769 | // that max key/value size is 128kb tops, to fit under 128mb mojo limit. |
| 770 | // This value is just a heuristic and is an attempt to make sure that |
| 771 | // GetAll fits under the message limit size. |
| 772 | static_assert( |
| 773 | blink::mojom::kIDBMaxMessageSize > |
| 774 | blink::mojom::kIDBGetAllChunkSize * blink::mojom::kIDBWrapThreshold, |
| 775 | "Chunk heuristic too large"); |
| 776 | |
| 777 | const size_t max_values_before_sending = blink::mojom::kIDBGetAllChunkSize; |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 778 | int64_t num_found_items = 0; |
cmumford | 3807363 | 2015-05-29 18:40:09 | [diff] [blame] | 779 | while (num_found_items++ < max_count) { |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 780 | StatusOr<bool> cursor_valid = true; |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 781 | if (did_first_seek) { |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 782 | cursor_valid = (*cursor)->Continue(); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 783 | } else { |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 784 | // Cursor creation performs the first seek, returning a nullptr cursor |
| 785 | // when invalid. |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 786 | did_first_seek = true; |
| 787 | } |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 788 | if (!cursor_valid.has_value()) { |
| 789 | result_sink->Get()->OnError( |
| 790 | CreateIDBErrorPtr(blink::mojom::IDBException::kUnknownError, |
| 791 | "Seek failure, unable to continue", transaction)); |
| 792 | return cursor_valid.error(); |
| 793 | } |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 794 | |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 795 | if (!cursor_valid.value()) { |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 796 | break; |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 797 | } |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 798 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 799 | blink::mojom::IDBRecordPtr return_record; |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 800 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 801 | if (result_type == blink::mojom::IDBGetAllResultType::Keys) { |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 802 | return_record = |
| 803 | blink::mojom::IDBRecord::New((*cursor)->GetPrimaryKey().Clone(), |
| 804 | /*value=*/nullptr, |
| 805 | /*index_key=*/std::nullopt); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 806 | } else if (result_type == blink::mojom::IDBGetAllResultType::Values) { |
| 807 | blink::mojom::IDBReturnValuePtr return_value = |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 808 | ExtractReturnValueFromCursorValue(*transaction, object_store_metadata, |
| 809 | **cursor); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 810 | return_record = blink::mojom::IDBRecord::New( |
| 811 | /*primary_key=*/std::nullopt, std::move(return_value), |
| 812 | /*index_key=*/std::nullopt); |
| 813 | } else if (result_type == blink::mojom::IDBGetAllResultType::Records) { |
| 814 | // Construct the record, which includes the primary key, value and index |
| 815 | // key. |
| 816 | blink::mojom::IDBReturnValuePtr return_value = |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 817 | ExtractReturnValueFromCursorValue(*transaction, object_store_metadata, |
| 818 | **cursor); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 819 | std::optional<IndexedDBKey> index_key; |
| 820 | if (index_id != IndexedDBIndexMetadata::kInvalidId) { |
| 821 | // The index key only exists for `IDBIndex::getAllRecords()`. |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 822 | index_key = (*cursor)->GetKey().Clone(); |
cmumford | 3807363 | 2015-05-29 18:40:09 | [diff] [blame] | 823 | } |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 824 | return_record = blink::mojom::IDBRecord::New( |
| 825 | (*cursor)->GetPrimaryKey().Clone(), std::move(return_value), |
| 826 | std::move(index_key)); |
Evan Stade | 6265dcd | 2024-02-27 20:50:04 | [diff] [blame] | 827 | } else { |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 828 | NOTREACHED(); |
Evan Stade | 6265dcd | 2024-02-27 20:50:04 | [diff] [blame] | 829 | } |
Adrienne Walker | 7c30dd6 | 2020-07-27 11:00:06 | [diff] [blame] | 830 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 831 | found_records.emplace_back(std::move(return_record)); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 832 | |
| 833 | // Periodically stream records if we have too many. |
| 834 | if (found_records.size() >= max_values_before_sending) { |
| 835 | send_records(/*done=*/false); |
Adrienne Walker | 7c30dd6 | 2020-07-27 11:00:06 | [diff] [blame] | 836 | } |
cmumford | 3807363 | 2015-05-29 18:40:09 | [diff] [blame] | 837 | } |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 838 | send_records(/*done=*/true); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 839 | return Status::OK(); |
cmumford | b86405eb | 2015-05-14 14:50:39 | [diff] [blame] | 840 | } |
| 841 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 842 | Status Database::OpenCursorOperation( |
dcheng | 531cca9 | 2016-04-09 03:03:23 | [diff] [blame] | 843 | std::unique_ptr<OpenCursorOperationParams> params, |
Ari Chivukula | 65a987e | 2022-04-26 19:04:12 | [diff] [blame] | 844 | const storage::BucketLocator& bucket_locator, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 845 | Transaction* transaction) { |
| 846 | TRACE_EVENT1("IndexedDB", "Database::OpenCursorOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 847 | transaction->id()); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 848 | |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 849 | if (!IsObjectStoreIdAndMaybeIndexIdInMetadata(params->object_store_id, |
| 850 | params->index_id)) { |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 851 | return Status::InvalidArgument("Invalid object_store_id and/or index_id."); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 852 | } |
| 853 | |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 854 | // The frontend has begun indexing, so this pauses the transaction |
| 855 | // until the indexing is complete. This can't happen any earlier |
| 856 | // because we don't want to switch to early mode in case multiple |
| 857 | // indexes are being created in a row, with Put()'s in between. |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 858 | if (params->task_type == blink::mojom::IDBTaskType::Preemptive) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 859 | transaction->AddPreemptiveEvent(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 860 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 861 | |
Evan Stade | a496adc | 2025-05-21 21:42:43 | [diff] [blame] | 862 | StatusOr<std::unique_ptr<BackingStore::Cursor>> backing_store_cursor; |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 863 | if (params->index_id == IndexedDBIndexMetadata::kInvalidId) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 864 | if (params->cursor_type == CursorType::kKeyOnly) { |
Chase Phillips | b2851f32 | 2018-11-16 00:27:48 | [diff] [blame] | 865 | DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 866 | backing_store_cursor = |
| 867 | transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 868 | params->object_store_id, params->key_range, params->direction); |
[email protected] | fe4aa9dc | 2013-08-27 03:28:57 | [diff] [blame] | 869 | } else { |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 870 | backing_store_cursor = |
| 871 | transaction->BackingStoreTransaction()->OpenObjectStoreCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 872 | params->object_store_id, params->key_range, params->direction); |
[email protected] | fe4aa9dc | 2013-08-27 03:28:57 | [diff] [blame] | 873 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 874 | } else { |
Chase Phillips | b2851f32 | 2018-11-16 00:27:48 | [diff] [blame] | 875 | DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 876 | if (params->cursor_type == CursorType::kKeyOnly) { |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 877 | backing_store_cursor = |
| 878 | transaction->BackingStoreTransaction()->OpenIndexKeyCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 879 | params->object_store_id, params->index_id, params->key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 880 | params->direction); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 881 | } else { |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 882 | backing_store_cursor = |
| 883 | transaction->BackingStoreTransaction()->OpenIndexCursor( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 884 | params->object_store_id, params->index_id, params->key_range, |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 885 | params->direction); |
[email protected] | b05831e | 2014-04-16 18:32:19 | [diff] [blame] | 886 | } |
| 887 | } |
| 888 | |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 889 | if (!backing_store_cursor.has_value()) { |
| 890 | DLOG(ERROR) << "Unable to open cursor operation: " |
| 891 | << backing_store_cursor.error().ToString(); |
| 892 | return backing_store_cursor.error(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 893 | } |
| 894 | |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 895 | if (!*backing_store_cursor) { |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 896 | // Occurs when we've reached the end of cursor's data. |
Chase Phillips | 46d3cdb | 2019-07-29 17:50:14 | [diff] [blame] | 897 | std::move(params->callback) |
| 898 | .Run(blink::mojom::IDBDatabaseOpenCursorResult::NewEmpty(true)); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 899 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 900 | } |
| 901 | |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 902 | mojo::PendingAssociatedRemote<blink::mojom::IDBCursor> pending_remote; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 903 | Cursor* cursor = Cursor::CreateAndBind( |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 904 | std::move(*backing_store_cursor), params->cursor_type, params->task_type, |
Evan Stade | 6584a49 | 2023-09-25 21:02:30 | [diff] [blame] | 905 | transaction->AsWeakPtr(), pending_remote); |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 906 | transaction->RegisterOpenCursor(cursor); |
Chase Phillips | 46d3cdb | 2019-07-29 17:50:14 | [diff] [blame] | 907 | |
Chase Phillips | 46d3cdb | 2019-07-29 17:50:14 | [diff] [blame] | 908 | blink::mojom::IDBValuePtr mojo_value; |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 909 | if (cursor->Value()) { |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 910 | mojo_value = transaction->BuildMojoValue(std::move(*cursor->Value())); |
Marijn Kruisselbrink | 145f759 | 2020-02-18 08:49:31 | [diff] [blame] | 911 | } |
Chase Phillips | 46d3cdb | 2019-07-29 17:50:14 | [diff] [blame] | 912 | |
Chase Phillips | 46d3cdb | 2019-07-29 17:50:14 | [diff] [blame] | 913 | std::move(params->callback) |
| 914 | .Run(blink::mojom::IDBDatabaseOpenCursorResult::NewValue( |
| 915 | blink::mojom::IDBDatabaseOpenCursorValue::New( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 916 | std::move(pending_remote), cursor->key().Clone(), |
| 917 | cursor->primary_key().Clone(), std::move(mojo_value)))); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 918 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 919 | } |
| 920 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 921 | Status Database::CountOperation( |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 922 | int64_t object_store_id, |
| 923 | int64_t index_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 924 | IndexedDBKeyRange key_range, |
Evan Stade | b7ecb0c | 2023-07-05 19:22:58 | [diff] [blame] | 925 | blink::mojom::IDBDatabase::CountCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 926 | Transaction* transaction) { |
| 927 | TRACE_EVENT1("IndexedDB", "Database::CountOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 928 | transaction->id()); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 929 | |
Evan Stade | b7ecb0c | 2023-07-05 19:22:58 | [diff] [blame] | 930 | if (!IsObjectStoreIdAndMaybeIndexIdInMetadata(object_store_id, index_id)) { |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 931 | return Status::InvalidArgument("Invalid object_store_id and/or index_id."); |
Evan Stade | b7ecb0c | 2023-07-05 19:22:58 | [diff] [blame] | 932 | } |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 933 | |
Abhishek Shanthkumar | 9b509ca | 2025-05-29 15:41:04 | [diff] [blame] | 934 | uint32_t count = -1; |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 935 | if (index_id == IndexedDBIndexMetadata::kInvalidId) { |
Abhishek Shanthkumar | 9b509ca | 2025-05-29 15:41:04 | [diff] [blame] | 936 | ASSIGN_OR_RETURN( |
| 937 | count, transaction->BackingStoreTransaction()->GetObjectStoreKeyCount( |
| 938 | object_store_id, std::move(key_range))); |
| 939 | |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 940 | } else { |
Abhishek Shanthkumar | 9b509ca | 2025-05-29 15:41:04 | [diff] [blame] | 941 | ASSIGN_OR_RETURN(count, |
| 942 | transaction->BackingStoreTransaction()->GetIndexKeyCount( |
| 943 | object_store_id, index_id, std::move(key_range))); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 944 | } |
Evan Stade | b7ecb0c | 2023-07-05 19:22:58 | [diff] [blame] | 945 | std::move(callback).Run(/*success=*/true, count); |
Evan Stade | 2563f3e | 2025-05-08 07:46:03 | [diff] [blame] | 946 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 947 | } |
| 948 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 949 | Status Database::DeleteRangeOperation( |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 950 | int64_t object_store_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 951 | IndexedDBKeyRange key_range, |
Evan Stade | ad03d76 | 2023-06-01 16:37:58 | [diff] [blame] | 952 | blink::mojom::IDBDatabase::DeleteRangeCallback success_callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 953 | Transaction* transaction) { |
| 954 | TRACE_EVENT1("IndexedDB", "Database::DeleteRangeOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 955 | transaction->id()); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 956 | |
Evan Stade | ad03d76 | 2023-06-01 16:37:58 | [diff] [blame] | 957 | Status s; |
| 958 | if (IsObjectStoreIdInMetadata(object_store_id)) { |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 959 | s = transaction->BackingStoreTransaction()->DeleteRange(object_store_id, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 960 | key_range); |
Evan Stade | ad03d76 | 2023-06-01 16:37:58 | [diff] [blame] | 961 | } else { |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 962 | s = Status::InvalidArgument("Invalid object_store_id."); |
Evan Stade | ad03d76 | 2023-06-01 16:37:58 | [diff] [blame] | 963 | } |
| 964 | if (s.ok()) { |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 965 | const IndexedDBObjectStoreMetadata& object_store_metadata = |
| 966 | GetObjectStoreMetadata(object_store_id); |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 967 | bucket_context_->delegate().on_content_changed.Run( |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 968 | metadata().name, object_store_metadata.name); |
Evan Stade | ad03d76 | 2023-06-01 16:37:58 | [diff] [blame] | 969 | } |
| 970 | std::move(success_callback).Run(s.ok()); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 971 | return s; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 972 | } |
| 973 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 974 | Status Database::GetKeyGeneratorCurrentNumberOperation( |
Harley Li | 20add69 | 2019-02-15 22:54:12 | [diff] [blame] | 975 | int64_t object_store_id, |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 976 | blink::mojom::IDBDatabase::GetKeyGeneratorCurrentNumberCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 977 | Transaction* transaction) { |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 978 | if (!IsObjectStoreIdInMetadata(object_store_id)) { |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 979 | std::move(callback).Run( |
| 980 | -1, CreateIDBErrorPtr(blink::mojom::IDBException::kDataError, |
| 981 | "Object store id not valid.", transaction)); |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 982 | return Status::InvalidArgument("Invalid object_store_id."); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 983 | } |
| 984 | |
Evan Stade | 027d5d5 | 2025-05-21 23:04:32 | [diff] [blame] | 985 | ASSIGN_OR_RETURN( |
| 986 | int64_t current_number, |
Evan Stade | ce09c4c | 2025-04-18 17:23:27 | [diff] [blame] | 987 | transaction->BackingStoreTransaction()->GetKeyGeneratorCurrentNumber( |
Evan Stade | 027d5d5 | 2025-05-21 23:04:32 | [diff] [blame] | 988 | object_store_id), |
| 989 | [&callback, transaction](const Status& status) { |
| 990 | std::move(callback).Run( |
| 991 | -1, CreateIDBErrorPtr( |
| 992 | blink::mojom::IDBException::kDataError, |
| 993 | "Failed to get the current number of key generator.", |
| 994 | transaction)); |
| 995 | return status; |
| 996 | }); |
| 997 | |
Evan Stade | dc38e971 | 2023-07-14 02:04:54 | [diff] [blame] | 998 | std::move(callback).Run(current_number, nullptr); |
Evan Stade | 027d5d5 | 2025-05-21 23:04:32 | [diff] [blame] | 999 | return Status::OK(); |
Harley Li | 20add69 | 2019-02-15 22:54:12 | [diff] [blame] | 1000 | } |
| 1001 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1002 | Status Database::ClearOperation( |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 1003 | int64_t object_store_id, |
Evan Stade | c5b90f0 | 2023-05-23 20:25:07 | [diff] [blame] | 1004 | blink::mojom::IDBDatabase::ClearCallback success_callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1005 | Transaction* transaction) { |
| 1006 | TRACE_EVENT1("IndexedDB", "Database::ClearOperation", "txn.id", |
Pei Zhang | c420ad7 | 2022-02-12 06:11:55 | [diff] [blame] | 1007 | transaction->id()); |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 1008 | Status s = Status::InvalidArgument("Invalid object_store_id."); |
Evan Stade | c5b90f0 | 2023-05-23 20:25:07 | [diff] [blame] | 1009 | if (IsObjectStoreIdInMetadata(object_store_id)) { |
Evan Stade | ce09c4c | 2025-04-18 17:23:27 | [diff] [blame] | 1010 | s = transaction->BackingStoreTransaction()->ClearObjectStore( |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 1011 | object_store_id); |
Evan Stade | c5b90f0 | 2023-05-23 20:25:07 | [diff] [blame] | 1012 | } |
| 1013 | if (s.ok()) { |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 1014 | const IndexedDBObjectStoreMetadata& object_store_metadata = |
| 1015 | GetObjectStoreMetadata(object_store_id); |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 1016 | bucket_context_->delegate().on_content_changed.Run( |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 1017 | name_, object_store_metadata.name); |
Evan Stade | c5b90f0 | 2023-05-23 20:25:07 | [diff] [blame] | 1018 | } |
| 1019 | std::move(success_callback).Run(s.ok()); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 1020 | return s; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 1021 | } |
| 1022 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1023 | bool Database::IsObjectStoreIdInMetadata(int64_t object_store_id) const { |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 1024 | if (!base::Contains(metadata().object_stores, object_store_id)) { |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 1025 | DLOG(ERROR) << "Invalid object_store_id"; |
| 1026 | return false; |
| 1027 | } |
| 1028 | return true; |
| 1029 | } |
| 1030 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1031 | bool Database::IsObjectStoreIdAndMaybeIndexIdInMetadata( |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 1032 | int64_t object_store_id, |
| 1033 | int64_t index_id) const { |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1034 | if (!IsObjectStoreIdInMetadata(object_store_id)) { |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 1035 | return false; |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1036 | } |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 1037 | const IndexedDBObjectStoreMetadata& object_store_metadata = |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 1038 | GetObjectStoreMetadata(object_store_id); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 1039 | if (index_id != IndexedDBIndexMetadata::kInvalidId && |
| 1040 | !base::Contains(object_store_metadata.indexes, index_id)) { |
| 1041 | DLOG(ERROR) << "Invalid index_id"; |
| 1042 | return false; |
| 1043 | } |
| 1044 | return true; |
| 1045 | } |
| 1046 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1047 | storage::mojom::IdbDatabaseMetadataPtr Database::GetIdbInternalsMetadata() |
| 1048 | const { |
Brad Triebwasser | fe45f3f | 2024-06-03 19:20:29 | [diff] [blame] | 1049 | storage::mojom::IdbDatabaseMetadataPtr info = |
| 1050 | storage::mojom::IdbDatabaseMetadata::New(); |
| 1051 | info->name = name(); |
| 1052 | info->connection_count = ConnectionCount(); |
| 1053 | info->active_open_delete = ActiveOpenDeleteCount(); |
| 1054 | info->pending_open_delete = PendingOpenDeleteCount(); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1055 | for (const Connection* connection : connections()) { |
Brad Triebwasser | fe45f3f | 2024-06-03 19:20:29 | [diff] [blame] | 1056 | for (const auto& [_, transaction] : connection->transactions()) { |
| 1057 | info->transactions.push_back(transaction->GetIdbInternalsMetadata()); |
| 1058 | } |
| 1059 | } |
| 1060 | return info; |
| 1061 | } |
| 1062 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1063 | void Database::NotifyOfIdbInternalsRelevantChange() { |
Brad Triebwasser | 88b84af | 2024-06-04 19:36:55 | [diff] [blame] | 1064 | // This metadata is included in the context metadata, so call up the chain. |
| 1065 | bucket_context_->NotifyOfIdbInternalsRelevantChange(); |
| 1066 | } |
| 1067 | |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1068 | // kIDBMaxMessageSize is defined based on the original |
Tom Sepez | 36c46c0 | 2025-07-11 21:43:56 | [diff] [blame] | 1069 | // IPC::mojom::kChannelMaximumMessageSize value. We use kIDBMaxMessageSize to |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1070 | // limit the size of arguments we pass into our Mojo calls. We want to ensure |
| 1071 | // this value is always no bigger than the current kMaximumMessageSize value |
| 1072 | // which also ensures it is always no bigger than the current Mojo message |
| 1073 | // size limit. |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1074 | static_assert( |
Tom Sepez | 36c46c0 | 2025-07-11 21:43:56 | [diff] [blame] | 1075 | blink::mojom::kIDBMaxMessageSize <= IPC::mojom::kChannelMaximumMessageSize, |
| 1076 | "kIDBMaxMessageSize is bigger than IPC::mojom::kChannelMaximumMessageSize"); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 1077 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1078 | void Database::CallUpgradeTransactionStartedForTesting(int64_t old_version) { |
Daniel Murphy | ede9159 | 2019-08-12 19:50:22 | [diff] [blame] | 1079 | connection_coordinator_.OnUpgradeTransactionStarted(old_version); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 1080 | } |
| 1081 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1082 | Status Database::OpenInternal() { |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 1083 | auto result = backing_store()->CreateOrOpenDatabase(name_); |
| 1084 | if (result.has_value()) { |
| 1085 | backing_store_db_ = std::move(result.value()); |
| 1086 | return Status::OK(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1087 | } |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 1088 | return result.error(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 1089 | } |
| 1090 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1091 | std::unique_ptr<Connection> Database::CreateConnection( |
| 1092 | std::unique_ptr<DatabaseCallbacks> database_callbacks, |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 1093 | mojo::Remote<storage::mojom::IndexedDBClientStateChecker> |
Evan Stade | 2db7aa7 | 2024-02-01 17:07:27 | [diff] [blame] | 1094 | client_state_checker, |
Evan Stade | 8e75d40 | 2024-09-04 00:42:43 | [diff] [blame] | 1095 | base::UnguessableToken client_token, |
| 1096 | int scheduling_priority) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1097 | auto connection = std::make_unique<Connection>( |
Evan Stade | 6a314fe | 2023-09-25 21:24:12 | [diff] [blame] | 1098 | *bucket_context_, weak_factory_.GetWeakPtr(), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1099 | base::BindRepeating(&Database::VersionChangeIgnored, |
Evan Stade | 6a314fe | 2023-09-25 21:24:12 | [diff] [blame] | 1100 | weak_factory_.GetWeakPtr()), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1101 | base::BindOnce(&Database::ConnectionClosed, weak_factory_.GetWeakPtr()), |
Evan Stade | 2db7aa7 | 2024-02-01 17:07:27 | [diff] [blame] | 1102 | std::move(database_callbacks), std::move(client_state_checker), |
Evan Stade | 8e75d40 | 2024-09-04 00:42:43 | [diff] [blame] | 1103 | client_token, scheduling_priority); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1104 | connections_.insert(connection.get()); |
Evan Stade | 9dc3639 | 2024-10-29 13:10:39 | [diff] [blame] | 1105 | bucket_context_->OnConnectionPriorityUpdated(); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1106 | return connection; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 1107 | } |
| 1108 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1109 | void Database::VersionChangeIgnored() { |
Daniel Murphy | ede9159 | 2019-08-12 19:50:22 | [diff] [blame] | 1110 | connection_coordinator_.OnVersionChangeIgnored(); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1111 | } |
| 1112 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1113 | bool Database::HasNoConnections() const { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1114 | return force_closing_ || connections().empty(); |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1115 | } |
| 1116 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1117 | void Database::SendVersionChangeToAllConnections(int64_t old_version, |
| 1118 | int64_t new_version) { |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1119 | if (force_closing_) { |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1120 | return; |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1121 | } |
Mingyu Lei | 85c2caf | 2022-12-16 09:46:39 | [diff] [blame] | 1122 | for (auto* connection : connections()) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1123 | // Before invoking this method, the `ConnectionCoordinator` had |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1124 | // set the request state to `kPendingNoConnections`. Now the request will |
| 1125 | // be blocked until all the existing connections to this database is |
| 1126 | // closed. There are three possible ways for the connection to be closed: |
| 1127 | // 1. If the client is already pending close, then the `VersionChange` |
| 1128 | // event will be ignored and the open request will be deemed blocked until |
| 1129 | // the pending close completes. |
Mingyu Lei | 85c2caf | 2022-12-16 09:46:39 | [diff] [blame] | 1130 | // 2. If the client is active, the `VersionChange` event will be enqueued |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1131 | // and the registered event listener will be fired asynchronously. The |
| 1132 | // event listener should be responsible for actively closing the IndexedDB |
Mingyu Lei | 85c2caf | 2022-12-16 09:46:39 | [diff] [blame] | 1133 | // connection. The document won't be eligible for BFCache before the |
| 1134 | // connection is closed if it receives the `versionchange` event. |
| 1135 | // 3. While the above two cases rely on the `VersionChange` event to be |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1136 | // delivered to the renderer process, the third case happens purely from |
| 1137 | // the IndexedDB/browser context. If the client is inactive, the |
| 1138 | // `VersionChange` event will not be delivered, instead, a mojo call is |
| 1139 | // sent to the browser process to disallow the activation of the inactive |
| 1140 | // client, which will close the connection as part of the destruction. No |
| 1141 | // matter which path it follows, the `SendVersionChangeToAllConnections` |
Mingyu Lei | 85c2caf | 2022-12-16 09:46:39 | [diff] [blame] | 1142 | // method is executed asynchronously. |
Mingyu Lei | ac9bde4 | 2023-06-22 09:56:24 | [diff] [blame] | 1143 | connection->DisallowInactiveClient( |
Evan Stade | 2db7aa7 | 2024-02-01 17:07:27 | [diff] [blame] | 1144 | storage::mojom::DisallowInactiveClientReason::kVersionChangeEvent, |
Mingyu Lei | ac9bde4 | 2023-06-22 09:56:24 | [diff] [blame] | 1145 | base::BindOnce( |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1146 | [](base::WeakPtr<Connection> connection, int64_t old_version, |
| 1147 | int64_t new_version, bool was_client_active) { |
Mingyu Lei | ac9bde4 | 2023-06-22 09:56:24 | [diff] [blame] | 1148 | if (connection && connection->IsConnected() && |
| 1149 | was_client_active) { |
| 1150 | connection->callbacks()->OnVersionChange(old_version, |
| 1151 | new_version); |
| 1152 | } |
| 1153 | }, |
| 1154 | connection->GetWeakPtr(), old_version, new_version)); |
Mingyu Lei | 85c2caf | 2022-12-16 09:46:39 | [diff] [blame] | 1155 | } |
Daniel Murphy | 48b6b3a | 2019-08-07 20:38:25 | [diff] [blame] | 1156 | } |
| 1157 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1158 | void Database::ConnectionClosed(Connection* connection) { |
| 1159 | TRACE_EVENT0("IndexedDB", "Database::ConnectionClosed"); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1160 | // Ignore connection closes during force close to prevent re-entry. |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1161 | if (force_closing_) { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1162 | return; |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1163 | } |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1164 | connections_.erase(connection); |
Evan Stade | 9dc3639 | 2024-10-29 13:10:39 | [diff] [blame] | 1165 | bucket_context_->OnConnectionPriorityUpdated(); |
Daniel Murphy | ede9159 | 2019-08-12 19:50:22 | [diff] [blame] | 1166 | connection_coordinator_.OnConnectionClosed(connection); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1167 | if (connections_.empty()) { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1168 | connection_coordinator_.OnNoConnections(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1169 | } |
| 1170 | if (CanBeDestroyed()) { |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 1171 | bucket_context_->QueueRunTasks(); |
Evan Stade | 4202b1f | 2024-06-12 16:10:54 | [diff] [blame] | 1172 | } |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1173 | } |
| 1174 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1175 | bool Database::CanBeDestroyed() { |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 1176 | return !connection_coordinator_.HasTasks() && connections_.empty(); |
[email protected] | 75a854a | 2014-07-07 15:57:36 | [diff] [blame] | 1177 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 1178 | |
Evan Stade | caa7d18 | 2025-04-30 17:42:12 | [diff] [blame] | 1179 | const IndexedDBObjectStoreMetadata& Database::GetObjectStoreMetadata( |
| 1180 | int64_t object_store_id) const { |
| 1181 | auto object_store_it = metadata().object_stores.find(object_store_id); |
| 1182 | DCHECK(object_store_it != metadata().object_stores.end()); |
| 1183 | return object_store_it->second; |
| 1184 | } |
| 1185 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1186 | } // namespace content::indexed_db |