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

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

Issue 16581002: IndexedDB: Eliminate interfaces for IndexedDB{Factory,Database,Cursor} (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 7 years, 6 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/strings/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/public/platform/WebIDBDatabaseException.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 transaction_id,
64 int64 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 transaction_id_;
77 int64 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 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 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 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 previous_int_version_;
122 };
123
124 class CreateIndexOperation : public IndexedDBTransaction::Operation {
125 public:
126 CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
127 int64 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 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 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 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 object_store_id,
160 int64 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 object_store_id_;
169 const int64 index_id_;
170 };
171
172 class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation {
173 public:
174 DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database,
175 int64 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 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 object_store_id,
193 int64 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 database_id_;
218 const int64 object_store_id_;
219 const int64 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 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>& 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 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> 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 database_id,
276 int64 object_store_id,
277 int64 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 database_id_;
297 const int64 object_store_id_;
298 const int64 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 database_id,
310 int64 object_store_id,
311 int64 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 database_id_;
325 const int64 object_store_id_;
326 const int64 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 database_id,
335 int64 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 database_id_;
348 const int64 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 database_id,
357 int64 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 database_id_;
368 const int64 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 transaction_id,
378 int64 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 Version() { return version_; }
388 int64 TransactionId() const { return transaction_id_; }
389
390 private:
391 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
392 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_;
393 int64 version_;
394 const int64 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 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_LT(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 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 object_store_id,
460 const IndexedDBIndexMetadata& index,
461 int64 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_LT(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 object_store_id, int64 index_id) {
477 DCHECK(metadata_.object_stores.find(object_store_id) !=
478 metadata_.object_stores.end());
479 IndexedDBObjectStoreMetadata object_store =
480 metadata_.object_stores[object_store_id];
481
482 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
483 object_store.indexes.erase(index_id);
484 metadata_.object_stores[object_store_id] = object_store;
485 }
486
487 bool IndexedDBDatabaseImpl::OpenInternal() {
488 bool success = false;
489 bool ok = backing_store_->GetIDBDatabaseMetaData(
490 metadata_.name, &metadata_, &success);
491 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success
492 << " id_ = " << metadata_.id;
493 if (!ok)
494 return false;
495 if (success)
496 return backing_store_->GetObjectStores(metadata_.id,
497 &metadata_.object_stores);
498
499 return backing_store_->CreateIDBDatabaseMetaData(
500 metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id);
501 }
502
503 IndexedDBDatabaseImpl::~IndexedDBDatabaseImpl() {
504 DCHECK(transactions_.empty());
505 DCHECK(pending_open_calls_.empty());
506 DCHECK(pending_delete_calls_.empty());
507 }
508
509 scoped_refptr<IndexedDBBackingStore> IndexedDBDatabaseImpl::BackingStore()
510 const {
511 return backing_store_;
512 }
513
514 void IndexedDBDatabaseImpl::CreateObjectStore(int64 transaction_id,
515 int64 object_store_id,
516 const string16& name,
517 const IndexedDBKeyPath& key_path,
518 bool auto_increment) {
519 IDB_TRACE("IndexedDBDatabaseImpl::create_object_store");
520 TransactionMap::const_iterator trans_iterator =
521 transactions_.find(transaction_id);
522 if (trans_iterator == transactions_.end())
523 return;
524 IndexedDBTransaction* transaction = trans_iterator->second;
525 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
526
527 DCHECK(metadata_.object_stores.find(object_store_id) ==
528 metadata_.object_stores.end());
529 IndexedDBObjectStoreMetadata object_store_metadata(
530 name,
531 object_store_id,
532 key_path,
533 auto_increment,
534 IndexedDBDatabase::kMinimumIndexId);
535
536 transaction->ScheduleTask(
537 new CreateObjectStoreOperation(backing_store_, object_store_metadata),
538 new CreateObjectStoreAbortOperation(this, object_store_id));
539
540 AddObjectStore(object_store_metadata, object_store_id);
541 }
542
543 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
544 IDB_TRACE("CreateObjectStoreOperation");
545 if (!backing_store_->CreateObjectStore(
546 transaction->BackingStoreTransaction(),
547 transaction->database()->id(),
548 object_store_metadata_.id,
549 object_store_metadata_.name,
550 object_store_metadata_.key_path,
551 object_store_metadata_.auto_increment)) {
552 transaction->Abort(IndexedDBDatabaseError(
553 WebKit::WebIDBDatabaseExceptionUnknownError,
554 ASCIIToUTF16("Internal error creating object store '") +
555 object_store_metadata_.name + ASCIIToUTF16("'.")));
556 return;
557 }
558 }
559
560 void IndexedDBDatabaseImpl::DeleteObjectStore(int64 transaction_id,
561 int64 object_store_id) {
562 IDB_TRACE("IndexedDBDatabaseImpl::delete_object_store");
563 TransactionMap::const_iterator trans_iterator =
564 transactions_.find(transaction_id);
565 if (trans_iterator == transactions_.end())
566 return;
567 IndexedDBTransaction* transaction = trans_iterator->second;
568 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
569
570 DCHECK(metadata_.object_stores.find(object_store_id) !=
571 metadata_.object_stores.end());
572 const IndexedDBObjectStoreMetadata& object_store_metadata =
573 metadata_.object_stores[object_store_id];
574
575 transaction->ScheduleTask(
576 new DeleteObjectStoreOperation(backing_store_, object_store_metadata),
577 new DeleteObjectStoreAbortOperation(this, object_store_metadata));
578 RemoveObjectStore(object_store_id);
579 }
580
581 void IndexedDBDatabaseImpl::CreateIndex(int64 transaction_id,
582 int64 object_store_id,
583 int64 index_id,
584 const string16& name,
585 const IndexedDBKeyPath& key_path,
586 bool unique,
587 bool multi_entry) {
588 IDB_TRACE("IndexedDBDatabaseImpl::create_index");
589 TransactionMap::const_iterator trans_iterator =
590 transactions_.find(transaction_id);
591 if (trans_iterator == transactions_.end())
592 return;
593 IndexedDBTransaction* transaction = trans_iterator->second;
594 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
595
596 DCHECK(metadata_.object_stores.find(object_store_id) !=
597 metadata_.object_stores.end());
598 const IndexedDBObjectStoreMetadata object_store =
599 metadata_.object_stores[object_store_id];
600
601 DCHECK(object_store.indexes.find(index_id) == object_store.indexes.end());
602 const IndexedDBIndexMetadata index_metadata(
603 name, index_id, key_path, unique, multi_entry);
604
605 transaction->ScheduleTask(
606 new CreateIndexOperation(backing_store_, object_store_id, index_metadata),
607 new CreateIndexAbortOperation(this, object_store_id, index_id));
608
609 AddIndex(object_store_id, index_metadata, index_id);
610 }
611
612 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) {
613 IDB_TRACE("CreateIndexOperation");
614 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
615 transaction->database()->id(),
616 object_store_id_,
617 index_metadata_.id,
618 index_metadata_.name,
619 index_metadata_.key_path,
620 index_metadata_.unique,
621 index_metadata_.multi_entry)) {
622 string16 error_string = ASCIIToUTF16("Internal error creating index '") +
623 index_metadata_.name + ASCIIToUTF16("'.");
624 transaction->Abort(IndexedDBDatabaseError(
625 WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
626 return;
627 }
628 }
629
630 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
631 IDB_TRACE("CreateIndexAbortOperation");
632 DCHECK(!transaction);
633 database_->RemoveIndex(object_store_id_, index_id_);
634 }
635
636 void IndexedDBDatabaseImpl::DeleteIndex(int64 transaction_id,
637 int64 object_store_id,
638 int64 index_id) {
639 IDB_TRACE("IndexedDBDatabaseImpl::delete_index");
640 TransactionMap::const_iterator trans_iterator =
641 transactions_.find(transaction_id);
642 if (trans_iterator == transactions_.end())
643 return;
644 IndexedDBTransaction* transaction = trans_iterator->second;
645 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
646
647 DCHECK(metadata_.object_stores.find(object_store_id) !=
648 metadata_.object_stores.end());
649 IndexedDBObjectStoreMetadata object_store =
650 metadata_.object_stores[object_store_id];
651
652 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
653 const IndexedDBIndexMetadata& index_metadata = object_store.indexes[index_id];
654
655 transaction->ScheduleTask(
656 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata),
657 new DeleteIndexAbortOperation(this, object_store_id, index_metadata));
658
659 RemoveIndex(object_store_id, index_id);
660 }
661
662 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) {
663 IDB_TRACE("DeleteIndexOperation");
664 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
665 transaction->database()->id(),
666 object_store_id_,
667 index_metadata_.id);
668 if (!ok) {
669 string16 error_string = ASCIIToUTF16("Internal error deleting index '") +
670 index_metadata_.name + ASCIIToUTF16("'.");
671 transaction->Abort(IndexedDBDatabaseError(
672 WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
673 }
674 }
675
676 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
677 IDB_TRACE("DeleteIndexAbortOperation");
678 DCHECK(!transaction);
679 database_->AddIndex(
680 object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId);
681 }
682
683 void IndexedDBDatabaseImpl::Commit(int64 transaction_id) {
684 // The frontend suggests that we commit, but we may have previously initiated
685 // an abort, and so have disposed of the transaction. on_abort has already
686 // been dispatched to the frontend, so it will find out about that
687 // asynchronously.
688 if (transactions_.find(transaction_id) != transactions_.end())
689 transactions_[transaction_id]->Commit();
690 }
691
692 void IndexedDBDatabaseImpl::Abort(int64 transaction_id) {
693 // If the transaction is unknown, then it has already been aborted by the
694 // backend before this call so it is safe to ignore it.
695 if (transactions_.find(transaction_id) != transactions_.end())
696 transactions_[transaction_id]->Abort();
697 }
698
699 void IndexedDBDatabaseImpl::Abort(int64 transaction_id,
700 const IndexedDBDatabaseError& error) {
701 // If the transaction is unknown, then it has already been aborted by the
702 // backend before this call so it is safe to ignore it.
703 if (transactions_.find(transaction_id) != transactions_.end())
704 transactions_[transaction_id]->Abort(error);
705 }
706
707 void IndexedDBDatabaseImpl::Get(
708 int64 transaction_id,
709 int64 object_store_id,
710 int64 index_id,
711 scoped_ptr<IndexedDBKeyRange> key_range,
712 bool key_only,
713 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
714 IDB_TRACE("IndexedDBDatabaseImpl::get");
715 TransactionMap::const_iterator trans_iterator =
716 transactions_.find(transaction_id);
717 if (trans_iterator == transactions_.end())
718 return;
719 IndexedDBTransaction* transaction = trans_iterator->second;
720
721 transaction->ScheduleTask(new GetOperation(
722 backing_store_,
723 metadata_,
724 object_store_id,
725 index_id,
726 key_range.Pass(),
727 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
728 callbacks));
729 }
730
731 void GetOperation::Perform(IndexedDBTransaction* transaction) {
732 IDB_TRACE("GetOperation");
733
734 const IndexedDBKey* key;
735
736 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
737 if (key_range_->IsOnlyKey()) {
738 key = &key_range_->lower();
739 } else {
740 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
741 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY);
742 // ObjectStore Retrieval Operation
743 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
744 transaction->BackingStoreTransaction(),
745 database_id_,
746 object_store_id_,
747 *key_range_,
748 indexed_db::CURSOR_NEXT);
749 } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
750 // Index Value Retrieval Operation
751 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
752 transaction->BackingStoreTransaction(),
753 database_id_,
754 object_store_id_,
755 index_id_,
756 *key_range_,
757 indexed_db::CURSOR_NEXT);
758 } else {
759 // Index Referenced Value Retrieval Operation
760 backing_store_cursor = backing_store_->OpenIndexCursor(
761 transaction->BackingStoreTransaction(),
762 database_id_,
763 object_store_id_,
764 index_id_,
765 *key_range_,
766 indexed_db::CURSOR_NEXT);
767 }
768
769 if (!backing_store_cursor) {
770 callbacks_->OnSuccess();
771 return;
772 }
773
774 key = &backing_store_cursor->key();
775 }
776
777 scoped_ptr<IndexedDBKey> primary_key;
778 bool ok;
779 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
780 // Object Store Retrieval Operation
781 std::vector<char> value;
782 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
783 database_id_,
784 object_store_id_,
785 *key,
786 &value);
787 if (!ok) {
788 callbacks_->OnError(IndexedDBDatabaseError(
789 WebKit::WebIDBDatabaseExceptionUnknownError,
790 "Internal error in get_record."));
791 return;
792 }
793
794 if (value.empty()) {
795 callbacks_->OnSuccess();
796 return;
797 }
798
799 if (auto_increment_ && !key_path_.IsNull()) {
800 callbacks_->OnSuccess(&value, *key, key_path_);
801 return;
802 }
803
804 callbacks_->OnSuccess(&value);
805 return;
806 }
807
808 // From here we are dealing only with indexes.
809 ok = backing_store_->GetPrimaryKeyViaIndex(
810 transaction->BackingStoreTransaction(),
811 database_id_,
812 object_store_id_,
813 index_id_,
814 *key,
815 &primary_key);
816 if (!ok) {
817 callbacks_->OnError(IndexedDBDatabaseError(
818 WebKit::WebIDBDatabaseExceptionUnknownError,
819 "Internal error in get_primary_key_via_index."));
820 return;
821 }
822 if (!primary_key) {
823 callbacks_->OnSuccess();
824 return;
825 }
826 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
827 // Index Value Retrieval Operation
828 callbacks_->OnSuccess(*primary_key);
829 return;
830 }
831
832 // Index Referenced Value Retrieval Operation
833 std::vector<char> value;
834 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
835 database_id_,
836 object_store_id_,
837 *primary_key,
838 &value);
839 if (!ok) {
840 callbacks_->OnError(
841 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
842 "Internal error in get_record."));
843 return;
844 }
845
846 if (value.empty()) {
847 callbacks_->OnSuccess();
848 return;
849 }
850 if (auto_increment_ && !key_path_.IsNull()) {
851 callbacks_->OnSuccess(&value, *primary_key, key_path_);
852 return;
853 }
854 callbacks_->OnSuccess(&value);
855 }
856
857 static scoped_ptr<IndexedDBKey> GenerateKey(
858 scoped_refptr<IndexedDBBackingStore> backing_store,
859 scoped_refptr<IndexedDBTransaction> transaction,
860 int64 database_id,
861 int64 object_store_id) {
862 const int64 max_generator_value =
863 9007199254740992LL; // Maximum integer storable as ECMAScript number.
864 int64 current_number;
865 bool ok = backing_store->GetKeyGeneratorCurrentNumber(
866 transaction->BackingStoreTransaction(),
867 database_id,
868 object_store_id,
869 &current_number);
870 if (!ok) {
871 LOG(ERROR) << "Failed to get_key_generator_current_number";
872 return make_scoped_ptr(new IndexedDBKey());
873 }
874 if (current_number < 0 || current_number > max_generator_value)
875 return make_scoped_ptr(new IndexedDBKey());
876
877 return make_scoped_ptr(
878 new IndexedDBKey(current_number, WebIDBKey::NumberType));
879 }
880
881 static bool UpdateKeyGenerator(
882 scoped_refptr<IndexedDBBackingStore> backing_store,
883 scoped_refptr<IndexedDBTransaction> transaction,
884 int64 database_id,
885 int64 object_store_id,
886 const IndexedDBKey* key,
887 bool check_current) {
888 DCHECK(key);
889 DCHECK_EQ(WebIDBKey::NumberType, key->type());
890 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
891 transaction->BackingStoreTransaction(),
892 database_id,
893 object_store_id,
894 static_cast<int64>(floor(key->number())) + 1,
895 check_current);
896 }
897
898 void IndexedDBDatabaseImpl::Put(
899 int64 transaction_id,
900 int64 object_store_id,
901 std::vector<char>* value,
902 scoped_ptr<IndexedDBKey> key,
903 PutMode put_mode,
904 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
905 const std::vector<int64>& index_ids,
906 const std::vector<IndexKeys>& index_keys) {
907 IDB_TRACE("IndexedDBDatabaseImpl::put");
908 TransactionMap::const_iterator trans_iterator =
909 transactions_.find(transaction_id);
910 if (trans_iterator == transactions_.end())
911 return;
912 IndexedDBTransaction* transaction = trans_iterator->second;
913 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
914
915 const IndexedDBObjectStoreMetadata object_store_metadata =
916 metadata_.object_stores[object_store_id];
917
918 DCHECK(key);
919 DCHECK(object_store_metadata.auto_increment || key->IsValid());
920 transaction->ScheduleTask(new PutOperation(backing_store_,
921 id(),
922 object_store_metadata,
923 value,
924 key.Pass(),
925 put_mode,
926 callbacks,
927 index_ids,
928 index_keys));
929 }
930
931 void PutOperation::Perform(IndexedDBTransaction* transaction) {
932 IDB_TRACE("PutOperation");
933 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
934 DCHECK_EQ(index_ids_.size(), index_keys_.size());
935 bool key_was_generated = false;
936
937 scoped_ptr<IndexedDBKey> key;
938 if (put_mode_ != IndexedDBDatabase::CURSOR_UPDATE &&
939 object_store_.auto_increment && !key_->IsValid()) {
940 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
941 backing_store_, transaction, database_id_, object_store_.id);
942 key_was_generated = true;
943 if (!auto_inc_key->IsValid()) {
944 callbacks_->OnError(IndexedDBDatabaseError(
945 WebKit::WebIDBDatabaseExceptionConstraintError,
946 "Maximum key generator value reached."));
947 return;
948 }
949 key = auto_inc_key.Pass();
950 } else {
951 key = key_.Pass();
952 }
953
954 DCHECK(key->IsValid());
955
956 IndexedDBBackingStore::RecordIdentifier record_identifier;
957 if (put_mode_ == IndexedDBDatabase::ADD_ONLY) {
958 bool found = false;
959 bool ok = backing_store_->KeyExistsInObjectStore(
960 transaction->BackingStoreTransaction(),
961 database_id_,
962 object_store_.id,
963 *key.get(),
964 &record_identifier,
965 &found);
966 if (!ok) {
967 callbacks_->OnError(IndexedDBDatabaseError(
968 WebKit::WebIDBDatabaseExceptionUnknownError,
969 "Internal error checking key existence."));
970 return;
971 }
972 if (found) {
973 callbacks_->OnError(IndexedDBDatabaseError(
974 WebKit::WebIDBDatabaseExceptionConstraintError,
975 "Key already exists in the object store."));
976 return;
977 }
978 }
979
980 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers;
981 string16 error_message;
982 bool obeys_constraints = false;
983 bool backing_store_success =
984 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction,
985 backing_store_.get(),
986 database_id_,
987 object_store_,
988 *key,
989 key_was_generated,
990 index_ids_,
991 index_keys_,
992 &index_writers,
993 &error_message,
994 &obeys_constraints);
995 if (!backing_store_success) {
996 callbacks_->OnError(IndexedDBDatabaseError(
997 WebKit::WebIDBDatabaseExceptionUnknownError,
998 "Internal error: backing store error updating index keys."));
999 return;
1000 }
1001 if (!obeys_constraints) {
1002 callbacks_->OnError(IndexedDBDatabaseError(
1003 WebKit::WebIDBDatabaseExceptionConstraintError, error_message));
1004 return;
1005 }
1006
1007 // Before this point, don't do any mutation. After this point, rollback the
1008 // transaction in case of error.
1009 backing_store_success =
1010 backing_store_->PutRecord(transaction->BackingStoreTransaction(),
1011 database_id_,
1012 object_store_.id,
1013 *key.get(),
1014 value_,
1015 &record_identifier);
1016 if (!backing_store_success) {
1017 callbacks_->OnError(IndexedDBDatabaseError(
1018 WebKit::WebIDBDatabaseExceptionUnknownError,
1019 "Internal error: backing store error performing put/add."));
1020 return;
1021 }
1022
1023 for (size_t i = 0; i < index_writers.size(); ++i) {
1024 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i];
1025 index_writer->WriteIndexKeys(record_identifier,
1026 backing_store_,
1027 transaction->BackingStoreTransaction(),
1028 database_id_,
1029 object_store_.id);
1030 }
1031
1032 if (object_store_.auto_increment &&
1033 put_mode_ != IndexedDBDatabase::CURSOR_UPDATE &&
1034 key->type() == WebIDBKey::NumberType) {
1035 bool ok = UpdateKeyGenerator(backing_store_,
1036 transaction,
1037 database_id_,
1038 object_store_.id,
1039 key.get(),
1040 !key_was_generated);
1041 if (!ok) {
1042 callbacks_->OnError(IndexedDBDatabaseError(
1043 WebKit::WebIDBDatabaseExceptionUnknownError,
1044 "Internal error updating key generator."));
1045 return;
1046 }
1047 }
1048
1049 callbacks_->OnSuccess(*key);
1050 }
1051
1052 void IndexedDBDatabaseImpl::SetIndexKeys(
1053 int64 transaction_id,
1054 int64 object_store_id,
1055 scoped_ptr<IndexedDBKey> primary_key,
1056 const std::vector<int64>& index_ids,
1057 const std::vector<IndexKeys>& index_keys) {
1058 IDB_TRACE("IndexedDBDatabaseImpl::set_index_keys");
1059 TransactionMap::const_iterator trans_iterator =
1060 transactions_.find(transaction_id);
1061 if (trans_iterator == transactions_.end())
1062 return;
1063 IndexedDBTransaction* transaction = trans_iterator->second;
1064 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
1065
1066 scoped_refptr<IndexedDBBackingStore> store = BackingStore();
1067 // TODO(jsbell): This method could be asynchronous, but we need to
1068 // evaluate if it's worth the extra complexity.
1069 IndexedDBBackingStore::RecordIdentifier record_identifier;
1070 bool found = false;
1071 bool ok =
1072 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(),
1073 metadata_.id,
1074 object_store_id,
1075 *primary_key,
1076 &record_identifier,
1077 &found);
1078 if (!ok) {
1079 transaction->Abort(IndexedDBDatabaseError(
1080 WebKit::WebIDBDatabaseExceptionUnknownError,
1081 "Internal error setting index keys."));
1082 return;
1083 }
1084 if (!found) {
1085 transaction->Abort(IndexedDBDatabaseError(
1086 WebKit::WebIDBDatabaseExceptionUnknownError,
1087 "Internal error setting index keys for object store."));
1088 return;
1089 }
1090
1091 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers;
1092 string16 error_message;
1093 bool obeys_constraints = false;
1094 DCHECK(metadata_.object_stores.find(object_store_id) !=
1095 metadata_.object_stores.end());
1096 const IndexedDBObjectStoreMetadata& object_store_metadata =
1097 metadata_.object_stores[object_store_id];
1098 bool backing_store_success =
1099 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction,
1100 store.get(),
1101 id(),
1102 object_store_metadata,
1103 *primary_key,
1104 false,
1105 index_ids,
1106 index_keys,
1107 &index_writers,
1108 &error_message,
1109 &obeys_constraints);
1110 if (!backing_store_success) {
1111 transaction->Abort(IndexedDBDatabaseError(
1112 WebKit::WebIDBDatabaseExceptionUnknownError,
1113 "Internal error: backing store error updating index keys."));
1114 return;
1115 }
1116 if (!obeys_constraints) {
1117 transaction->Abort(IndexedDBDatabaseError(
1118 WebKit::WebIDBDatabaseExceptionConstraintError, error_message));
1119 return;
1120 }
1121
1122 for (size_t i = 0; i < index_writers.size(); ++i) {
1123 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i];
1124 index_writer->WriteIndexKeys(record_identifier,
1125 store.get(),
1126 transaction->BackingStoreTransaction(),
1127 id(),
1128 object_store_id);
1129 }
1130 }
1131
1132 void IndexedDBDatabaseImpl::SetIndexesReady(
1133 int64 transaction_id,
1134 int64,
1135 const std::vector<int64>& index_ids) {
1136 IDB_TRACE("IndexedDBObjectStoreImpl::set_indexes_ready");
1137
1138 TransactionMap::const_iterator trans_iterator =
1139 transactions_.find(transaction_id);
1140 if (trans_iterator == transactions_.end())
1141 return;
1142 IndexedDBTransaction* transaction = trans_iterator->second;
1143
1144 transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK,
1145 new SetIndexesReadyOperation(index_ids.size()));
1146 }
1147
1148 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) {
1149 IDB_TRACE("SetIndexesReadyOperation");
1150 for (size_t i = 0; i < index_count_; ++i)
1151 transaction->DidCompletePreemptiveEvent();
1152 }
1153
1154 void IndexedDBDatabaseImpl::OpenCursor(
1155 int64 transaction_id,
1156 int64 object_store_id,
1157 int64 index_id,
1158 scoped_ptr<IndexedDBKeyRange> key_range,
1159 indexed_db::CursorDirection direction,
1160 bool key_only,
1161 TaskType task_type,
1162 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1163 IDB_TRACE("IndexedDBDatabaseImpl::open_cursor");
1164 TransactionMap::const_iterator trans_iterator =
1165 transactions_.find(transaction_id);
1166 if (trans_iterator == transactions_.end())
1167 return;
1168 IndexedDBTransaction* transaction = trans_iterator->second;
1169
1170 transaction->ScheduleTask(new OpenCursorOperation(
1171 backing_store_,
1172 id(),
1173 object_store_id,
1174 index_id,
1175 key_range.Pass(),
1176 direction,
1177 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
1178 task_type,
1179 callbacks));
1180 }
1181
1182 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) {
1183 IDB_TRACE("OpenCursorOperation");
1184
1185 // The frontend has begun indexing, so this pauses the transaction
1186 // until the indexing is complete. This can't happen any earlier
1187 // because we don't want to switch to early mode in case multiple
1188 // indexes are being created in a row, with Put()'s in between.
1189 if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK)
1190 transaction->AddPreemptiveEvent();
1191
1192 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1193 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
1194 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY);
1195 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
1196 transaction->BackingStoreTransaction(),
1197 database_id_,
1198 object_store_id_,
1199 *key_range_,
1200 direction_);
1201 } else {
1202 DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK);
1203 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
1204 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1205 transaction->BackingStoreTransaction(),
1206 database_id_,
1207 object_store_id_,
1208 index_id_,
1209 *key_range_,
1210 direction_);
1211 } else {
1212 backing_store_cursor = backing_store_->OpenIndexCursor(
1213 transaction->BackingStoreTransaction(),
1214 database_id_,
1215 object_store_id_,
1216 index_id_,
1217 *key_range_,
1218 direction_);
1219 }
1220 }
1221
1222 if (!backing_store_cursor) {
1223 callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
1224 return;
1225 }
1226
1227 IndexedDBDatabase::TaskType task_type(
1228 static_cast<IndexedDBDatabase::TaskType>(task_type_));
1229 scoped_refptr<IndexedDBCursorImpl> cursor = IndexedDBCursorImpl::Create(
1230 backing_store_cursor.Pass(), cursor_type_, task_type, transaction);
1231 callbacks_->OnSuccess(
1232 cursor, cursor->key(), cursor->primary_key(), cursor->Value());
1233 }
1234
1235 void IndexedDBDatabaseImpl::Count(
1236 int64 transaction_id,
1237 int64 object_store_id,
1238 int64 index_id,
1239 scoped_ptr<IndexedDBKeyRange> key_range,
1240 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1241 IDB_TRACE("IndexedDBDatabaseImpl::count");
1242 TransactionMap::const_iterator trans_iterator =
1243 transactions_.find(transaction_id);
1244 if (trans_iterator == transactions_.end())
1245 return;
1246 IndexedDBTransaction* transaction = trans_iterator->second;
1247
1248 DCHECK(metadata_.object_stores.find(object_store_id) !=
1249 metadata_.object_stores.end());
1250 transaction->ScheduleTask(new CountOperation(backing_store_,
1251 id(),
1252 object_store_id,
1253 index_id,
1254 key_range.Pass(),
1255 callbacks));
1256 }
1257
1258 void CountOperation::Perform(IndexedDBTransaction* transaction) {
1259 IDB_TRACE("CountOperation");
1260 uint32 count = 0;
1261 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1262
1263 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
1264 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
1265 transaction->BackingStoreTransaction(),
1266 database_id_,
1267 object_store_id_,
1268 *key_range_,
1269 indexed_db::CURSOR_NEXT);
1270 } else {
1271 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1272 transaction->BackingStoreTransaction(),
1273 database_id_,
1274 object_store_id_,
1275 index_id_,
1276 *key_range_,
1277 indexed_db::CURSOR_NEXT);
1278 }
1279 if (!backing_store_cursor) {
1280 callbacks_->OnSuccess(count);
1281 return;
1282 }
1283
1284 do {
1285 ++count;
1286 } while (backing_store_cursor->ContinueFunction(0));
1287
1288 callbacks_->OnSuccess(count);
1289 }
1290
1291 void IndexedDBDatabaseImpl::DeleteRange(
1292 int64 transaction_id,
1293 int64 object_store_id,
1294 scoped_ptr<IndexedDBKeyRange> key_range,
1295 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1296 IDB_TRACE("IndexedDBDatabaseImpl::delete_range");
1297 TransactionMap::const_iterator trans_iterator =
1298 transactions_.find(transaction_id);
1299 if (trans_iterator == transactions_.end())
1300 return;
1301 IndexedDBTransaction* transaction = trans_iterator->second;
1302
1303 transaction->ScheduleTask(new DeleteRangeOperation(
1304 backing_store_, id(), object_store_id, key_range.Pass(), callbacks));
1305 }
1306
1307 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) {
1308 IDB_TRACE("DeleteRangeOperation");
1309 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor =
1310 backing_store_->OpenObjectStoreCursor(
1311 transaction->BackingStoreTransaction(),
1312 database_id_,
1313 object_store_id_,
1314 *key_range_,
1315 indexed_db::CURSOR_NEXT);
1316 if (backing_store_cursor) {
1317 do {
1318 if (!backing_store_->DeleteRecord(
1319 transaction->BackingStoreTransaction(),
1320 database_id_,
1321 object_store_id_,
1322 backing_store_cursor->record_identifier())) {
1323 callbacks_->OnError(IndexedDBDatabaseError(
1324 WebKit::WebIDBDatabaseExceptionUnknownError,
1325 "Internal error deleting data in range"));
1326 return;
1327 }
1328 } while (backing_store_cursor->ContinueFunction(0));
1329 }
1330
1331 callbacks_->OnSuccess();
1332 }
1333
1334 void IndexedDBDatabaseImpl::Clear(
1335 int64 transaction_id,
1336 int64 object_store_id,
1337 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1338 IDB_TRACE("IndexedDBDatabaseImpl::clear");
1339 TransactionMap::const_iterator trans_iterator =
1340 transactions_.find(transaction_id);
1341 if (trans_iterator == transactions_.end())
1342 return;
1343 IndexedDBTransaction* transaction = trans_iterator->second;
1344 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
1345
1346 transaction->ScheduleTask(
1347 new ClearOperation(backing_store_, id(), object_store_id, callbacks));
1348 }
1349
1350 void ClearOperation::Perform(IndexedDBTransaction* transaction) {
1351 IDB_TRACE("ObjectStoreClearOperation");
1352 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(),
1353 database_id_,
1354 object_store_id_)) {
1355 callbacks_->OnError(IndexedDBDatabaseError(
1356 WebKit::WebIDBDatabaseExceptionUnknownError,
1357 "Internal error clearing object store"));
1358 return;
1359 }
1360 callbacks_->OnSuccess();
1361 }
1362
1363 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
1364 IDB_TRACE("DeleteObjectStoreOperation");
1365 bool ok =
1366 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(),
1367 transaction->database()->id(),
1368 object_store_metadata_.id);
1369 if (!ok) {
1370 string16 error_string =
1371 ASCIIToUTF16("Internal error deleting object store '") +
1372 object_store_metadata_.name + ASCIIToUTF16("'.");
1373 transaction->Abort(IndexedDBDatabaseError(
1374 WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
1375 }
1376 }
1377
1378 void IndexedDBDatabaseImpl::VersionChangeOperation::Perform(
1379 IndexedDBTransaction* transaction) {
1380 IDB_TRACE("VersionChangeOperation");
1381 int64 database_id = database_->id();
1382 int64 old_version = database_->metadata_.int_version;
1383 DCHECK_GT(version_, old_version);
1384 database_->metadata_.int_version = version_;
1385 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion(
1386 transaction->BackingStoreTransaction(),
1387 database_id,
1388 database_->metadata_.int_version)) {
1389 IndexedDBDatabaseError error(
1390 WebKit::WebIDBDatabaseExceptionUnknownError,
1391 ASCIIToUTF16("Internal error writing data to stable storage when "
1392 "updating version."));
1393 callbacks_->OnError(error);
1394 transaction->Abort(error);
1395 return;
1396 }
1397 DCHECK(!database_->pending_second_half_open_);
1398 database_->pending_second_half_open_.reset(new PendingOpenCall(
1399 callbacks_, database_callbacks_, transaction_id_, version_));
1400 callbacks_->OnUpgradeNeeded(old_version, database_, database_->metadata());
1401 }
1402
1403 void IndexedDBDatabaseImpl::TransactionStarted(
1404 IndexedDBTransaction* transaction) {
1405
1406 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) {
1407 DCHECK(!running_version_change_transaction_);
1408 running_version_change_transaction_ = transaction;
1409 }
1410 }
1411
1412 void IndexedDBDatabaseImpl::TransactionFinished(
1413 IndexedDBTransaction* transaction) {
1414
1415 DCHECK(transactions_.find(transaction->id()) != transactions_.end());
1416 DCHECK_EQ(transactions_[transaction->id()], transaction);
1417 transactions_.erase(transaction->id());
1418 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) {
1419 DCHECK_EQ(transaction, running_version_change_transaction_);
1420 running_version_change_transaction_ = NULL;
1421 }
1422 }
1423
1424 void IndexedDBDatabaseImpl::TransactionFinishedAndAbortFired(
1425 IndexedDBTransaction* transaction) {
1426 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) {
1427 if (pending_second_half_open_) {
1428 pending_second_half_open_->Callbacks()->OnError(IndexedDBDatabaseError(
1429 WebKit::WebIDBDatabaseExceptionAbortError,
1430 "Version change transaction was aborted in "
1431 "upgradeneeded event handler."));
1432 pending_second_half_open_.reset();
1433 }
1434 ProcessPendingCalls();
1435 }
1436 }
1437
1438 void IndexedDBDatabaseImpl::TransactionFinishedAndCompleteFired(
1439 IndexedDBTransaction* transaction) {
1440 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) {
1441 DCHECK(pending_second_half_open_);
1442 if (pending_second_half_open_) {
1443 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version);
1444 DCHECK(metadata_.id != kInvalidId);
1445 pending_second_half_open_->Callbacks()->OnSuccess(this, this->metadata());
1446 pending_second_half_open_.reset();
1447 }
1448 ProcessPendingCalls();
1449 }
1450 }
1451
1452 size_t IndexedDBDatabaseImpl::ConnectionCount() const {
1453 // This does not include pending open calls, as those should not block version
1454 // changes and deletes.
1455 return database_callbacks_set_.size();
1456 }
1457
1458 void IndexedDBDatabaseImpl::ProcessPendingCalls() {
1459 if (pending_second_half_open_) {
1460 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version);
1461 DCHECK(metadata_.id != kInvalidId);
1462 scoped_ptr<PendingOpenCall> pending_call = pending_second_half_open_.Pass();
1463 pending_call->Callbacks()->OnSuccess(this, this->metadata());
1464 // Fall through when complete, as pending opens may be unblocked.
1465 }
1466
1467 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
1468 DCHECK(pending_run_version_change_transaction_call_->Version() >
1469 metadata_.int_version);
1470 scoped_ptr<PendingOpenCall> pending_call =
1471 pending_run_version_change_transaction_call_.Pass();
1472 RunVersionChangeTransactionFinal(pending_call->Callbacks(),
1473 pending_call->DatabaseCallbacks(),
1474 pending_call->TransactionId(),
1475 pending_call->Version());
1476 DCHECK_EQ(static_cast<size_t>(1), ConnectionCount());
1477 // Fall through would be a no-op, since transaction must complete
1478 // asynchronously.
1479 DCHECK(IsDeleteDatabaseBlocked());
1480 DCHECK(IsOpenConnectionBlocked());
1481 return;
1482 }
1483
1484 if (!IsDeleteDatabaseBlocked()) {
1485 PendingDeleteCallList pending_delete_calls;
1486 pending_delete_calls_.swap(pending_delete_calls);
1487 while (!pending_delete_calls.empty()) {
1488 // Only the first delete call will delete the database, but each must fire
1489 // callbacks.
1490 scoped_ptr<PendingDeleteCall> pending_delete_call(
1491 pending_delete_calls.front());
1492 pending_delete_calls.pop_front();
1493 DeleteDatabaseFinal(pending_delete_call->Callbacks());
1494 }
1495 // delete_database_final should never re-queue calls.
1496 DCHECK(pending_delete_calls_.empty());
1497 // Fall through when complete, as pending opens may be unblocked.
1498 }
1499
1500 if (!IsOpenConnectionBlocked()) {
1501 PendingOpenCallList pending_open_calls;
1502 pending_open_calls_.swap(pending_open_calls);
1503 while (!pending_open_calls.empty()) {
1504 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front());
1505 pending_open_calls.pop_front();
1506 OpenConnection(pending_open_call->Callbacks(),
1507 pending_open_call->DatabaseCallbacks(),
1508 pending_open_call->TransactionId(),
1509 pending_open_call->Version());
1510 }
1511 }
1512 }
1513
1514 void IndexedDBDatabaseImpl::CreateTransaction(
1515 int64 transaction_id,
1516 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks,
1517 const std::vector<int64>& object_store_ids,
1518 uint16 mode) {
1519
1520 DCHECK(database_callbacks_set_.has(callbacks));
1521
1522 scoped_refptr<IndexedDBTransaction> transaction =
1523 IndexedDBTransaction::Create(
1524 transaction_id,
1525 callbacks,
1526 object_store_ids,
1527 static_cast<indexed_db::TransactionMode>(mode),
1528 this);
1529 DCHECK(transactions_.find(transaction_id) == transactions_.end());
1530 transactions_[transaction_id] = transaction;
1531 }
1532
1533 bool IndexedDBDatabaseImpl::IsOpenConnectionBlocked() const {
1534 return !pending_delete_calls_.empty() ||
1535 running_version_change_transaction_ ||
1536 pending_run_version_change_transaction_call_;
1537 }
1538
1539 void IndexedDBDatabaseImpl::OpenConnection(
1540 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1541 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1542 int64 transaction_id,
1543 int64 version) {
1544 DCHECK(backing_store_.get());
1545
1546 // TODO(jsbell): Should have a priority queue so that higher version
1547 // requests are processed first. http://crbug.com/225850
1548 if (IsOpenConnectionBlocked()) {
1549 pending_open_calls_.push_back(new PendingOpenCall(
1550 callbacks, database_callbacks, transaction_id, version));
1551 return;
1552 }
1553
1554 if (metadata_.id == kInvalidId) {
1555 // The database was deleted then immediately re-opened; OpenInternal()
1556 // recreates it in the backing store.
1557 if (OpenInternal()) {
1558 DCHECK_EQ(metadata_.int_version,
1559 IndexedDBDatabaseMetadata::NO_INT_VERSION);
1560 } else {
1561 string16 message;
1562 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
1563 message = ASCIIToUTF16(
1564 "Internal error opening database with no version specified.");
1565 else
1566 message =
1567 ASCIIToUTF16("Internal error opening database with version ") +
1568 Int64ToString16(version);
1569 callbacks->OnError(IndexedDBDatabaseError(
1570 WebKit::WebIDBDatabaseExceptionUnknownError, message));
1571 return;
1572 }
1573 }
1574
1575 // We infer that the database didn't exist from its lack of either type of
1576 // version.
1577 bool is_new_database =
1578 metadata_.version == kNoStringVersion &&
1579 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION;
1580
1581 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) {
1582 // For unit tests only - skip upgrade steps. Calling from script with
1583 // DEFAULT_INT_VERSION throws exception.
1584 // TODO(jsbell): Assert that we're executing a unit test.
1585 DCHECK(is_new_database);
1586 database_callbacks_set_.insert(database_callbacks);
1587 callbacks->OnSuccess(this, this->metadata());
1588 return;
1589 }
1590
1591 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
1592 if (!is_new_database) {
1593 database_callbacks_set_.insert(database_callbacks);
1594 callbacks->OnSuccess(this, this->metadata());
1595 return;
1596 }
1597 // Spec says: If no version is specified and no database exists, set
1598 // database version to 1.
1599 version = 1;
1600 }
1601
1602 if (version > metadata_.int_version) {
1603 database_callbacks_set_.insert(database_callbacks);
1604 RunVersionChangeTransaction(
1605 callbacks, database_callbacks, transaction_id, version);
1606 return;
1607 }
1608 if (version < metadata_.int_version) {
1609 callbacks->OnError(IndexedDBDatabaseError(
1610 WebKit::WebIDBDatabaseExceptionVersionError,
1611 ASCIIToUTF16("The requested version (") + Int64ToString16(version) +
1612 ASCIIToUTF16(") is less than the existing version (") +
1613 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
1614 return;
1615 }
1616 DCHECK_EQ(version, metadata_.int_version);
1617 database_callbacks_set_.insert(database_callbacks);
1618 callbacks->OnSuccess(this, this->metadata());
1619 }
1620
1621 void IndexedDBDatabaseImpl::RunVersionChangeTransaction(
1622 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1623 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1624 int64 transaction_id,
1625 int64 requested_version) {
1626
1627 DCHECK(callbacks);
1628 DCHECK(database_callbacks_set_.has(database_callbacks));
1629 if (ConnectionCount() > 1) {
1630 // Front end ensures the event is not fired at connections that have
1631 // close_pending set.
1632 for (DatabaseCallbacksSet::const_iterator it =
1633 database_callbacks_set_.begin();
1634 it != database_callbacks_set_.end();
1635 ++it) {
1636 if (*it != database_callbacks.get())
1637 (*it)->OnVersionChange(metadata_.int_version, requested_version);
1638 }
1639 // TODO(jsbell): Remove the call to on_blocked and instead wait
1640 // until the frontend tells us that all the "versionchange" events
1641 // have been delivered. http://crbug.com/100123
1642 callbacks->OnBlocked(metadata_.int_version);
1643
1644 DCHECK(!pending_run_version_change_transaction_call_);
1645 pending_run_version_change_transaction_call_.reset(new PendingOpenCall(
1646 callbacks, database_callbacks, transaction_id, requested_version));
1647 return;
1648 }
1649 RunVersionChangeTransactionFinal(
1650 callbacks, database_callbacks, transaction_id, requested_version);
1651 }
1652
1653 void IndexedDBDatabaseImpl::RunVersionChangeTransactionFinal(
1654 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1655 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1656 int64 transaction_id,
1657 int64 requested_version) {
1658
1659 std::vector<int64> object_store_ids;
1660 CreateTransaction(transaction_id,
1661 database_callbacks,
1662 object_store_ids,
1663 indexed_db::TRANSACTION_VERSION_CHANGE);
1664 scoped_refptr<IndexedDBTransaction> transaction =
1665 transactions_[transaction_id];
1666
1667 transaction->ScheduleTask(
1668 new VersionChangeOperation(this,
1669 transaction_id,
1670 requested_version,
1671 callbacks,
1672 database_callbacks),
1673 new VersionChangeAbortOperation(
1674 this, metadata_.version, metadata_.int_version));
1675
1676 DCHECK(!pending_second_half_open_);
1677 }
1678
1679 void IndexedDBDatabaseImpl::DeleteDatabase(
1680 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1681
1682 if (IsDeleteDatabaseBlocked()) {
1683 for (DatabaseCallbacksSet::const_iterator it =
1684 database_callbacks_set_.begin();
1685 it != database_callbacks_set_.end();
1686 ++it) {
1687 // Front end ensures the event is not fired at connections that have
1688 // close_pending set.
1689 (*it)->OnVersionChange(metadata_.int_version,
1690 IndexedDBDatabaseMetadata::NO_INT_VERSION);
1691 }
1692 // TODO(jsbell): Only fire on_blocked if there are open
1693 // connections after the VersionChangeEvents are received, not
1694 // just set up to fire. http://crbug.com/100123
1695 callbacks->OnBlocked(metadata_.int_version);
1696 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
1697 return;
1698 }
1699 DeleteDatabaseFinal(callbacks);
1700 }
1701
1702 bool IndexedDBDatabaseImpl::IsDeleteDatabaseBlocked() const {
1703 return !!ConnectionCount();
1704 }
1705
1706 void IndexedDBDatabaseImpl::DeleteDatabaseFinal(
1707 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1708 DCHECK(!IsDeleteDatabaseBlocked());
1709 DCHECK(backing_store_);
1710 if (!backing_store_->DeleteDatabase(metadata_.name)) {
1711 callbacks->OnError(IndexedDBDatabaseError(
1712 WebKit::WebIDBDatabaseExceptionUnknownError,
1713 "Internal error deleting database."));
1714 return;
1715 }
1716 metadata_.version = kNoStringVersion;
1717 metadata_.id = kInvalidId;
1718 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
1719 metadata_.object_stores.clear();
1720 callbacks->OnSuccess();
1721 }
1722
1723 void IndexedDBDatabaseImpl::Close(
1724 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks) {
1725 DCHECK(callbacks);
1726 DCHECK(database_callbacks_set_.has(callbacks));
1727
1728 // Close outstanding transactions from the closing connection. This
1729 // can not happen if the close is requested by the connection itself
1730 // as the front-end defers the close until all transactions are
1731 // complete, so something unusual has happened e.g. unexpected
1732 // process termination.
1733 {
1734 TransactionMap transactions(transactions_);
1735 for (TransactionMap::const_iterator it = transactions.begin(),
1736 end = transactions.end();
1737 it != end;
1738 ++it) {
1739 if (it->second->connection() == callbacks)
1740 it->second->Abort(
1741 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
1742 "Connection is closing."));
1743 }
1744 }
1745
1746 database_callbacks_set_.erase(callbacks);
1747 if (pending_second_half_open_ &&
1748 pending_second_half_open_->DatabaseCallbacks() == callbacks) {
1749 pending_second_half_open_->Callbacks()->OnError(
1750 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionAbortError,
1751 "The connection was closed."));
1752 pending_second_half_open_.reset();
1753 }
1754
1755 // process_pending_calls allows the inspector to process a pending open call
1756 // and call close, reentering IndexedDBDatabaseImpl::close. Then the
1757 // backend would be removed both by the inspector closing its connection, and
1758 // by the connection that first called close.
1759 // To avoid that situation, don't proceed in case of reentrancy.
1760 if (closing_connection_)
1761 return;
1762 base::AutoReset<bool> ClosingConnection(&closing_connection_, true);
1763 ProcessPendingCalls();
1764
1765 // TODO(jsbell): Add a test for the pending_open_calls_ cases below.
1766 if (!ConnectionCount() && !pending_open_calls_.size() &&
1767 !pending_delete_calls_.size()) {
1768 DCHECK(transactions_.empty());
1769
1770 backing_store_ = NULL;
1771
1772 // This check should only be false in unit tests.
1773 // TODO(jsbell): Assert factory_ || we're executing a unit test.
1774 if (factory_)
1775 factory_->RemoveIDBDatabaseBackend(identifier_);
1776 }
1777 }
1778
1779 void CreateObjectStoreAbortOperation::Perform(
1780 IndexedDBTransaction* transaction) {
1781 IDB_TRACE("CreateObjectStoreAbortOperation");
1782 DCHECK(!transaction);
1783 database_->RemoveObjectStore(object_store_id_);
1784 }
1785
1786 void DeleteObjectStoreAbortOperation::Perform(
1787 IndexedDBTransaction* transaction) {
1788 IDB_TRACE("DeleteObjectStoreAbortOperation");
1789 DCHECK(!transaction);
1790 database_->AddObjectStore(object_store_metadata_,
1791 IndexedDBObjectStoreMetadata::kInvalidId);
1792 }
1793
1794 void IndexedDBDatabaseImpl::VersionChangeAbortOperation::Perform(
1795 IndexedDBTransaction* transaction) {
1796 IDB_TRACE("VersionChangeAbortOperation");
1797 DCHECK(!transaction);
1798 database_->metadata_.version = previous_version_;
1799 database_->metadata_.int_version = previous_int_version_;
1800 }
1801
1802 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_database_impl.h ('k') | content/browser/indexed_db/indexed_db_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698