Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: content/browser/indexed_db/indexed_db_database_impl.cc

Issue 15564008: Migrate the IndexedDB backend from Blink to Chromium (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Coding style fixes Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698