Home | History | Annotate | Download | only in indexed_db
      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_index_writer.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/browser/indexed_db/indexed_db_backing_store.h"
     10 #include "content/browser/indexed_db/indexed_db_tracing.h"
     11 #include "content/browser/indexed_db/indexed_db_transaction.h"
     12 #include "content/common/indexed_db/indexed_db_key.h"
     13 #include "content/common/indexed_db/indexed_db_key_path.h"
     14 #include "content/common/indexed_db/indexed_db_key_range.h"
     15 
     16 namespace content {
     17 
     18 IndexWriter::IndexWriter(
     19     const IndexedDBIndexMetadata& index_metadata)
     20     : index_metadata_(index_metadata) {}
     21 
     22 IndexWriter::IndexWriter(
     23     const IndexedDBIndexMetadata& index_metadata,
     24     const IndexedDBDatabase::IndexKeys& index_keys)
     25     : index_metadata_(index_metadata), index_keys_(index_keys) {}
     26 
     27 IndexWriter::~IndexWriter() {}
     28 
     29 bool IndexWriter::VerifyIndexKeys(
     30     IndexedDBBackingStore* backing_store,
     31     IndexedDBBackingStore::Transaction* transaction,
     32     int64 database_id,
     33     int64 object_store_id,
     34     int64 index_id,
     35     bool* can_add_keys,
     36     const IndexedDBKey& primary_key,
     37     string16* error_message) const {
     38   *can_add_keys = false;
     39   for (size_t i = 0; i < index_keys_.size(); ++i) {
     40     bool ok = AddingKeyAllowed(backing_store,
     41                                transaction,
     42                                database_id,
     43                                object_store_id,
     44                                index_id,
     45                                (index_keys_)[i],
     46                                primary_key,
     47                                can_add_keys);
     48     if (!ok)
     49       return false;
     50     if (!*can_add_keys) {
     51       if (error_message)
     52         *error_message = ASCIIToUTF16("Unable to add key to index '") +
     53                          index_metadata_.name +
     54                          ASCIIToUTF16("': at least one key does not satisfy "
     55                                       "the uniqueness requirements.");
     56       return true;
     57     }
     58   }
     59   *can_add_keys = true;
     60   return true;
     61 }
     62 
     63 void IndexWriter::WriteIndexKeys(
     64     const IndexedDBBackingStore::RecordIdentifier& record_identifier,
     65     IndexedDBBackingStore* backing_store,
     66     IndexedDBBackingStore::Transaction* transaction,
     67     int64 database_id,
     68     int64 object_store_id) const {
     69   int64 index_id = index_metadata_.id;
     70   for (size_t i = 0; i < index_keys_.size(); ++i) {
     71     bool ok = backing_store->PutIndexDataForRecord(transaction,
     72                                                    database_id,
     73                                                    object_store_id,
     74                                                    index_id,
     75                                                    index_keys_[i],
     76                                                    record_identifier);
     77     // This should have already been verified as a valid write during
     78     // verify_index_keys.
     79     DCHECK(ok);
     80   }
     81 }
     82 
     83 bool IndexWriter::AddingKeyAllowed(
     84     IndexedDBBackingStore* backing_store,
     85     IndexedDBBackingStore::Transaction* transaction,
     86     int64 database_id,
     87     int64 object_store_id,
     88     int64 index_id,
     89     const IndexedDBKey& index_key,
     90     const IndexedDBKey& primary_key,
     91     bool* allowed) const {
     92   *allowed = false;
     93   if (!index_metadata_.unique) {
     94     *allowed = true;
     95     return true;
     96   }
     97 
     98   scoped_ptr<IndexedDBKey> found_primary_key;
     99   bool found = false;
    100   bool ok = backing_store->KeyExistsInIndex(transaction,
    101                                             database_id,
    102                                             object_store_id,
    103                                             index_id,
    104                                             index_key,
    105                                             &found_primary_key,
    106                                             &found);
    107   if (!ok)
    108     return false;
    109   if (!found ||
    110       (primary_key.IsValid() && found_primary_key->IsEqual(primary_key)))
    111     *allowed = true;
    112   return true;
    113 }
    114 
    115 bool MakeIndexWriters(
    116     scoped_refptr<IndexedDBTransaction> transaction,
    117     IndexedDBBackingStore* backing_store,
    118     int64 database_id,
    119     const IndexedDBObjectStoreMetadata& object_store,
    120     const IndexedDBKey& primary_key,  // makes a copy
    121     bool key_was_generated,
    122     const std::vector<int64>& index_ids,
    123     const std::vector<IndexedDBDatabase::IndexKeys>& index_keys,
    124     ScopedVector<IndexWriter>* index_writers,
    125     string16* error_message,
    126     bool* completed) {
    127   DCHECK_EQ(index_ids.size(), index_keys.size());
    128   *completed = false;
    129 
    130   std::map<int64, IndexedDBDatabase::IndexKeys> index_key_map;
    131   for (size_t i = 0; i < index_ids.size(); ++i)
    132     index_key_map[index_ids[i]] = index_keys[i];
    133 
    134   for (IndexedDBObjectStoreMetadata::IndexMap::const_iterator it =
    135            object_store.indexes.begin();
    136        it != object_store.indexes.end();
    137        ++it) {
    138     const IndexedDBIndexMetadata& index = it->second;
    139 
    140     IndexedDBDatabase::IndexKeys keys = index_key_map[it->first];
    141     // If the object_store is using auto_increment, then any indexes with an
    142     // identical key_path need to also use the primary (generated) key as a key.
    143     if (key_was_generated && (index.key_path == object_store.key_path))
    144       keys.push_back(primary_key);
    145 
    146     scoped_ptr<IndexWriter> index_writer(new IndexWriter(index, keys));
    147     bool can_add_keys = false;
    148     bool backing_store_success =
    149         index_writer->VerifyIndexKeys(backing_store,
    150                                       transaction->BackingStoreTransaction(),
    151                                       database_id,
    152                                       object_store.id,
    153                                       index.id,
    154                                       &can_add_keys,
    155                                       primary_key,
    156                                       error_message);
    157     if (!backing_store_success)
    158       return false;
    159     if (!can_add_keys)
    160       return true;
    161 
    162     index_writers->push_back(index_writer.release());
    163   }
    164 
    165   *completed = true;
    166   return true;
    167 }
    168 
    169 }  // namespace content
    170