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