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