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/cursor.h" |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 6 | |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 7 | #include <stddef.h> |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 8 | |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 9 | #include <cstdint> |
| 10 | #include <memory> |
dcheng | 36b6aec9 | 2015-12-26 06:16:36 | [diff] [blame] | 11 | #include <utility> |
[email protected] | 4cfd02d | 2014-06-11 18:08:40 | [diff] [blame] | 12 | #include <vector> |
| 13 | |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 14 | #include "base/check.h" |
Hans Wennborg | 0917de89 | 2020-04-28 20:21:15 | [diff] [blame] | 15 | #include "base/check_op.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 16 | #include "base/memory/ptr_util.h" |
| 17 | #include "base/memory/weak_ptr.h" |
Hans Wennborg | 0917de89 | 2020-04-28 20:21:15 | [diff] [blame] | 18 | #include "base/notreached.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 19 | #include "base/trace_event/trace_event.h" |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 20 | #include "content/browser/indexed_db/indexed_db_database_error.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 21 | #include "content/browser/indexed_db/indexed_db_external_object.h" |
[email protected] | 120875f | 2014-03-19 23:08:52 | [diff] [blame] | 22 | #include "content/browser/indexed_db/indexed_db_value.h" |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 23 | #include "content/browser/indexed_db/instance/callback_helpers.h" |
| 24 | #include "content/browser/indexed_db/instance/transaction.h" |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 25 | #include "content/browser/indexed_db/status.h" |
| 26 | #include "mojo/public/cpp/bindings/pending_associated_remote.h" |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 27 | #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" |
Henrique Ferreiro | da0a55c | 2019-11-12 14:06:04 | [diff] [blame] | 28 | #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h" |
Etienne Pierre-doray | e0fb4b16 | 2025-08-07 16:44:48 | [diff] [blame] | 29 | #include "third_party/perfetto/include/perfetto/tracing/track.h" |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 30 | |
Chase Phillips | 68ecf551 | 2018-08-16 01:59:13 | [diff] [blame] | 31 | using blink::IndexedDBKey; |
| 32 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 33 | namespace content::indexed_db { |
dmurph | 9d00e05d | 2016-12-01 23:00:34 | [diff] [blame] | 34 | namespace { |
| 35 | // This should never be script visible: the cursor should either be closed when |
| 36 | // it hits the end of the range (and script throws an error before the call |
| 37 | // could be made), if the transaction has finished (ditto), or if there's an |
| 38 | // incoming request from the front end but the transaction has aborted on the |
| 39 | // back end; in that case the tx will already have sent an abort to the request |
| 40 | // so this would be ignored. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 41 | DatabaseError CreateCursorClosedError() { |
| 42 | return DatabaseError(blink::mojom::IDBException::kUnknownError, |
| 43 | "The cursor has been closed."); |
dmurph | 9d00e05d | 2016-12-01 23:00:34 | [diff] [blame] | 44 | } |
| 45 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 46 | DatabaseError CreateError(blink::mojom::IDBException code, |
| 47 | const char* message, |
| 48 | base::WeakPtr<Transaction> transaction) { |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 49 | if (transaction) { |
Chase Phillips | 091007d | 2019-05-22 22:00:13 | [diff] [blame] | 50 | transaction->IncrementNumErrorsSent(); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 51 | } |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 52 | return DatabaseError(code, message); |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 53 | } |
| 54 | |
dmurph | 9d00e05d | 2016-12-01 23:00:34 | [diff] [blame] | 55 | } // namespace |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 56 | |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 57 | // static |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 58 | Cursor* Cursor::CreateAndBind( |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 59 | std::unique_ptr<BackingStore::Cursor> cursor, |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 60 | indexed_db::CursorType cursor_type, |
| 61 | blink::mojom::IDBTaskType task_type, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 62 | base::WeakPtr<Transaction> transaction, |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 63 | mojo::PendingAssociatedRemote<blink::mojom::IDBCursor>& pending_remote) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 64 | auto instance = base::WrapUnique( |
| 65 | new Cursor(std::move(cursor), cursor_type, task_type, transaction)); |
| 66 | Cursor* instance_ptr = instance.get(); |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 67 | mojo::MakeSelfOwnedAssociatedReceiver( |
| 68 | std::move(instance), pending_remote.InitWithNewEndpointAndPassReceiver()); |
| 69 | return instance_ptr; |
| 70 | } |
| 71 | |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 72 | Cursor::Cursor(std::unique_ptr<BackingStore::Cursor> cursor, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 73 | indexed_db::CursorType cursor_type, |
| 74 | blink::mojom::IDBTaskType task_type, |
| 75 | base::WeakPtr<Transaction> transaction) |
Evan Stade | 5f29b6a9 | 2025-04-02 08:09:53 | [diff] [blame] | 76 | : bucket_locator_(transaction->bucket_context()->bucket_locator()), |
Marijn Kruisselbrink | 145f759 | 2020-02-18 08:49:31 | [diff] [blame] | 77 | task_type_(task_type), |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 78 | cursor_type_(cursor_type), |
Daniel Murphy | 17ee4e5 | 2019-04-29 21:40:29 | [diff] [blame] | 79 | transaction_(std::move(transaction)), |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 80 | cursor_(std::move(cursor)) { |
Etienne Pierre-doray | e0fb4b16 | 2025-08-07 16:44:48 | [diff] [blame] | 81 | TRACE_EVENT_BEGIN("IndexedDB", "Cursor::open", |
| 82 | perfetto::Track::FromPointer(this)); |
dmurph | 84f5e28 | 2017-03-30 00:58:55 | [diff] [blame] | 83 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 84 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 85 | Cursor::~Cursor() { |
dmurph | 84f5e28 | 2017-03-30 00:58:55 | [diff] [blame] | 86 | // Call to make sure we complete our lifetime trace. |
| 87 | Close(); |
| 88 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 89 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 90 | void Cursor::Advance(uint32_t count, |
| 91 | blink::mojom::IDBCursor::AdvanceCallback callback) { |
| 92 | TRACE_EVENT0("IndexedDB", "Cursor::Advance"); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 93 | |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 94 | if (!transaction_) { |
Daniel Murphy | 17ee4e5 | 2019-04-29 21:40:29 | [diff] [blame] | 95 | Close(); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 96 | } |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 97 | if (closed_) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 98 | const DatabaseError error(CreateCursorClosedError()); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 99 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 100 | blink::mojom::IDBError::New(error.code(), error.message()))); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 101 | return; |
| 102 | } |
| 103 | |
Chase Phillips | 091007d | 2019-05-22 22:00:13 | [diff] [blame] | 104 | blink::mojom::IDBCursor::AdvanceCallback aborting_callback = |
| 105 | CreateCallbackAbortOnDestruct<blink::mojom::IDBCursor::AdvanceCallback, |
| 106 | blink::mojom::IDBCursorResultPtr>( |
| 107 | std::move(callback), transaction_); |
| 108 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 109 | transaction_->ScheduleTask( |
| 110 | task_type_, BindWeakOperation<Cursor>(&Cursor::AdvanceOperation, |
| 111 | ptr_factory_.GetWeakPtr(), count, |
| 112 | std::move(aborting_callback))); |
dmurph | 9d00e05d | 2016-12-01 23:00:34 | [diff] [blame] | 113 | } |
| 114 | |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 115 | Status Cursor::AdvanceOperation( |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 116 | uint32_t count, |
Chase Phillips | 9a58b89 | 2019-01-11 22:04:27 | [diff] [blame] | 117 | blink::mojom::IDBCursor::AdvanceCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 118 | Transaction* /*transaction*/) { |
| 119 | TRACE_EVENT0("IndexedDB", "Cursor::AdvanceOperation"); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 120 | |
| 121 | if (!cursor_) { |
| 122 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewEmpty(true)); |
| 123 | return Status::OK(); |
| 124 | } |
| 125 | |
| 126 | if (StatusOr<bool> result = cursor_->Advance(count); |
| 127 | !result.has_value() || !*result) { |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 128 | cursor_.reset(); |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 129 | |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 130 | if (result.has_value()) { |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 131 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewEmpty(true)); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 132 | return Status::OK(); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 133 | } |
Chase Phillips | 9a58b89 | 2019-01-11 22:04:27 | [diff] [blame] | 134 | |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 135 | // CreateError() needs to be called before calling Close() so |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 136 | // |transaction_| is alive. |
Henrique Ferreiro | da0a55c | 2019-11-12 14:06:04 | [diff] [blame] | 137 | auto error = CreateError(blink::mojom::IDBException::kUnknownError, |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 138 | "Error advancing cursor", transaction_); |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 139 | Close(); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 140 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 141 | blink::mojom::IDBError::New(error.code(), error.message()))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 142 | return result.error(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 143 | } |
| 144 | |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 145 | blink::mojom::IDBValuePtr mojo_value; |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 146 | IndexedDBValue* value = Value(); |
| 147 | if (value) { |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 148 | mojo_value = transaction_->BuildMojoValue(std::move(*value)); |
Chase Phillips | 77bf9a95 | 2019-02-21 02:07:09 | [diff] [blame] | 149 | } else { |
| 150 | mojo_value = blink::mojom::IDBValue::New(); |
| 151 | } |
Chase Phillips | 9a58b89 | 2019-01-11 22:04:27 | [diff] [blame] | 152 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 153 | std::vector<IndexedDBKey> keys; |
| 154 | keys.emplace_back(key().Clone()); |
| 155 | std::vector<IndexedDBKey> primary_keys; |
| 156 | primary_keys.emplace_back(primary_key().Clone()); |
Chase Phillips | 0e203582 | 2019-03-13 18:03:56 | [diff] [blame] | 157 | std::vector<blink::mojom::IDBValuePtr> values; |
| 158 | values.push_back(std::move(mojo_value)); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 159 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewValues( |
Chase Phillips | 0e203582 | 2019-03-13 18:03:56 | [diff] [blame] | 160 | blink::mojom::IDBCursorValue::New( |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 161 | std::move(keys), std::move(primary_keys), std::move(values)))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 162 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 163 | } |
| 164 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 165 | void Cursor::Continue(IndexedDBKey key, |
| 166 | IndexedDBKey primary_key, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 167 | blink::mojom::IDBCursor::ContinueCallback callback) { |
| 168 | TRACE_EVENT0("IndexedDB", "Cursor::Continue"); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 169 | if (!transaction_) { |
Daniel Murphy | 17ee4e5 | 2019-04-29 21:40:29 | [diff] [blame] | 170 | Close(); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 171 | } |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 172 | if (closed_) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 173 | const DatabaseError error(CreateCursorClosedError()); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 174 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 175 | blink::mojom::IDBError::New(error.code(), error.message()))); |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 176 | return; |
| 177 | } |
| 178 | |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 179 | blink::mojom::IDBCursor::ContinueCallback aborting_callback = |
| 180 | CreateCallbackAbortOnDestruct<blink::mojom::IDBCursor::ContinueCallback, |
| 181 | blink::mojom::IDBCursorResultPtr>( |
| 182 | std::move(callback), transaction_); |
Chase Phillips | 091007d | 2019-05-22 22:00:13 | [diff] [blame] | 183 | |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 184 | transaction_->ScheduleTask( |
| 185 | task_type_, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 186 | BindWeakOperation<Cursor>( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 187 | &Cursor::ContinueOperation, ptr_factory_.GetWeakPtr(), std::move(key), |
| 188 | std::move(primary_key), std::move(aborting_callback))); |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 189 | } |
| 190 | |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 191 | Status Cursor::ContinueOperation( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 192 | IndexedDBKey key, |
| 193 | IndexedDBKey primary_key, |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 194 | blink::mojom::IDBCursor::ContinueCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 195 | Transaction* /*transaction*/) { |
| 196 | TRACE_EVENT0("IndexedDB", "Cursor::ContinueOperation"); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 197 | |
| 198 | if (!cursor_) { |
| 199 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewEmpty(true)); |
| 200 | return Status::OK(); |
| 201 | } |
| 202 | |
| 203 | if (StatusOr<bool> result = cursor_->Continue(key, primary_key); |
| 204 | !result.has_value() || !*result) { |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 205 | cursor_.reset(); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 206 | if (result.has_value()) { |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 207 | // This happens if we reach the end of the iterator and can't continue. |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 208 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewEmpty(true)); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 209 | return Status::OK(); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 210 | } |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 211 | |
| 212 | // |transaction_| must be valid for CreateError(), so we can't call |
| 213 | // Close() until after calling CreateError(). |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 214 | DatabaseError error = CreateError(blink::mojom::IDBException::kUnknownError, |
| 215 | "Error continuing cursor.", transaction_); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 216 | Close(); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 217 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 218 | blink::mojom::IDBError::New(error.code(), error.message()))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 219 | return result.error(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 220 | } |
| 221 | |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 222 | blink::mojom::IDBValuePtr mojo_value; |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 223 | IndexedDBValue* value = Value(); |
| 224 | if (value) { |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 225 | mojo_value = transaction_->BuildMojoValue(std::move(*value)); |
Chase Phillips | d9377f2a | 2019-03-06 19:30:10 | [diff] [blame] | 226 | } else { |
| 227 | mojo_value = blink::mojom::IDBValue::New(); |
| 228 | } |
| 229 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 230 | std::vector<IndexedDBKey> keys; |
| 231 | keys.emplace_back(this->key().Clone()); |
| 232 | std::vector<IndexedDBKey> primary_keys; |
| 233 | primary_keys.emplace_back(this->primary_key().Clone()); |
Chase Phillips | 0e203582 | 2019-03-13 18:03:56 | [diff] [blame] | 234 | std::vector<blink::mojom::IDBValuePtr> values; |
| 235 | values.push_back(std::move(mojo_value)); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 236 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewValues( |
Chase Phillips | 0e203582 | 2019-03-13 18:03:56 | [diff] [blame] | 237 | blink::mojom::IDBCursorValue::New( |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 238 | std::move(keys), std::move(primary_keys), std::move(values)))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 239 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 240 | } |
| 241 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 242 | void Cursor::Prefetch(int number_to_fetch, |
| 243 | blink::mojom::IDBCursor::PrefetchCallback callback) { |
| 244 | TRACE_EVENT0("IndexedDB", "Cursor::Prefetch"); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 245 | |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 246 | if (!transaction_) { |
Daniel Murphy | 17ee4e5 | 2019-04-29 21:40:29 | [diff] [blame] | 247 | Close(); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 248 | } |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 249 | if (closed_) { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 250 | const DatabaseError error(CreateCursorClosedError()); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 251 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 252 | blink::mojom::IDBError::New(error.code(), error.message()))); |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 253 | return; |
| 254 | } |
| 255 | |
Chase Phillips | 091007d | 2019-05-22 22:00:13 | [diff] [blame] | 256 | blink::mojom::IDBCursor::PrefetchCallback aborting_callback = |
| 257 | CreateCallbackAbortOnDestruct<blink::mojom::IDBCursor::PrefetchCallback, |
| 258 | blink::mojom::IDBCursorResultPtr>( |
| 259 | std::move(callback), transaction_); |
| 260 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 261 | transaction_->ScheduleTask( |
| 262 | task_type_, |
| 263 | BindWeakOperation<Cursor>(&Cursor::PrefetchIterationOperation, |
| 264 | ptr_factory_.GetWeakPtr(), number_to_fetch, |
| 265 | std::move(aborting_callback))); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 266 | } |
| 267 | |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 268 | Status Cursor::PrefetchIterationOperation( |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 269 | int number_to_fetch, |
Chase Phillips | f74e517 | 2019-03-13 20:44:43 | [diff] [blame] | 270 | blink::mojom::IDBCursor::PrefetchCallback callback, |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 271 | Transaction* /*transaction*/) { |
| 272 | TRACE_EVENT0("IndexedDB", "Cursor::PrefetchIterationOperation"); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 273 | |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 274 | Status s = Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 275 | std::vector<IndexedDBKey> found_keys; |
| 276 | std::vector<IndexedDBKey> found_primary_keys; |
[email protected] | 120875f | 2014-03-19 23:08:52 | [diff] [blame] | 277 | std::vector<IndexedDBValue> found_values; |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 278 | |
Tom Sepez | 36c46c0 | 2025-07-11 21:43:56 | [diff] [blame] | 279 | // TODO(cmumford): Use IPC::mojom::kChannelMaximumMessageSize |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 280 | const size_t max_size_estimate = 10 * 1024 * 1024; |
| 281 | size_t size_estimate = 0; |
| 282 | |
[email protected] | b05831e | 2014-04-16 18:32:19 | [diff] [blame] | 283 | // TODO(cmumford): Handle this error (crbug.com/363397). Although this will |
| 284 | // properly fail, caller will not know why, and any corruption |
| 285 | // will be ignored. |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 286 | for (int i = 0; i < number_to_fetch; ++i) { |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 287 | if (!cursor_ || reached_end_during_prefetch_) { |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 288 | break; |
| 289 | } |
| 290 | |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 291 | StatusOr<bool> result = cursor_->Continue(); |
| 292 | if (!result.has_value()) { |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 293 | cursor_.reset(); |
Chase Phillips | f74e517 | 2019-03-13 20:44:43 | [diff] [blame] | 294 | // |transaction_| must be valid for CreateError(), so we can't call |
| 295 | // Close() until after calling CreateError(). |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 296 | DatabaseError error = |
Henrique Ferreiro | da0a55c | 2019-11-12 14:06:04 | [diff] [blame] | 297 | CreateError(blink::mojom::IDBException::kUnknownError, |
Andreas Butler | 32936e3 | 2019-01-26 00:21:32 | [diff] [blame] | 298 | "Error continuing cursor.", transaction_); |
| 299 | Close(); |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 300 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewErrorResult( |
| 301 | blink::mojom::IDBError::New(error.code(), error.message()))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 302 | return result.error(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 303 | } |
| 304 | |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 305 | if (!*result) { |
| 306 | // We've reached the end, so just return what we have. |
| 307 | reached_end_during_prefetch_ = true; |
| 308 | break; |
| 309 | } |
| 310 | |
[email protected] | 9e21543 | 2014-01-07 22:55:04 | [diff] [blame] | 311 | if (i == 0) { |
| 312 | // First prefetched result is always used, so that's the position |
| 313 | // a cursor should be reset to if the prefetch is invalidated. |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 314 | cursor_->SavePosition(); |
[email protected] | 9e21543 | 2014-01-07 22:55:04 | [diff] [blame] | 315 | } |
| 316 | |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 317 | found_keys.emplace_back(cursor_->GetKey().Clone()); |
| 318 | found_primary_keys.emplace_back(cursor_->GetPrimaryKey().Clone()); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 319 | |
[email protected] | 65880a8 | 2013-08-16 21:30:08 | [diff] [blame] | 320 | switch (cursor_type_) { |
Evan Stade | 6265dcd | 2024-02-27 20:50:04 | [diff] [blame] | 321 | case indexed_db::CursorType::kKeyOnly: |
[email protected] | 120875f | 2014-03-19 23:08:52 | [diff] [blame] | 322 | found_values.push_back(IndexedDBValue()); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 323 | break; |
Evan Stade | 6265dcd | 2024-02-27 20:50:04 | [diff] [blame] | 324 | case indexed_db::CursorType::kKeyAndValue: { |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 325 | found_values.push_back(std::move(cursor_->GetValue())); |
| 326 | size_estimate += found_values.back().SizeEstimate(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 327 | break; |
| 328 | } |
| 329 | default: |
Peter Boström | fc7ddc18 | 2024-10-31 19:37:21 | [diff] [blame] | 330 | NOTREACHED(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 331 | } |
Evan Stade | d9529ea5 | 2025-04-11 17:02:50 | [diff] [blame] | 332 | size_estimate += cursor_->GetKey().size_estimate(); |
| 333 | size_estimate += cursor_->GetPrimaryKey().size_estimate(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 334 | |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 335 | if (size_estimate > max_size_estimate) { |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 336 | break; |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 337 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 338 | } |
| 339 | |
thestig | 76ee1f4 | 2016-07-08 18:54:00 | [diff] [blame] | 340 | if (found_keys.empty()) { |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 341 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewEmpty(true)); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 342 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 343 | } |
| 344 | |
Chase Phillips | f74e517 | 2019-03-13 20:44:43 | [diff] [blame] | 345 | DCHECK_EQ(found_keys.size(), found_primary_keys.size()); |
| 346 | DCHECK_EQ(found_keys.size(), found_values.size()); |
| 347 | |
| 348 | std::vector<blink::mojom::IDBValuePtr> mojo_values; |
| 349 | mojo_values.reserve(found_values.size()); |
Evan Stade | 2bc92e8 | 2025-06-04 19:07:36 | [diff] [blame] | 350 | for (IndexedDBValue& value : found_values) { |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 351 | mojo_values.emplace_back(transaction_->BuildMojoValue(std::move(value))); |
Chase Phillips | bc46123 | 2019-05-09 22:35:14 | [diff] [blame] | 352 | } |
Chase Phillips | f74e517 | 2019-03-13 20:44:43 | [diff] [blame] | 353 | |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 354 | std::move(callback).Run(blink::mojom::IDBCursorResult::NewValues( |
Chase Phillips | f74e517 | 2019-03-13 20:44:43 | [diff] [blame] | 355 | blink::mojom::IDBCursorValue::New(std::move(found_keys), |
| 356 | std::move(found_primary_keys), |
Chase Phillips | 284581e | 2019-05-22 21:56:45 | [diff] [blame] | 357 | std::move(mojo_values)))); |
Evan Stade | 5dd95ec2 | 2025-06-10 23:47:26 | [diff] [blame] | 358 | return Status::OK(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 359 | } |
| 360 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 361 | void Cursor::PrefetchReset(int used_prefetches) { |
| 362 | TRACE_EVENT0("IndexedDB", "Cursor::PrefetchReset"); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 363 | if (closed_) { |
Evan Stade | b568dbdc | 2023-08-10 05:21:24 | [diff] [blame] | 364 | return; |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 365 | } |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 366 | |
| 367 | reached_end_during_prefetch_ = false; |
| 368 | if (!cursor_->TryResetToLastSavedPosition()) { |
| 369 | cursor_.reset(); |
| 370 | } |
| 371 | |
dmurph | 50ab051b3 | 2016-11-29 22:13:30 | [diff] [blame] | 372 | // First prefetched result is always used. |
Joshua Bell | 98475ae | 2019-08-15 01:43:36 | [diff] [blame] | 373 | if (cursor_) { |
[email protected] | 9e21543 | 2014-01-07 22:55:04 | [diff] [blame] | 374 | DCHECK_GT(used_prefetches, 0); |
Abhishek Shanthkumar | d9bed3af | 2025-07-01 08:37:03 | [diff] [blame] | 375 | if (used_prefetches > 1) { |
| 376 | auto result = cursor_->Advance(used_prefetches - 1); |
| 377 | DCHECK(!result.has_value() || result.value()); |
| 378 | } |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 379 | } |
Chase Phillips | 4674aa34 | 2019-03-05 01:55:17 | [diff] [blame] | 380 | } |
| 381 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 382 | void Cursor::Close() { |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 383 | if (closed_) { |
dmurph | 84f5e28 | 2017-03-30 00:58:55 | [diff] [blame] | 384 | return; |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 385 | } |
Etienne Pierre-doray | e0fb4b16 | 2025-08-07 16:44:48 | [diff] [blame] | 386 | // Corresponds to the TRACE_EVENT_BEGIN in the constructor. |
| 387 | TRACE_EVENT_END("IndexedDB", perfetto::Track::FromPointer(this)); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 388 | TRACE_EVENT0("IndexedDB", "Cursor::Close"); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 389 | closed_ = true; |
| 390 | cursor_.reset(); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 391 | if (transaction_) { |
Victor Costan | 23303e6f1 | 2019-09-25 20:16:48 | [diff] [blame] | 392 | transaction_->UnregisterOpenCursor(this); |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 393 | } |
Daniel Murphy | 17ee4e5 | 2019-04-29 21:40:29 | [diff] [blame] | 394 | transaction_.reset(); |
[email protected] | 72a4183d | 2013-05-31 18:33:10 | [diff] [blame] | 395 | } |
| 396 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 397 | } // namespace content::indexed_db |