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