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