Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/indexed_db/indexed_db_database_impl.h" | |
| 6 | |
| 7 #include <math.h> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/auto_reset.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "content/browser/indexed_db/indexed_db_backing_store.h" | |
| 16 #include "content/browser/indexed_db/indexed_db_cursor_impl.h" | |
| 17 #include "content/browser/indexed_db/indexed_db_factory_impl.h" | |
| 18 #include "content/browser/indexed_db/indexed_db_index_writer.h" | |
| 19 #include "content/browser/indexed_db/indexed_db_tracing.h" | |
| 20 #include "content/browser/indexed_db/indexed_db_transaction.h" | |
| 21 #include "content/common/indexed_db/indexed_db_key_path.h" | |
| 22 #include "content/common/indexed_db/indexed_db_key_range.h" | |
| 23 #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseExcep tion.h" | |
| 24 | |
| 25 using base::Int64ToString16; | |
| 26 using WebKit::WebIDBKey; | |
| 27 | |
| 28 namespace content { | |
| 29 | |
| 30 class CreateObjectStoreOperation : public IndexedDBTransaction::Operation { | |
| 31 public: | |
| 32 CreateObjectStoreOperation( | |
| 33 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 34 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
| 35 : backing_store_(backing_store), | |
| 36 object_store_metadata_(object_store_metadata) {} | |
| 37 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 38 | |
| 39 private: | |
| 40 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 41 const IndexedDBObjectStoreMetadata object_store_metadata_; | |
| 42 }; | |
| 43 | |
| 44 class DeleteObjectStoreOperation : public IndexedDBTransaction::Operation { | |
| 45 public: | |
| 46 DeleteObjectStoreOperation( | |
| 47 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 48 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
| 49 : backing_store_(backing_store), | |
| 50 object_store_metadata_(object_store_metadata) {} | |
| 51 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 52 | |
| 53 private: | |
| 54 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 55 const IndexedDBObjectStoreMetadata object_store_metadata_; | |
| 56 }; | |
| 57 | |
| 58 class IndexedDBDatabaseImpl::VersionChangeOperation | |
| 59 : public IndexedDBTransaction::Operation { | |
| 60 public: | |
| 61 VersionChangeOperation( | |
| 62 scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 63 int64_t transaction_id, | |
| 64 int64_t version, | |
| 65 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 66 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks) | |
| 67 : database_(database), | |
| 68 transaction_id_(transaction_id), | |
| 69 version_(version), | |
| 70 callbacks_(callbacks), | |
| 71 database_callbacks_(database_callbacks) {} | |
| 72 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 73 | |
| 74 private: | |
| 75 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 76 int64_t transaction_id_; | |
| 77 int64_t version_; | |
| 78 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 79 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_; | |
| 80 }; | |
| 81 | |
| 82 class CreateObjectStoreAbortOperation : public IndexedDBTransaction::Operation { | |
| 83 public: | |
| 84 CreateObjectStoreAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 85 int64_t object_store_id) | |
| 86 : database_(database), object_store_id_(object_store_id) {} | |
| 87 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 88 | |
| 89 private: | |
| 90 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 91 const int64_t object_store_id_; | |
| 92 }; | |
| 93 | |
| 94 class DeleteObjectStoreAbortOperation : public IndexedDBTransaction::Operation { | |
| 95 public: | |
| 96 DeleteObjectStoreAbortOperation( | |
| 97 scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 98 const IndexedDBObjectStoreMetadata& object_store_metadata) | |
| 99 : database_(database), object_store_metadata_(object_store_metadata) {} | |
| 100 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 101 | |
| 102 private: | |
| 103 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 104 IndexedDBObjectStoreMetadata object_store_metadata_; | |
| 105 }; | |
| 106 | |
| 107 class IndexedDBDatabaseImpl::VersionChangeAbortOperation | |
| 108 : public IndexedDBTransaction::Operation { | |
| 109 public: | |
| 110 VersionChangeAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 111 const string16& previous_version, | |
| 112 int64_t previous_int_version) | |
| 113 : database_(database), | |
| 114 previous_version_(previous_version), | |
| 115 previous_int_version_(previous_int_version) {} | |
| 116 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 117 | |
| 118 private: | |
| 119 scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 120 string16 previous_version_; | |
| 121 int64_t previous_int_version_; | |
| 122 }; | |
| 123 | |
| 124 class CreateIndexOperation : public IndexedDBTransaction::Operation { | |
| 125 public: | |
| 126 CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 127 int64_t object_store_id, | |
| 128 const IndexedDBIndexMetadata& index_metadata) | |
| 129 : backing_store_(backing_store), | |
| 130 object_store_id_(object_store_id), | |
| 131 index_metadata_(index_metadata) {} | |
| 132 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 133 | |
| 134 private: | |
| 135 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 136 const int64_t object_store_id_; | |
| 137 const IndexedDBIndexMetadata index_metadata_; | |
| 138 }; | |
| 139 | |
| 140 class DeleteIndexOperation : public IndexedDBTransaction::Operation { | |
| 141 public: | |
| 142 DeleteIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 143 int64_t object_store_id, | |
| 144 const IndexedDBIndexMetadata& index_metadata) | |
| 145 : backing_store_(backing_store), | |
| 146 object_store_id_(object_store_id), | |
| 147 index_metadata_(index_metadata) {} | |
| 148 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 149 | |
| 150 private: | |
| 151 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 152 const int64_t object_store_id_; | |
| 153 const IndexedDBIndexMetadata index_metadata_; | |
| 154 }; | |
| 155 | |
| 156 class CreateIndexAbortOperation : public IndexedDBTransaction::Operation { | |
| 157 public: | |
| 158 CreateIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 159 int64_t object_store_id, | |
| 160 int64_t index_id) | |
| 161 : database_(database), | |
| 162 object_store_id_(object_store_id), | |
| 163 index_id_(index_id) {} | |
| 164 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 165 | |
| 166 private: | |
| 167 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 168 const int64_t object_store_id_; | |
| 169 const int64_t index_id_; | |
| 170 }; | |
| 171 | |
| 172 class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation { | |
| 173 public: | |
| 174 DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database, | |
| 175 int64_t object_store_id, | |
| 176 const IndexedDBIndexMetadata& index_metadata) | |
| 177 : database_(database), | |
| 178 object_store_id_(object_store_id), | |
| 179 index_metadata_(index_metadata) {} | |
| 180 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 181 | |
| 182 private: | |
| 183 const scoped_refptr<IndexedDBDatabaseImpl> database_; | |
| 184 const int64_t object_store_id_; | |
| 185 const IndexedDBIndexMetadata index_metadata_; | |
| 186 }; | |
| 187 | |
| 188 class GetOperation : public IndexedDBTransaction::Operation { | |
| 189 public: | |
| 190 GetOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 191 const IndexedDBDatabaseMetadata& metadata, | |
| 192 int64_t object_store_id, | |
| 193 int64_t index_id, | |
| 194 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 195 indexed_db::CursorType cursor_type, | |
| 196 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 197 : backing_store_(backing_store), | |
| 198 database_id_(metadata.id), | |
| 199 object_store_id_(object_store_id), | |
| 200 index_id_(index_id), | |
| 201 key_path_(metadata.object_stores.find(object_store_id) | |
| 202 ->second.key_path), | |
| 203 auto_increment_(metadata.object_stores.find(object_store_id) | |
| 204 ->second.auto_increment), | |
| 205 key_range_(key_range.Pass()), | |
| 206 cursor_type_(cursor_type), | |
| 207 callbacks_(callbacks) { | |
| 208 DCHECK(metadata.object_stores.find(object_store_id) != | |
| 209 metadata.object_stores.end()); | |
| 210 DCHECK(metadata.object_stores.find(object_store_id)->second.id == | |
| 211 object_store_id); | |
| 212 } | |
| 213 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 214 | |
| 215 private: | |
| 216 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 217 const int64_t database_id_; | |
| 218 const int64_t object_store_id_; | |
| 219 const int64_t index_id_; | |
| 220 const IndexedDBKeyPath key_path_; | |
| 221 const bool auto_increment_; | |
| 222 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
| 223 const indexed_db::CursorType cursor_type_; | |
| 224 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 225 }; | |
| 226 | |
| 227 class PutOperation : public IndexedDBTransaction::Operation { | |
| 228 public: | |
| 229 PutOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 230 int64_t database_id, | |
| 231 const IndexedDBObjectStoreMetadata& object_store, | |
| 232 std::vector<char>* value, | |
| 233 scoped_ptr<IndexedDBKey> key, | |
| 234 IndexedDBDatabase::PutMode put_mode, | |
| 235 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 236 const std::vector<int64_t>& index_ids, | |
| 237 const std::vector<IndexedDBDatabase::IndexKeys>& index_keys) | |
| 238 : backing_store_(backing_store), | |
| 239 database_id_(database_id), | |
| 240 object_store_(object_store), | |
| 241 key_(key.Pass()), | |
| 242 put_mode_(put_mode), | |
| 243 callbacks_(callbacks), | |
| 244 index_ids_(index_ids), | |
| 245 index_keys_(index_keys) { | |
| 246 value_.swap(*value); | |
| 247 } | |
| 248 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 249 | |
| 250 private: | |
| 251 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 252 const int64_t database_id_; | |
| 253 const IndexedDBObjectStoreMetadata object_store_; | |
| 254 std::vector<char> value_; | |
| 255 scoped_ptr<IndexedDBKey> key_; | |
| 256 const IndexedDBDatabase::PutMode put_mode_; | |
| 257 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 258 const std::vector<int64_t> index_ids_; | |
| 259 const std::vector<IndexedDBDatabase::IndexKeys> index_keys_; | |
| 260 }; | |
| 261 | |
| 262 class SetIndexesReadyOperation : public IndexedDBTransaction::Operation { | |
| 263 public: | |
| 264 explicit SetIndexesReadyOperation(size_t index_count) | |
| 265 : index_count_(index_count) {} | |
| 266 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 267 | |
| 268 private: | |
| 269 const size_t index_count_; | |
| 270 }; | |
| 271 | |
| 272 class OpenCursorOperation : public IndexedDBTransaction::Operation { | |
| 273 public: | |
| 274 OpenCursorOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 275 int64_t database_id, | |
| 276 int64_t object_store_id, | |
| 277 int64_t index_id, | |
| 278 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 279 indexed_db::CursorDirection direction, | |
| 280 indexed_db::CursorType cursor_type, | |
| 281 IndexedDBDatabase::TaskType task_type, | |
| 282 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 283 : backing_store_(backing_store), | |
| 284 database_id_(database_id), | |
| 285 object_store_id_(object_store_id), | |
| 286 index_id_(index_id), | |
| 287 key_range_(key_range.Pass()), | |
| 288 direction_(direction), | |
| 289 cursor_type_(cursor_type), | |
| 290 task_type_(task_type), | |
| 291 callbacks_(callbacks) {} | |
| 292 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 293 | |
| 294 private: | |
| 295 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 296 const int64_t database_id_; | |
| 297 const int64_t object_store_id_; | |
| 298 const int64_t index_id_; | |
| 299 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
| 300 const indexed_db::CursorDirection direction_; | |
| 301 const indexed_db::CursorType cursor_type_; | |
| 302 const IndexedDBDatabase::TaskType task_type_; | |
| 303 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 304 }; | |
| 305 | |
| 306 class CountOperation : public IndexedDBTransaction::Operation { | |
| 307 public: | |
| 308 CountOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 309 int64_t database_id, | |
| 310 int64_t object_store_id, | |
| 311 int64_t index_id, | |
| 312 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 313 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 314 : backing_store_(backing_store), | |
| 315 database_id_(database_id), | |
| 316 object_store_id_(object_store_id), | |
| 317 index_id_(index_id), | |
| 318 key_range_(key_range.Pass()), | |
| 319 callbacks_(callbacks) {} | |
| 320 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 321 | |
| 322 private: | |
| 323 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 324 const int64_t database_id_; | |
| 325 const int64_t object_store_id_; | |
| 326 const int64_t index_id_; | |
| 327 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
| 328 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 329 }; | |
| 330 | |
| 331 class DeleteRangeOperation : public IndexedDBTransaction::Operation { | |
| 332 public: | |
| 333 DeleteRangeOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 334 int64_t database_id, | |
| 335 int64_t object_store_id, | |
| 336 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 337 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 338 : backing_store_(backing_store), | |
| 339 database_id_(database_id), | |
| 340 object_store_id_(object_store_id), | |
| 341 key_range_(key_range.Pass()), | |
| 342 callbacks_(callbacks) {} | |
| 343 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 344 | |
| 345 private: | |
| 346 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 347 const int64_t database_id_; | |
| 348 const int64_t object_store_id_; | |
| 349 const scoped_ptr<IndexedDBKeyRange> key_range_; | |
| 350 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 351 }; | |
| 352 | |
| 353 class ClearOperation : public IndexedDBTransaction::Operation { | |
| 354 public: | |
| 355 ClearOperation(scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 356 int64_t database_id, | |
| 357 int64_t object_store_id, | |
| 358 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 359 : backing_store_(backing_store), | |
| 360 database_id_(database_id), | |
| 361 object_store_id_(object_store_id), | |
| 362 callbacks_(callbacks) {} | |
| 363 virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE; | |
| 364 | |
| 365 private: | |
| 366 const scoped_refptr<IndexedDBBackingStore> backing_store_; | |
| 367 const int64_t database_id_; | |
| 368 const int64_t object_store_id_; | |
| 369 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 370 }; | |
| 371 | |
| 372 class IndexedDBDatabaseImpl::PendingOpenCall { | |
| 373 public: | |
| 374 PendingOpenCall( | |
| 375 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 376 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
| 377 int64_t transaction_id, | |
| 378 int64_t version) | |
| 379 : callbacks_(callbacks), | |
| 380 database_callbacks_(database_callbacks), | |
| 381 version_(version), | |
| 382 transaction_id_(transaction_id) {} | |
| 383 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; } | |
| 384 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> DatabaseCallbacks() { | |
| 385 return database_callbacks_; | |
| 386 } | |
| 387 int64_t Version() { return version_; } | |
| 388 int64_t TransactionId() const { return transaction_id_; } | |
| 389 | |
| 390 private: | |
| 391 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 392 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_; | |
| 393 int64_t version_; | |
| 394 const int64_t transaction_id_; | |
| 395 }; | |
| 396 | |
| 397 class IndexedDBDatabaseImpl::PendingDeleteCall { | |
| 398 public: | |
| 399 explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacksWrapper> callbacks) | |
| 400 : callbacks_(callbacks) {} | |
| 401 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; } | |
| 402 | |
| 403 private: | |
| 404 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_; | |
| 405 }; | |
| 406 | |
| 407 scoped_refptr<IndexedDBDatabaseImpl> IndexedDBDatabaseImpl::Create( | |
| 408 const string16& name, | |
| 409 IndexedDBBackingStore* database, | |
| 410 IndexedDBFactoryImpl* factory, | |
| 411 const string16& unique_identifier) { | |
| 412 scoped_refptr<IndexedDBDatabaseImpl> backend = | |
| 413 new IndexedDBDatabaseImpl(name, database, factory, unique_identifier); | |
| 414 if (!backend->OpenInternal()) | |
| 415 return 0; | |
| 416 return backend; | |
| 417 } | |
| 418 | |
| 419 namespace { | |
| 420 const base::string16::value_type kNoStringVersion[] = { 0 }; | |
| 421 } | |
| 422 | |
| 423 IndexedDBDatabaseImpl::IndexedDBDatabaseImpl( | |
| 424 const string16& name, | |
| 425 IndexedDBBackingStore* backing_store, | |
| 426 IndexedDBFactoryImpl* factory, | |
| 427 const string16& unique_identifier) | |
| 428 : backing_store_(backing_store), | |
| 429 metadata_(name, | |
| 430 kInvalidId, | |
| 431 kNoStringVersion, | |
| 432 IndexedDBDatabaseMetadata::NO_INT_VERSION, | |
| 433 kInvalidId), | |
| 434 identifier_(unique_identifier), | |
| 435 factory_(factory), | |
| 436 running_version_change_transaction_(NULL), | |
| 437 closing_connection_(false) { | |
| 438 DCHECK(!metadata_.name.empty()); | |
| 439 } | |
| 440 | |
| 441 void IndexedDBDatabaseImpl::AddObjectStore( | |
| 442 const IndexedDBObjectStoreMetadata& object_store, | |
| 443 int64_t new_max_object_store_id) { | |
| 444 DCHECK(metadata_.object_stores.find(object_store.id) == | |
| 445 metadata_.object_stores.end()); | |
| 446 if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) { | |
| 447 DCHECK(metadata_.max_object_store_id < new_max_object_store_id); | |
| 448 metadata_.max_object_store_id = new_max_object_store_id; | |
| 449 } | |
| 450 metadata_.object_stores[object_store.id] = object_store; | |
| 451 } | |
| 452 | |
| 453 void IndexedDBDatabaseImpl::RemoveObjectStore(int64_t object_store_id) { | |
| 454 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 455 metadata_.object_stores.end()); | |
| 456 metadata_.object_stores.erase(object_store_id); | |
| 457 } | |
| 458 | |
| 459 void IndexedDBDatabaseImpl::AddIndex(int64_t object_store_id, | |
| 460 const IndexedDBIndexMetadata& index, | |
| 461 int64_t new_max_index_id) { | |
| 462 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 463 metadata_.object_stores.end()); | |
| 464 IndexedDBObjectStoreMetadata object_store = | |
| 465 metadata_.object_stores[object_store_id]; | |
| 466 | |
| 467 DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end()); | |
| 468 object_store.indexes[index.id] = index; | |
| 469 if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) { | |
| 470 DCHECK(object_store.max_index_id < new_max_index_id); | |
| 471 object_store.max_index_id = new_max_index_id; | |
| 472 } | |
| 473 metadata_.object_stores[object_store_id] = object_store; | |
| 474 } | |
| 475 | |
| 476 void IndexedDBDatabaseImpl::RemoveIndex(int64_t object_store_id, | |
| 477 int64_t index_id) { | |
| 478 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 479 metadata_.object_stores.end()); | |
| 480 IndexedDBObjectStoreMetadata object_store = | |
| 481 metadata_.object_stores[object_store_id]; | |
| 482 | |
| 483 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
| 484 object_store.indexes.erase(index_id); | |
| 485 metadata_.object_stores[object_store_id] = object_store; | |
| 486 } | |
| 487 | |
| 488 bool IndexedDBDatabaseImpl::OpenInternal() { | |
| 489 bool success = false; | |
| 490 bool ok = backing_store_->GetIDBDatabaseMetaData( | |
| 491 metadata_.name, &metadata_, success); | |
| 492 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success | |
| 493 << " id_ = " << metadata_.id; | |
| 494 if (!ok) | |
| 495 return false; | |
| 496 if (success) | |
| 497 return backing_store_->GetObjectStores(metadata_.id, | |
| 498 &metadata_.object_stores); | |
| 499 | |
| 500 return backing_store_->CreateIDBDatabaseMetaData( | |
| 501 metadata_.name, metadata_.version, metadata_.int_version, metadata_.id); | |
| 502 } | |
| 503 | |
| 504 IndexedDBDatabaseImpl::~IndexedDBDatabaseImpl() { | |
| 505 DCHECK(transactions_.empty()); | |
| 506 DCHECK(pending_open_calls_.empty()); | |
| 507 DCHECK(pending_delete_calls_.empty()); | |
| 508 } | |
| 509 | |
| 510 scoped_refptr<IndexedDBBackingStore> IndexedDBDatabaseImpl::BackingStore() | |
| 511 const { | |
| 512 return backing_store_; | |
| 513 } | |
| 514 | |
| 515 void IndexedDBDatabaseImpl::CreateObjectStore(int64_t transaction_id, | |
| 516 int64_t object_store_id, | |
| 517 const string16& name, | |
| 518 const IndexedDBKeyPath& key_path, | |
| 519 bool auto_increment) { | |
| 520 IDB_TRACE("IndexedDBDatabaseImpl::create_object_store"); | |
| 521 TransactionMap::const_iterator trans_iterator = | |
| 522 transactions_.find(transaction_id); | |
| 523 if (trans_iterator == transactions_.end()) | |
| 524 return; | |
| 525 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 526 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 527 | |
| 528 DCHECK(metadata_.object_stores.find(object_store_id) == | |
| 529 metadata_.object_stores.end()); | |
| 530 IndexedDBObjectStoreMetadata object_store_metadata( | |
| 531 name, | |
| 532 object_store_id, | |
| 533 key_path, | |
| 534 auto_increment, | |
| 535 IndexedDBDatabase::kMinimumIndexId); | |
| 536 | |
| 537 transaction->ScheduleTask( | |
| 538 new CreateObjectStoreOperation(backing_store_, object_store_metadata), | |
| 539 new CreateObjectStoreAbortOperation(this, object_store_id)); | |
| 540 | |
| 541 AddObjectStore(object_store_metadata, object_store_id); | |
| 542 } | |
| 543 | |
| 544 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
| 545 IDB_TRACE("CreateObjectStoreOperation"); | |
| 546 if (!backing_store_->CreateObjectStore( | |
| 547 transaction->BackingStoreTransaction(), | |
| 548 transaction->database()->id(), | |
| 549 object_store_metadata_.id, | |
| 550 object_store_metadata_.name, | |
| 551 object_store_metadata_.key_path, | |
| 552 object_store_metadata_.auto_increment)) { | |
| 553 string16 error_string = | |
| 554 ASCIIToUTF16("Internal error creating object store '") + | |
| 555 object_store_metadata_.name + ASCIIToUTF16("'."); | |
| 556 | |
| 557 scoped_refptr<IndexedDBDatabaseError> error = | |
| 558 IndexedDBDatabaseError::Create( | |
| 559 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
| 560 transaction->Abort(error); | |
| 561 return; | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 void IndexedDBDatabaseImpl::DeleteObjectStore(int64_t transaction_id, | |
| 566 int64_t object_store_id) { | |
| 567 IDB_TRACE("IndexedDBDatabaseImpl::delete_object_store"); | |
| 568 TransactionMap::const_iterator trans_iterator = | |
| 569 transactions_.find(transaction_id); | |
| 570 if (trans_iterator == transactions_.end()) | |
| 571 return; | |
| 572 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 573 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 574 | |
| 575 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 576 metadata_.object_stores.end()); | |
| 577 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
| 578 metadata_.object_stores[object_store_id]; | |
| 579 | |
| 580 transaction->ScheduleTask( | |
| 581 new DeleteObjectStoreOperation(backing_store_, object_store_metadata), | |
| 582 new DeleteObjectStoreAbortOperation(this, object_store_metadata)); | |
| 583 RemoveObjectStore(object_store_id); | |
| 584 } | |
| 585 | |
| 586 void IndexedDBDatabaseImpl::CreateIndex(int64_t transaction_id, | |
| 587 int64_t object_store_id, | |
| 588 int64_t index_id, | |
| 589 const string16& name, | |
| 590 const IndexedDBKeyPath& key_path, | |
| 591 bool unique, | |
| 592 bool multi_entry) { | |
| 593 IDB_TRACE("IndexedDBDatabaseImpl::create_index"); | |
| 594 TransactionMap::const_iterator trans_iterator = | |
| 595 transactions_.find(transaction_id); | |
| 596 if (trans_iterator == transactions_.end()) | |
| 597 return; | |
| 598 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 599 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 600 | |
| 601 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 602 metadata_.object_stores.end()); | |
| 603 const IndexedDBObjectStoreMetadata object_store = | |
| 604 metadata_.object_stores[object_store_id]; | |
| 605 | |
| 606 DCHECK(object_store.indexes.find(index_id) == object_store.indexes.end()); | |
| 607 const IndexedDBIndexMetadata index_metadata( | |
| 608 name, index_id, key_path, unique, multi_entry); | |
| 609 | |
| 610 transaction->ScheduleTask( | |
| 611 new CreateIndexOperation(backing_store_, object_store_id, index_metadata), | |
| 612 new CreateIndexAbortOperation(this, object_store_id, index_id)); | |
| 613 | |
| 614 AddIndex(object_store_id, index_metadata, index_id); | |
| 615 } | |
| 616 | |
| 617 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
| 618 IDB_TRACE("CreateIndexOperation"); | |
| 619 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(), | |
| 620 transaction->database()->id(), | |
| 621 object_store_id_, | |
| 622 index_metadata_.id, | |
| 623 index_metadata_.name, | |
| 624 index_metadata_.key_path, | |
| 625 index_metadata_.unique, | |
| 626 index_metadata_.multi_entry)) { | |
| 627 string16 error_string = ASCIIToUTF16("Internal error creating index '") + | |
| 628 index_metadata_.name + ASCIIToUTF16("'."); | |
| 629 transaction->Abort(IndexedDBDatabaseError::Create( | |
| 630 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); | |
| 631 return; | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
| 636 IDB_TRACE("CreateIndexAbortOperation"); | |
| 637 DCHECK(!transaction); | |
| 638 database_->RemoveIndex(object_store_id_, index_id_); | |
| 639 } | |
| 640 | |
| 641 void IndexedDBDatabaseImpl::DeleteIndex(int64_t transaction_id, | |
| 642 int64_t object_store_id, | |
| 643 int64_t index_id) { | |
| 644 IDB_TRACE("IndexedDBDatabaseImpl::delete_index"); | |
| 645 TransactionMap::const_iterator trans_iterator = | |
| 646 transactions_.find(transaction_id); | |
| 647 if (trans_iterator == transactions_.end()) | |
| 648 return; | |
| 649 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 650 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 651 | |
| 652 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 653 metadata_.object_stores.end()); | |
| 654 IndexedDBObjectStoreMetadata object_store = | |
| 655 metadata_.object_stores[object_store_id]; | |
| 656 | |
| 657 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); | |
| 658 const IndexedDBIndexMetadata& index_metadata = object_store.indexes[index_id]; | |
| 659 | |
| 660 transaction->ScheduleTask( | |
| 661 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata), | |
| 662 new DeleteIndexAbortOperation(this, object_store_id, index_metadata)); | |
| 663 | |
| 664 RemoveIndex(object_store_id, index_id); | |
| 665 } | |
| 666 | |
| 667 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) { | |
| 668 IDB_TRACE("DeleteIndexOperation"); | |
| 669 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(), | |
| 670 transaction->database()->id(), | |
| 671 object_store_id_, | |
| 672 index_metadata_.id); | |
| 673 if (!ok) { | |
| 674 string16 error_string = ASCIIToUTF16("Internal error deleting index '") + | |
| 675 index_metadata_.name + ASCIIToUTF16("'."); | |
| 676 scoped_refptr<IndexedDBDatabaseError> error = | |
| 677 IndexedDBDatabaseError::Create( | |
| 678 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
| 679 transaction->Abort(error); | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { | |
| 684 IDB_TRACE("DeleteIndexAbortOperation"); | |
| 685 DCHECK(!transaction); | |
| 686 database_->AddIndex( | |
| 687 object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId); | |
| 688 } | |
| 689 | |
| 690 void IndexedDBDatabaseImpl::Commit(int64_t transaction_id) { | |
| 691 // The frontend suggests that we commit, but we may have previously initiated | |
| 692 // an abort, and so have disposed of the transaction. on_abort has already | |
| 693 // been dispatched to the frontend, so it will find out about that | |
| 694 // asynchronously. | |
| 695 if (transactions_.find(transaction_id) != transactions_.end()) | |
| 696 transactions_[transaction_id]->Commit(); | |
| 697 } | |
| 698 | |
| 699 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id) { | |
| 700 // If the transaction is unknown, then it has already been aborted by the | |
| 701 // backend before this call so it is safe to ignore it. | |
| 702 if (transactions_.find(transaction_id) != transactions_.end()) | |
| 703 transactions_[transaction_id]->Abort(); | |
| 704 } | |
| 705 | |
| 706 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id, | |
| 707 scoped_refptr<IndexedDBDatabaseError> error) { | |
| 708 // If the transaction is unknown, then it has already been aborted by the | |
| 709 // backend before this call so it is safe to ignore it. | |
| 710 if (transactions_.find(transaction_id) != transactions_.end()) | |
| 711 transactions_[transaction_id]->Abort(error); | |
| 712 } | |
| 713 | |
| 714 void IndexedDBDatabaseImpl::Get( | |
| 715 int64_t transaction_id, | |
| 716 int64_t object_store_id, | |
| 717 int64_t index_id, | |
| 718 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 719 bool key_only, | |
| 720 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 721 IDB_TRACE("IndexedDBDatabaseImpl::get"); | |
| 722 TransactionMap::const_iterator trans_iterator = | |
| 723 transactions_.find(transaction_id); | |
| 724 if (trans_iterator == transactions_.end()) | |
| 725 return; | |
| 726 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 727 | |
| 728 transaction->ScheduleTask(new GetOperation( | |
| 729 backing_store_, | |
| 730 metadata_, | |
| 731 object_store_id, | |
| 732 index_id, | |
| 733 key_range.Pass(), | |
| 734 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
| 735 callbacks)); | |
| 736 } | |
| 737 | |
| 738 void GetOperation::Perform(IndexedDBTransaction* transaction) { | |
| 739 IDB_TRACE("GetOperation"); | |
| 740 | |
| 741 const IndexedDBKey* key; | |
| 742 | |
| 743 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
| 744 if (key_range_->IsOnlyKey()) { | |
| 745 key = &key_range_->lower(); | |
| 746 } else { | |
| 747 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
| 748 DCHECK(cursor_type_ != indexed_db::CURSOR_KEY_ONLY); | |
| 749 // ObjectStore Retrieval Operation | |
| 750 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
| 751 transaction->BackingStoreTransaction(), | |
| 752 database_id_, | |
| 753 object_store_id_, | |
| 754 *key_range_, | |
| 755 indexed_db::CURSOR_NEXT); | |
| 756 } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
| 757 // Index Value Retrieval Operation | |
| 758 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
| 759 transaction->BackingStoreTransaction(), | |
| 760 database_id_, | |
| 761 object_store_id_, | |
| 762 index_id_, | |
| 763 *key_range_, | |
| 764 indexed_db::CURSOR_NEXT); | |
| 765 } else { | |
| 766 // Index Referenced Value Retrieval Operation | |
| 767 backing_store_cursor = backing_store_->OpenIndexCursor( | |
| 768 transaction->BackingStoreTransaction(), | |
| 769 database_id_, | |
| 770 object_store_id_, | |
| 771 index_id_, | |
| 772 *key_range_, | |
| 773 indexed_db::CURSOR_NEXT); | |
| 774 } | |
| 775 | |
| 776 if (!backing_store_cursor) { | |
| 777 callbacks_->OnSuccess(); | |
| 778 return; | |
| 779 } | |
| 780 | |
| 781 key = &backing_store_cursor->key(); | |
| 782 } | |
| 783 | |
| 784 scoped_ptr<IndexedDBKey> primary_key; | |
| 785 bool ok; | |
| 786 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
| 787 // Object Store Retrieval Operation | |
| 788 std::vector<char> value; | |
| 789 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), | |
| 790 database_id_, | |
| 791 object_store_id_, | |
| 792 *key, | |
| 793 value); | |
| 794 if (!ok) { | |
| 795 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 796 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 797 ASCIIToUTF16("Internal error in get_record."))); | |
| 798 return; | |
| 799 } | |
| 800 | |
| 801 if (value.empty()) { | |
| 802 callbacks_->OnSuccess(); | |
| 803 return; | |
| 804 } | |
| 805 | |
| 806 if (auto_increment_ && !key_path_.IsNull()) { | |
| 807 callbacks_->OnSuccess(&value, *key, key_path_); | |
| 808 return; | |
| 809 } | |
| 810 | |
| 811 callbacks_->OnSuccess(&value); | |
| 812 } | |
| 813 | |
| 814 // From here we are dealing only with indexes. | |
| 815 ok = backing_store_->GetPrimaryKeyViaIndex( | |
| 816 transaction->BackingStoreTransaction(), | |
| 817 database_id_, | |
| 818 object_store_id_, | |
| 819 index_id_, | |
| 820 *key, | |
| 821 &primary_key); | |
| 822 if (!ok) { | |
| 823 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 824 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 825 ASCIIToUTF16("Internal error in get_primary_key_via_index."))); | |
| 826 return; | |
| 827 } | |
| 828 if (!primary_key) { | |
| 829 callbacks_->OnSuccess(); | |
| 830 return; | |
| 831 } | |
| 832 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
| 833 // Index Value Retrieval Operation | |
| 834 callbacks_->OnSuccess(*primary_key); | |
| 835 return; | |
| 836 } | |
| 837 | |
| 838 // Index Referenced Value Retrieval Operation | |
| 839 std::vector<char> value; | |
| 840 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), | |
| 841 database_id_, | |
| 842 object_store_id_, | |
| 843 *primary_key, | |
| 844 value); | |
| 845 if (!ok) { | |
| 846 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 847 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 848 ASCIIToUTF16("Internal error in get_record."))); | |
| 849 return; | |
| 850 } | |
| 851 | |
| 852 if (value.empty()) { | |
| 853 callbacks_->OnSuccess(); | |
| 854 return; | |
| 855 } | |
| 856 if (auto_increment_ && !key_path_.IsNull()) { | |
| 857 callbacks_->OnSuccess(&value, *primary_key, key_path_); | |
| 858 return; | |
| 859 } | |
| 860 callbacks_->OnSuccess(&value); | |
| 861 } | |
| 862 | |
| 863 static scoped_ptr<IndexedDBKey> GenerateKey( | |
| 864 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 865 scoped_refptr<IndexedDBTransaction> transaction, | |
| 866 int64_t database_id, | |
| 867 int64_t object_store_id) { | |
| 868 const int64_t max_generator_value = | |
| 869 9007199254740992LL; // Maximum integer storable as ECMAScript number. | |
| 870 int64_t current_number; | |
| 871 bool ok = backing_store->GetKeyGeneratorCurrentNumber( | |
| 872 transaction->BackingStoreTransaction(), | |
| 873 database_id, | |
| 874 object_store_id, | |
| 875 current_number); | |
| 876 if (!ok) { | |
| 877 LOG(ERROR) << "Failed to get_key_generator_current_number"; | |
| 878 return make_scoped_ptr(new IndexedDBKey()); | |
| 879 } | |
| 880 if (current_number < 0 || current_number > max_generator_value) | |
| 881 return make_scoped_ptr(new IndexedDBKey()); | |
| 882 | |
| 883 return make_scoped_ptr( | |
| 884 new IndexedDBKey(current_number, WebIDBKey::NumberType)); | |
| 885 } | |
| 886 | |
| 887 static bool UpdateKeyGenerator( | |
| 888 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 889 scoped_refptr<IndexedDBTransaction> transaction, | |
| 890 int64_t database_id, | |
| 891 int64_t object_store_id, | |
| 892 const IndexedDBKey* key, | |
| 893 bool check_current) { | |
| 894 DCHECK_EQ(key && key->type(), WebIDBKey::NumberType); | |
| 895 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber( | |
| 896 transaction->BackingStoreTransaction(), | |
| 897 database_id, | |
| 898 object_store_id, | |
| 899 static_cast<int64_t>(floor(key->number())) + 1, | |
| 900 check_current); | |
| 901 } | |
| 902 | |
| 903 void IndexedDBDatabaseImpl::Put( | |
| 904 int64_t transaction_id, | |
| 905 int64_t object_store_id, | |
| 906 std::vector<char>* value, | |
| 907 scoped_ptr<IndexedDBKey> key, | |
| 908 PutMode put_mode, | |
| 909 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 910 const std::vector<int64_t>& index_ids, | |
| 911 const std::vector<IndexKeys>& index_keys) { | |
| 912 IDB_TRACE("IndexedDBDatabaseImpl::put"); | |
| 913 TransactionMap::const_iterator trans_iterator = | |
| 914 transactions_.find(transaction_id); | |
| 915 if (trans_iterator == transactions_.end()) | |
| 916 return; | |
| 917 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 918 DCHECK(transaction->mode() != indexed_db::TRANSACTION_READ_ONLY); | |
| 919 | |
| 920 const IndexedDBObjectStoreMetadata object_store_metadata = | |
| 921 metadata_.object_stores[object_store_id]; | |
| 922 | |
| 923 DCHECK(key); | |
| 924 DCHECK(object_store_metadata.auto_increment || key->IsValid()); | |
| 925 transaction->ScheduleTask(new PutOperation(backing_store_, | |
| 926 id(), | |
| 927 object_store_metadata, | |
| 928 value, | |
| 929 key.Pass(), | |
| 930 put_mode, | |
| 931 callbacks, | |
| 932 index_ids, | |
| 933 index_keys)); | |
| 934 } | |
| 935 | |
| 936 void PutOperation::Perform(IndexedDBTransaction* transaction) { | |
| 937 IDB_TRACE("PutOperation"); | |
| 938 DCHECK(transaction->mode() != indexed_db::TRANSACTION_READ_ONLY); | |
| 939 DCHECK_EQ(index_ids_.size(), index_keys_.size()); | |
| 940 bool key_was_generated = false; | |
| 941 | |
| 942 scoped_ptr<IndexedDBKey> key; | |
| 943 if (put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && | |
| 944 object_store_.auto_increment && !key_->IsValid()) { | |
| 945 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey( | |
| 946 backing_store_, transaction, database_id_, object_store_.id); | |
| 947 key_was_generated = true; | |
| 948 if (!auto_inc_key->IsValid()) { | |
| 949 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 950 WebKit::WebIDBDatabaseExceptionConstraintError, | |
| 951 ASCIIToUTF16("Maximum key generator value reached."))); | |
| 952 return; | |
| 953 } | |
| 954 key = auto_inc_key.Pass(); | |
| 955 } else { | |
| 956 key = key_.Pass(); | |
| 957 } | |
| 958 | |
| 959 DCHECK(key->IsValid()); | |
| 960 | |
| 961 IndexedDBBackingStore::RecordIdentifier record_identifier; | |
| 962 if (put_mode_ == IndexedDBDatabase::ADD_ONLY) { | |
| 963 bool found = false; | |
| 964 bool ok = backing_store_->KeyExistsInObjectStore( | |
| 965 transaction->BackingStoreTransaction(), | |
| 966 database_id_, | |
| 967 object_store_.id, | |
| 968 *key.get(), | |
| 969 &record_identifier, | |
| 970 found); | |
| 971 if (!ok) { | |
| 972 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 973 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 974 ASCIIToUTF16("Internal error checking key existence."))); | |
| 975 return; | |
| 976 } | |
| 977 if (found) { | |
| 978 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 979 WebKit::WebIDBDatabaseExceptionConstraintError, | |
| 980 ASCIIToUTF16("Key already exists in the object store."))); | |
| 981 return; | |
| 982 } | |
| 983 } | |
| 984 | |
| 985 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers; | |
| 986 string16 error_message; | |
| 987 bool obeys_constraints = false; | |
| 988 bool backing_store_success = | |
| 989 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction, | |
| 990 backing_store_.get(), | |
| 991 database_id_, | |
| 992 object_store_, | |
| 993 *key, | |
| 994 key_was_generated, | |
| 995 index_ids_, | |
| 996 index_keys_, | |
| 997 &index_writers, | |
| 998 &error_message, | |
| 999 &obeys_constraints); | |
| 1000 if (!backing_store_success) { | |
| 1001 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1002 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1003 ASCIIToUTF16( | |
| 1004 "Internal error: backing store error updating index keys."))); | |
| 1005 return; | |
| 1006 } | |
| 1007 if (!obeys_constraints) { | |
| 1008 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1009 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); | |
| 1010 return; | |
| 1011 } | |
| 1012 | |
| 1013 // Before this point, don't do any mutation. After this point, rollback the | |
| 1014 // transaction in case of error. | |
| 1015 backing_store_success = | |
| 1016 backing_store_->PutRecord(transaction->BackingStoreTransaction(), | |
| 1017 database_id_, | |
| 1018 object_store_.id, | |
| 1019 *key.get(), | |
| 1020 value_, | |
| 1021 &record_identifier); | |
| 1022 if (!backing_store_success) { | |
| 1023 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1024 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1025 ASCIIToUTF16( | |
| 1026 "Internal error: backing store error performing put/add."))); | |
| 1027 return; | |
| 1028 } | |
| 1029 | |
| 1030 for (size_t i = 0; i < index_writers.size(); ++i) { | |
| 1031 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i]; | |
| 1032 index_writer->WriteIndexKeys(record_identifier, | |
| 1033 backing_store_, | |
| 1034 transaction->BackingStoreTransaction(), | |
| 1035 database_id_, | |
| 1036 object_store_.id); | |
| 1037 } | |
| 1038 | |
| 1039 if (object_store_.auto_increment && | |
| 1040 put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && | |
| 1041 key->type() == WebIDBKey::NumberType) { | |
| 1042 bool ok = UpdateKeyGenerator(backing_store_, | |
| 1043 transaction, | |
| 1044 database_id_, | |
| 1045 object_store_.id, | |
| 1046 key.get(), | |
| 1047 !key_was_generated); | |
| 1048 if (!ok) { | |
| 1049 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1050 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1051 ASCIIToUTF16("Internal error updating key generator."))); | |
| 1052 return; | |
| 1053 } | |
| 1054 } | |
| 1055 | |
| 1056 callbacks_->OnSuccess(*key); | |
| 1057 } | |
| 1058 | |
| 1059 void IndexedDBDatabaseImpl::SetIndexKeys( | |
| 1060 int64_t transaction_id, | |
| 1061 int64_t object_store_id, | |
| 1062 scoped_ptr<IndexedDBKey> primary_key, | |
| 1063 const std::vector<int64_t>& index_ids, | |
| 1064 const std::vector<IndexKeys>& index_keys) { | |
| 1065 IDB_TRACE("IndexedDBDatabaseImpl::set_index_keys"); | |
| 1066 TransactionMap::const_iterator trans_iterator = | |
| 1067 transactions_.find(transaction_id); | |
| 1068 if (trans_iterator == transactions_.end()) | |
| 1069 return; | |
| 1070 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1071 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 1072 | |
| 1073 scoped_refptr<IndexedDBBackingStore> store = BackingStore(); | |
| 1074 // TODO(jsbell): This method could be asynchronous, but we need to evaluate if | |
| 1075 // it's | |
| 1076 // worth the extra complexity. | |
| 1077 IndexedDBBackingStore::RecordIdentifier record_identifier; | |
| 1078 bool found = false; | |
| 1079 bool ok = | |
| 1080 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(), | |
| 1081 metadata_.id, | |
| 1082 object_store_id, | |
| 1083 *primary_key, | |
| 1084 &record_identifier, | |
| 1085 found); | |
| 1086 if (!ok) { | |
| 1087 transaction->Abort(IndexedDBDatabaseError::Create( | |
| 1088 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1089 ASCIIToUTF16("Internal error setting index keys."))); | |
| 1090 return; | |
| 1091 } | |
| 1092 if (!found) { | |
| 1093 scoped_refptr<IndexedDBDatabaseError> error = | |
| 1094 IndexedDBDatabaseError::Create( | |
| 1095 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1096 ASCIIToUTF16( | |
| 1097 "Internal error setting index keys for object store.")); | |
| 1098 transaction->Abort(error); | |
| 1099 return; | |
| 1100 } | |
| 1101 | |
| 1102 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers; | |
| 1103 string16 error_message; | |
| 1104 bool obeys_constraints = false; | |
| 1105 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 1106 metadata_.object_stores.end()); | |
| 1107 const IndexedDBObjectStoreMetadata& object_store_metadata = | |
| 1108 metadata_.object_stores[object_store_id]; | |
| 1109 bool backing_store_success = | |
| 1110 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction, | |
| 1111 store.get(), | |
| 1112 id(), | |
| 1113 object_store_metadata, | |
| 1114 *primary_key, | |
| 1115 false, | |
| 1116 index_ids, | |
| 1117 index_keys, | |
| 1118 &index_writers, | |
| 1119 &error_message, | |
| 1120 &obeys_constraints); | |
| 1121 if (!backing_store_success) { | |
| 1122 transaction->Abort(IndexedDBDatabaseError::Create( | |
| 1123 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1124 ASCIIToUTF16( | |
| 1125 "Internal error: backing store error updating index keys."))); | |
| 1126 return; | |
| 1127 } | |
| 1128 if (!obeys_constraints) { | |
| 1129 transaction->Abort(IndexedDBDatabaseError::Create( | |
| 1130 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); | |
| 1131 return; | |
| 1132 } | |
| 1133 | |
| 1134 for (size_t i = 0; i < index_writers.size(); ++i) { | |
| 1135 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i]; | |
| 1136 index_writer->WriteIndexKeys(record_identifier, | |
| 1137 store.get(), | |
| 1138 transaction->BackingStoreTransaction(), | |
| 1139 id(), | |
| 1140 object_store_id); | |
| 1141 } | |
| 1142 } | |
| 1143 | |
| 1144 void IndexedDBDatabaseImpl::SetIndexesReady( | |
| 1145 int64_t transaction_id, | |
| 1146 int64_t, | |
| 1147 const std::vector<int64_t>& index_ids) { | |
| 1148 IDB_TRACE("IndexedDBObjectStoreImpl::set_indexes_ready"); | |
| 1149 | |
| 1150 TransactionMap::const_iterator trans_iterator = | |
| 1151 transactions_.find(transaction_id); | |
| 1152 if (trans_iterator == transactions_.end()) | |
| 1153 return; | |
| 1154 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1155 | |
| 1156 transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK, | |
| 1157 new SetIndexesReadyOperation(index_ids.size())); | |
| 1158 } | |
| 1159 | |
| 1160 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1161 IDB_TRACE("SetIndexesReadyOperation"); | |
| 1162 for (size_t i = 0; i < index_count_; ++i) | |
| 1163 transaction->DidCompletePreemptiveEvent(); | |
| 1164 } | |
| 1165 | |
| 1166 void IndexedDBDatabaseImpl::OpenCursor( | |
| 1167 int64_t transaction_id, | |
| 1168 int64_t object_store_id, | |
| 1169 int64_t index_id, | |
| 1170 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 1171 indexed_db::CursorDirection direction, | |
| 1172 bool key_only, | |
| 1173 TaskType task_type, | |
| 1174 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1175 IDB_TRACE("IndexedDBDatabaseImpl::open_cursor"); | |
| 1176 TransactionMap::const_iterator trans_iterator = | |
| 1177 transactions_.find(transaction_id); | |
| 1178 if (trans_iterator == transactions_.end()) | |
| 1179 return; | |
| 1180 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1181 | |
| 1182 transaction->ScheduleTask(new OpenCursorOperation( | |
| 1183 backing_store_, | |
| 1184 id(), | |
| 1185 object_store_id, | |
| 1186 index_id, | |
| 1187 key_range.Pass(), | |
| 1188 direction, | |
| 1189 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, | |
| 1190 task_type, | |
| 1191 callbacks)); | |
| 1192 } | |
| 1193 | |
| 1194 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1195 IDB_TRACE("OpenCursorOperation"); | |
| 1196 | |
| 1197 // The frontend has begun indexing, so this pauses the transaction | |
| 1198 // until the indexing is complete. This can't happen any earlier | |
| 1199 // because we don't want to switch to early mode in case multiple | |
| 1200 // indexes are being created in a row, with Put()'s in between. | |
| 1201 if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK) | |
| 1202 transaction->AddPreemptiveEvent(); | |
| 1203 | |
| 1204 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
| 1205 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
| 1206 DCHECK(cursor_type_ != indexed_db::CURSOR_KEY_ONLY); | |
| 1207 backing_store_cursor = backing_store_->OpenObjectStoreCursor( | |
| 1208 transaction->BackingStoreTransaction(), | |
| 1209 database_id_, | |
| 1210 object_store_id_, | |
| 1211 *key_range_, | |
| 1212 direction_); | |
| 1213 } else { | |
| 1214 DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK); | |
| 1215 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { | |
| 1216 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
| 1217 transaction->BackingStoreTransaction(), | |
| 1218 database_id_, | |
| 1219 object_store_id_, | |
| 1220 index_id_, | |
| 1221 *key_range_, | |
| 1222 direction_); | |
| 1223 } else { | |
| 1224 backing_store_cursor = backing_store_->OpenIndexCursor( | |
| 1225 transaction->BackingStoreTransaction(), | |
| 1226 database_id_, | |
| 1227 object_store_id_, | |
| 1228 index_id_, | |
| 1229 *key_range_, | |
| 1230 direction_); | |
| 1231 } | |
| 1232 } | |
| 1233 | |
| 1234 if (!backing_store_cursor) { | |
| 1235 callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL)); | |
| 1236 return; | |
| 1237 } | |
| 1238 | |
| 1239 IndexedDBDatabase::TaskType task_type( | |
| 1240 static_cast<IndexedDBDatabase::TaskType>(task_type_)); | |
| 1241 scoped_refptr<IndexedDBCursorImpl> cursor = | |
| 1242 IndexedDBCursorImpl::Create(backing_store_cursor.Pass(), | |
| 1243 cursor_type_, | |
| 1244 task_type, | |
| 1245 transaction, | |
| 1246 object_store_id_); | |
| 1247 callbacks_->OnSuccess( | |
| 1248 cursor, cursor->key(), cursor->primary_key(), cursor->Value()); | |
| 1249 } | |
| 1250 | |
| 1251 void IndexedDBDatabaseImpl::Count( | |
| 1252 int64_t transaction_id, | |
| 1253 int64_t object_store_id, | |
| 1254 int64_t index_id, | |
| 1255 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 1256 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1257 IDB_TRACE("IndexedDBDatabaseImpl::count"); | |
| 1258 TransactionMap::const_iterator trans_iterator = | |
| 1259 transactions_.find(transaction_id); | |
| 1260 if (trans_iterator == transactions_.end()) | |
| 1261 return; | |
| 1262 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1263 | |
| 1264 DCHECK(metadata_.object_stores.find(object_store_id) != | |
| 1265 metadata_.object_stores.end()); | |
| 1266 transaction->ScheduleTask(new CountOperation(backing_store_, | |
| 1267 id(), | |
| 1268 object_store_id, | |
| 1269 index_id, | |
| 1270 key_range.Pass(), | |
| 1271 callbacks)); | |
| 1272 } | |
| 1273 | |
| 1274 void CountOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1275 IDB_TRACE("CountOperation"); | |
| 1276 uint32_t count = 0; | |
| 1277 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; | |
| 1278 | |
| 1279 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { | |
| 1280 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( | |
| 1281 transaction->BackingStoreTransaction(), | |
| 1282 database_id_, | |
| 1283 object_store_id_, | |
| 1284 *key_range_, | |
| 1285 indexed_db::CURSOR_NEXT); | |
| 1286 } else { | |
| 1287 backing_store_cursor = backing_store_->OpenIndexKeyCursor( | |
| 1288 transaction->BackingStoreTransaction(), | |
| 1289 database_id_, | |
| 1290 object_store_id_, | |
| 1291 index_id_, | |
| 1292 *key_range_, | |
| 1293 indexed_db::CURSOR_NEXT); | |
| 1294 } | |
| 1295 if (!backing_store_cursor) { | |
| 1296 callbacks_->OnSuccess(count); | |
| 1297 return; | |
| 1298 } | |
| 1299 | |
| 1300 do { | |
| 1301 ++count; | |
| 1302 } while (backing_store_cursor->ContinueFunction(0)); | |
| 1303 | |
| 1304 callbacks_->OnSuccess(count); | |
| 1305 } | |
| 1306 | |
| 1307 void IndexedDBDatabaseImpl::DeleteRange( | |
| 1308 int64_t transaction_id, | |
| 1309 int64_t object_store_id, | |
| 1310 scoped_ptr<IndexedDBKeyRange> key_range, | |
| 1311 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1312 IDB_TRACE("IndexedDBDatabaseImpl::delete_range"); | |
| 1313 TransactionMap::const_iterator trans_iterator = | |
| 1314 transactions_.find(transaction_id); | |
| 1315 if (trans_iterator == transactions_.end()) | |
| 1316 return; | |
| 1317 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1318 | |
| 1319 transaction->ScheduleTask(new DeleteRangeOperation( | |
| 1320 backing_store_, id(), object_store_id, key_range.Pass(), callbacks)); | |
| 1321 } | |
| 1322 | |
| 1323 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1324 IDB_TRACE("DeleteRangeOperation"); | |
| 1325 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
| 1326 backing_store_->OpenObjectStoreCursor( | |
| 1327 transaction->BackingStoreTransaction(), | |
| 1328 database_id_, | |
| 1329 object_store_id_, | |
| 1330 *key_range_, | |
| 1331 indexed_db::CURSOR_NEXT); | |
| 1332 if (backing_store_cursor) { | |
| 1333 do { | |
| 1334 if (!backing_store_->DeleteRecord( | |
| 1335 transaction->BackingStoreTransaction(), | |
| 1336 database_id_, | |
| 1337 object_store_id_, | |
| 1338 backing_store_cursor->record_identifier())) { | |
| 1339 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1340 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1341 ASCIIToUTF16("Internal error deleting data in range"))); | |
| 1342 return; | |
| 1343 } | |
| 1344 } while (backing_store_cursor->ContinueFunction(0)); | |
| 1345 } | |
| 1346 | |
| 1347 callbacks_->OnSuccess(); | |
| 1348 } | |
| 1349 | |
| 1350 void IndexedDBDatabaseImpl::Clear( | |
| 1351 int64_t transaction_id, | |
| 1352 int64_t object_store_id, | |
| 1353 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1354 IDB_TRACE("IndexedDBDatabaseImpl::clear"); | |
| 1355 TransactionMap::const_iterator trans_iterator = | |
| 1356 transactions_.find(transaction_id); | |
| 1357 if (trans_iterator == transactions_.end()) | |
| 1358 return; | |
| 1359 IndexedDBTransaction* transaction = trans_iterator->second; | |
| 1360 DCHECK(transaction->mode() != indexed_db::TRANSACTION_READ_ONLY); | |
| 1361 | |
| 1362 transaction->ScheduleTask( | |
| 1363 new ClearOperation(backing_store_, id(), object_store_id, callbacks)); | |
| 1364 } | |
| 1365 | |
| 1366 void ClearOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1367 IDB_TRACE("ObjectStoreClearOperation"); | |
| 1368 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(), | |
| 1369 database_id_, | |
| 1370 object_store_id_)) { | |
| 1371 callbacks_->OnError(IndexedDBDatabaseError::Create( | |
| 1372 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1373 ASCIIToUTF16("Internal error clearing object store"))); | |
| 1374 return; | |
| 1375 } | |
| 1376 callbacks_->OnSuccess(); | |
| 1377 } | |
| 1378 | |
| 1379 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { | |
| 1380 IDB_TRACE("DeleteObjectStoreOperation"); | |
| 1381 bool ok = | |
| 1382 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), | |
| 1383 transaction->database()->id(), | |
| 1384 object_store_metadata_.id); | |
| 1385 if (!ok) { | |
| 1386 string16 error_string = | |
| 1387 ASCIIToUTF16("Internal error deleting object store '") + | |
| 1388 object_store_metadata_.name + ASCIIToUTF16("'."); | |
| 1389 scoped_refptr<IndexedDBDatabaseError> error = | |
| 1390 IndexedDBDatabaseError::Create( | |
| 1391 WebKit::WebIDBDatabaseExceptionUnknownError, error_string); | |
| 1392 transaction->Abort(error); | |
| 1393 } | |
| 1394 } | |
| 1395 | |
| 1396 void IndexedDBDatabaseImpl::VersionChangeOperation::Perform( | |
| 1397 IndexedDBTransaction* transaction) { | |
| 1398 IDB_TRACE("VersionChangeOperation"); | |
| 1399 int64_t database_id = database_->id(); | |
| 1400 int64_t old_version = database_->metadata_.int_version; | |
| 1401 DCHECK(version_ > old_version); | |
| 1402 database_->metadata_.int_version = version_; | |
| 1403 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion( | |
| 1404 transaction->BackingStoreTransaction(), | |
| 1405 database_id, | |
| 1406 database_->metadata_.int_version)) { | |
| 1407 scoped_refptr<IndexedDBDatabaseError> error = | |
| 1408 IndexedDBDatabaseError::Create( | |
| 1409 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1410 ASCIIToUTF16("Internal error writing data to stable storage when " | |
| 1411 "updating version.")); | |
| 1412 callbacks_->OnError(error); | |
| 1413 transaction->Abort(error); | |
| 1414 return; | |
| 1415 } | |
| 1416 DCHECK(!database_->pending_second_half_open_); | |
| 1417 database_->pending_second_half_open_.reset(new PendingOpenCall( | |
| 1418 callbacks_, database_callbacks_, transaction_id_, version_)); | |
| 1419 callbacks_->OnUpgradeNeeded(old_version, database_, database_->metadata()); | |
| 1420 } | |
| 1421 | |
| 1422 void IndexedDBDatabaseImpl::TransactionStarted( | |
| 1423 IndexedDBTransaction* transaction) { | |
| 1424 | |
| 1425 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
| 1426 DCHECK(!running_version_change_transaction_); | |
| 1427 running_version_change_transaction_ = transaction; | |
| 1428 } | |
| 1429 } | |
| 1430 | |
| 1431 void IndexedDBDatabaseImpl::TransactionFinished( | |
| 1432 IndexedDBTransaction* transaction) { | |
| 1433 | |
| 1434 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); | |
| 1435 DCHECK_EQ(transactions_[transaction->id()], transaction); | |
| 1436 transactions_.erase(transaction->id()); | |
| 1437 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
| 1438 DCHECK_EQ(transaction, running_version_change_transaction_); | |
| 1439 running_version_change_transaction_ = NULL; | |
| 1440 } | |
| 1441 } | |
| 1442 | |
| 1443 void IndexedDBDatabaseImpl::TransactionFinishedAndAbortFired( | |
| 1444 IndexedDBTransaction* transaction) { | |
| 1445 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
| 1446 if (pending_second_half_open_) { | |
| 1447 pending_second_half_open_->Callbacks() | |
| 1448 ->OnError(IndexedDBDatabaseError::Create( | |
| 1449 WebKit::WebIDBDatabaseExceptionAbortError, | |
| 1450 ASCIIToUTF16("Version change transaction was aborted in " | |
| 1451 "upgradeneeded event handler."))); | |
| 1452 pending_second_half_open_.reset(); | |
| 1453 } | |
| 1454 ProcessPendingCalls(); | |
| 1455 } | |
| 1456 } | |
| 1457 | |
| 1458 void IndexedDBDatabaseImpl::TransactionFinishedAndCompleteFired( | |
| 1459 IndexedDBTransaction* transaction) { | |
| 1460 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { | |
| 1461 DCHECK(pending_second_half_open_); | |
| 1462 if (pending_second_half_open_) { | |
| 1463 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
| 1464 DCHECK(metadata_.id != kInvalidId); | |
| 1465 pending_second_half_open_->Callbacks()->OnSuccess(this, this->metadata()); | |
| 1466 pending_second_half_open_.reset(); | |
| 1467 } | |
| 1468 ProcessPendingCalls(); | |
| 1469 } | |
| 1470 } | |
| 1471 | |
| 1472 size_t IndexedDBDatabaseImpl::ConnectionCount() const { | |
| 1473 // This does not include pending open calls, as those should not block version | |
| 1474 // changes and deletes. | |
| 1475 return database_callbacks_set_.size(); | |
| 1476 } | |
| 1477 | |
| 1478 void IndexedDBDatabaseImpl::ProcessPendingCalls() { | |
| 1479 if (pending_second_half_open_) { | |
| 1480 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); | |
| 1481 DCHECK(metadata_.id != kInvalidId); | |
| 1482 scoped_ptr<PendingOpenCall> pending_call = pending_second_half_open_.Pass(); | |
| 1483 pending_call->Callbacks()->OnSuccess(this, this->metadata()); | |
| 1484 // Fall through when complete, as pending opens may be unblocked. | |
| 1485 } | |
| 1486 | |
| 1487 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { | |
| 1488 DCHECK(pending_run_version_change_transaction_call_->Version() > | |
| 1489 metadata_.int_version); | |
| 1490 scoped_ptr<PendingOpenCall> pending_call = | |
| 1491 pending_run_version_change_transaction_call_.Pass(); | |
| 1492 RunVersionChangeTransactionFinal(pending_call->Callbacks(), | |
| 1493 pending_call->DatabaseCallbacks(), | |
| 1494 pending_call->TransactionId(), | |
| 1495 pending_call->Version()); | |
| 1496 DCHECK(ConnectionCount() == 1); | |
| 1497 // Fall through would be a no-op, since transaction must complete | |
| 1498 // asynchronously. | |
| 1499 DCHECK(IsDeleteDatabaseBlocked()); | |
| 1500 DCHECK(IsOpenConnectionBlocked()); | |
| 1501 return; | |
| 1502 } | |
| 1503 | |
| 1504 if (!IsDeleteDatabaseBlocked()) { | |
| 1505 PendingDeleteCallList pending_delete_calls; | |
| 1506 pending_delete_calls_.swap(pending_delete_calls); | |
| 1507 while (!pending_delete_calls.empty()) { | |
| 1508 // Only the first delete call will delete the database, but each must fire | |
| 1509 // callbacks. | |
| 1510 scoped_ptr<PendingDeleteCall> pending_delete_call( | |
| 1511 pending_delete_calls.front()); | |
| 1512 pending_delete_calls.pop_front(); | |
| 1513 DeleteDatabaseFinal(pending_delete_call->Callbacks()); | |
| 1514 } | |
| 1515 // delete_database_final should never re-queue calls. | |
| 1516 DCHECK(pending_delete_calls_.empty()); | |
| 1517 // Fall through when complete, as pending opens may be unblocked. | |
| 1518 } | |
| 1519 | |
| 1520 if (!IsOpenConnectionBlocked()) { | |
| 1521 PendingOpenCallList pending_open_calls; | |
| 1522 pending_open_calls_.swap(pending_open_calls); | |
| 1523 while (!pending_open_calls.empty()) { | |
| 1524 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); | |
| 1525 pending_open_calls.pop_front(); | |
| 1526 OpenConnection(pending_open_call->Callbacks(), | |
| 1527 pending_open_call->DatabaseCallbacks(), | |
| 1528 pending_open_call->TransactionId(), | |
| 1529 pending_open_call->Version()); | |
| 1530 } | |
| 1531 } | |
| 1532 } | |
| 1533 | |
| 1534 void IndexedDBDatabaseImpl::CreateTransaction( | |
| 1535 int64_t transaction_id, | |
| 1536 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks, | |
| 1537 const std::vector<int64_t>& object_store_ids, | |
| 1538 unsigned short mode) { | |
| 1539 | |
| 1540 DCHECK(database_callbacks_set_.has(callbacks)); | |
| 1541 | |
| 1542 scoped_refptr<IndexedDBTransaction> transaction = | |
| 1543 IndexedDBTransaction::Create( | |
| 1544 transaction_id, | |
| 1545 callbacks, | |
| 1546 object_store_ids, | |
| 1547 static_cast<indexed_db::TransactionMode>(mode), | |
| 1548 this); | |
| 1549 DCHECK(transactions_.find(transaction_id) == transactions_.end()); | |
| 1550 transactions_[transaction_id] = transaction; | |
| 1551 } | |
| 1552 | |
| 1553 bool IndexedDBDatabaseImpl::IsOpenConnectionBlocked() const { | |
| 1554 return !pending_delete_calls_.empty() || | |
| 1555 running_version_change_transaction_ || | |
| 1556 pending_run_version_change_transaction_call_; | |
| 1557 } | |
| 1558 | |
| 1559 void IndexedDBDatabaseImpl::OpenConnection( | |
| 1560 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 1561 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
| 1562 int64_t transaction_id, | |
| 1563 int64_t version) { | |
| 1564 DCHECK(backing_store_.get()); | |
| 1565 | |
| 1566 // TODO(jsbell): Should have a priority queue so that higher version requests | |
| 1567 // are | |
|
dgrogan
2013/05/22 18:22:06
There are a few of these bad comment wraps.
jsbell
2013/05/22 22:21:14
Done.
| |
| 1568 // processed first. http://crbug.com/225850 | |
| 1569 if (IsOpenConnectionBlocked()) { | |
| 1570 pending_open_calls_.push_back(new PendingOpenCall( | |
| 1571 callbacks, database_callbacks, transaction_id, version)); | |
| 1572 return; | |
| 1573 } | |
| 1574 | |
| 1575 if (metadata_.id == kInvalidId) { | |
| 1576 // The database was deleted then immediately re-opened; OpenInternal() | |
| 1577 // recreates it in the backing store. | |
| 1578 if (OpenInternal()) { | |
| 1579 DCHECK_EQ(metadata_.int_version, | |
| 1580 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
| 1581 } else { | |
| 1582 string16 message; | |
| 1583 scoped_refptr<IndexedDBDatabaseError> error; | |
| 1584 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) | |
| 1585 message = ASCIIToUTF16( | |
| 1586 "Internal error opening database with no version specified."); | |
| 1587 else | |
| 1588 message = | |
| 1589 ASCIIToUTF16("Internal error opening database with version ") + | |
| 1590 Int64ToString16(version); | |
| 1591 callbacks->OnError(IndexedDBDatabaseError::Create( | |
| 1592 WebKit::WebIDBDatabaseExceptionUnknownError, message)); | |
| 1593 return; | |
| 1594 } | |
| 1595 } | |
| 1596 | |
| 1597 // We infer that the database didn't exist from its lack of either type of | |
| 1598 // version. | |
| 1599 bool is_new_database = | |
| 1600 metadata_.version == kNoStringVersion && | |
| 1601 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
| 1602 | |
| 1603 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { | |
| 1604 // For unit tests only - skip upgrade steps. Calling from script with | |
| 1605 // DEFAULT_INT_VERSION throws exception. | |
| 1606 // TODO(jsbell): Assert that we're executing a unit test. | |
| 1607 DCHECK(is_new_database); | |
| 1608 database_callbacks_set_.insert(database_callbacks); | |
| 1609 callbacks->OnSuccess(this, this->metadata()); | |
| 1610 return; | |
| 1611 } | |
| 1612 | |
| 1613 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { | |
| 1614 if (!is_new_database) { | |
| 1615 database_callbacks_set_.insert(database_callbacks); | |
| 1616 callbacks->OnSuccess(this, this->metadata()); | |
| 1617 return; | |
| 1618 } | |
| 1619 // Spec says: If no version is specified and no database exists, set | |
| 1620 // database version to 1. | |
| 1621 version = 1; | |
| 1622 } | |
| 1623 | |
| 1624 if (version > metadata_.int_version) { | |
| 1625 database_callbacks_set_.insert(database_callbacks); | |
| 1626 RunVersionChangeTransaction( | |
| 1627 callbacks, database_callbacks, transaction_id, version); | |
| 1628 return; | |
| 1629 } | |
| 1630 if (version < metadata_.int_version) { | |
| 1631 callbacks->OnError(IndexedDBDatabaseError::Create( | |
| 1632 WebKit::WebIDBDatabaseExceptionVersionError, | |
| 1633 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + | |
| 1634 ASCIIToUTF16(") is less than the existing version (") + | |
| 1635 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); | |
| 1636 return; | |
| 1637 } | |
| 1638 DCHECK_EQ(version, metadata_.int_version); | |
| 1639 database_callbacks_set_.insert(database_callbacks); | |
| 1640 callbacks->OnSuccess(this, this->metadata()); | |
| 1641 } | |
| 1642 | |
| 1643 void IndexedDBDatabaseImpl::RunVersionChangeTransaction( | |
| 1644 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 1645 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
| 1646 int64_t transaction_id, | |
| 1647 int64_t requested_version) { | |
| 1648 | |
| 1649 DCHECK(callbacks); | |
| 1650 DCHECK(database_callbacks_set_.has(database_callbacks)); | |
| 1651 if (ConnectionCount() > 1) { | |
| 1652 // Front end ensures the event is not fired at connections that have | |
| 1653 // close_pending set. | |
| 1654 for (DatabaseCallbacksSet::const_iterator it = | |
| 1655 database_callbacks_set_.begin(); | |
| 1656 it != database_callbacks_set_.end(); | |
| 1657 ++it) { | |
| 1658 if (*it != database_callbacks.get()) | |
| 1659 (*it)->OnVersionChange(metadata_.int_version, requested_version); | |
| 1660 } | |
| 1661 // TODO(jsbell): Remove the call to on_blocked and instead wait until the | |
| 1662 // frontend | |
|
dgrogan
2013/05/22 18:22:06
comment wrapping
jsbell
2013/05/22 19:13:04
Done.
| |
| 1663 // tells us that all the "versionchange" events have been delivered. | |
| 1664 // http://crbug.com/100123 | |
| 1665 callbacks->OnBlocked(metadata_.int_version); | |
| 1666 | |
| 1667 DCHECK(!pending_run_version_change_transaction_call_); | |
| 1668 pending_run_version_change_transaction_call_.reset(new PendingOpenCall( | |
| 1669 callbacks, database_callbacks, transaction_id, requested_version)); | |
| 1670 return; | |
| 1671 } | |
| 1672 RunVersionChangeTransactionFinal( | |
| 1673 callbacks, database_callbacks, transaction_id, requested_version); | |
| 1674 } | |
| 1675 | |
| 1676 void IndexedDBDatabaseImpl::RunVersionChangeTransactionFinal( | |
| 1677 scoped_refptr<IndexedDBCallbacksWrapper> callbacks, | |
| 1678 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks, | |
| 1679 int64_t transaction_id, | |
| 1680 int64_t requested_version) { | |
| 1681 | |
| 1682 std::vector<int64_t> object_store_ids; | |
| 1683 CreateTransaction(transaction_id, | |
| 1684 database_callbacks, | |
| 1685 object_store_ids, | |
| 1686 indexed_db::TRANSACTION_VERSION_CHANGE); | |
| 1687 scoped_refptr<IndexedDBTransaction> transaction = | |
| 1688 transactions_[transaction_id]; | |
| 1689 | |
| 1690 transaction->ScheduleTask( | |
| 1691 new VersionChangeOperation(this, | |
| 1692 transaction_id, | |
| 1693 requested_version, | |
| 1694 callbacks, | |
| 1695 database_callbacks), | |
| 1696 new VersionChangeAbortOperation( | |
| 1697 this, metadata_.version, metadata_.int_version)); | |
| 1698 | |
| 1699 DCHECK(!pending_second_half_open_); | |
| 1700 } | |
| 1701 | |
| 1702 void IndexedDBDatabaseImpl::DeleteDatabase( | |
| 1703 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1704 | |
| 1705 if (IsDeleteDatabaseBlocked()) { | |
| 1706 for (DatabaseCallbacksSet::const_iterator it = | |
| 1707 database_callbacks_set_.begin(); | |
| 1708 it != database_callbacks_set_.end(); | |
| 1709 ++it) { | |
| 1710 // Front end ensures the event is not fired at connections that have | |
| 1711 // close_pending set. | |
| 1712 (*it)->OnVersionChange(metadata_.int_version, | |
| 1713 IndexedDBDatabaseMetadata::NO_INT_VERSION); | |
| 1714 } | |
| 1715 // TODO(jsbell): Only fire on_blocked if there are open connections after | |
| 1716 // the | |
|
dgrogan
2013/05/22 18:22:06
comment wrapping
jsbell
2013/05/22 19:13:04
Done.
| |
| 1717 // VersionChangeEvents are received, not just set up to fire. | |
| 1718 // http://crbug.com/100123 | |
| 1719 callbacks->OnBlocked(metadata_.int_version); | |
| 1720 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); | |
| 1721 return; | |
| 1722 } | |
| 1723 DeleteDatabaseFinal(callbacks); | |
| 1724 } | |
| 1725 | |
| 1726 bool IndexedDBDatabaseImpl::IsDeleteDatabaseBlocked() const { | |
| 1727 return ConnectionCount(); | |
| 1728 } | |
| 1729 | |
| 1730 void IndexedDBDatabaseImpl::DeleteDatabaseFinal( | |
| 1731 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) { | |
| 1732 DCHECK(!IsDeleteDatabaseBlocked()); | |
| 1733 DCHECK(backing_store_); | |
| 1734 if (!backing_store_->DeleteDatabase(metadata_.name)) { | |
| 1735 callbacks->OnError(IndexedDBDatabaseError::Create( | |
| 1736 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1737 ASCIIToUTF16("Internal error deleting database."))); | |
| 1738 return; | |
| 1739 } | |
| 1740 metadata_.version = kNoStringVersion; | |
| 1741 metadata_.id = kInvalidId; | |
| 1742 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | |
| 1743 metadata_.object_stores.clear(); | |
| 1744 callbacks->OnSuccess(); | |
| 1745 } | |
| 1746 | |
| 1747 void IndexedDBDatabaseImpl::Close( | |
| 1748 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks) { | |
| 1749 DCHECK(callbacks); | |
| 1750 DCHECK(database_callbacks_set_.has(callbacks)); | |
| 1751 | |
| 1752 // Close outstanding transactions from the closing connection. This | |
| 1753 // can not happen if the close is requested by the connection itself | |
| 1754 // as the front-end defers the close until all transactions are | |
| 1755 // complete, so something unusual has happened e.g. unexpected | |
| 1756 // process termination. | |
| 1757 { | |
| 1758 TransactionMap transactions(transactions_); | |
| 1759 for (TransactionMap::const_iterator it = transactions.begin(), | |
| 1760 end = transactions.end(); | |
| 1761 it != end; | |
| 1762 ++it) { | |
| 1763 if (it->second->connection() == callbacks) | |
| 1764 it->second->Abort(IndexedDBDatabaseError::Create( | |
| 1765 WebKit::WebIDBDatabaseExceptionUnknownError, | |
| 1766 ASCIIToUTF16("Connection is closing."))); | |
| 1767 } | |
| 1768 } | |
| 1769 | |
| 1770 database_callbacks_set_.erase(callbacks); | |
| 1771 if (pending_second_half_open_ && | |
| 1772 pending_second_half_open_->DatabaseCallbacks() == callbacks) { | |
| 1773 pending_second_half_open_->Callbacks() | |
| 1774 ->OnError(IndexedDBDatabaseError::Create( | |
| 1775 WebKit::WebIDBDatabaseExceptionAbortError, | |
| 1776 ASCIIToUTF16("The connection was closed."))); | |
| 1777 pending_second_half_open_.reset(); | |
| 1778 } | |
| 1779 | |
| 1780 // process_pending_calls allows the inspector to process a pending open call | |
| 1781 // and call close, reentering IndexedDBDatabaseImpl::close. Then the | |
| 1782 // backend would be removed both by the inspector closing its connection, and | |
| 1783 // by the connection that first called close. | |
| 1784 // To avoid that situation, don't proceed in case of reentrancy. | |
| 1785 if (closing_connection_) | |
| 1786 return; | |
| 1787 base::AutoReset<bool> ClosingConnection(&closing_connection_, true); | |
| 1788 ProcessPendingCalls(); | |
| 1789 | |
| 1790 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. | |
| 1791 if (!ConnectionCount() && !pending_open_calls_.size() && | |
| 1792 !pending_delete_calls_.size()) { | |
| 1793 DCHECK(transactions_.empty()); | |
| 1794 | |
| 1795 backing_store_ = NULL; | |
| 1796 | |
| 1797 // This check should only be false in unit tests. | |
| 1798 // TODO(jsbell): Assert factory_ || we're executing a unit test. | |
| 1799 if (factory_) | |
| 1800 factory_->RemoveIDBDatabaseBackend(identifier_); | |
| 1801 } | |
| 1802 } | |
| 1803 | |
| 1804 void CreateObjectStoreAbortOperation::Perform( | |
| 1805 IndexedDBTransaction* transaction) { | |
| 1806 IDB_TRACE("CreateObjectStoreAbortOperation"); | |
| 1807 DCHECK(!transaction); | |
| 1808 database_->RemoveObjectStore(object_store_id_); | |
| 1809 } | |
| 1810 | |
| 1811 void DeleteObjectStoreAbortOperation::Perform( | |
| 1812 IndexedDBTransaction* transaction) { | |
| 1813 IDB_TRACE("DeleteObjectStoreAbortOperation"); | |
| 1814 DCHECK(!transaction); | |
| 1815 database_->AddObjectStore(object_store_metadata_, | |
| 1816 IndexedDBObjectStoreMetadata::kInvalidId); | |
| 1817 } | |
| 1818 | |
| 1819 void IndexedDBDatabaseImpl::VersionChangeAbortOperation::Perform( | |
| 1820 IndexedDBTransaction* transaction) { | |
| 1821 IDB_TRACE("VersionChangeAbortOperation"); | |
| 1822 DCHECK(!transaction); | |
| 1823 database_->metadata_.version = previous_version_; | |
| 1824 database_->metadata_.int_version = previous_int_version_; | |
| 1825 } | |
| 1826 | |
| 1827 } // namespace content | |
| OLD | NEW |