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