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