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_backing_store.h"
6
7#include "base/files/file_path.h"
8#include "base/files/file_util.h"
9#include "base/format_macros.h"
10#include "base/json/json_reader.h"
11#include "base/json/json_writer.h"
12#include "base/logging.h"
13#include "base/metrics/histogram.h"
14#include "base/strings/string_util.h"
15#include "base/strings/stringprintf.h"
16#include "base/strings/utf_string_conversions.h"
17#include "content/browser/child_process_security_policy_impl.h"
18#include "content/browser/indexed_db/indexed_db_blob_info.h"
19#include "content/browser/indexed_db/indexed_db_class_factory.h"
20#include "content/browser/indexed_db/indexed_db_database_error.h"
21#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
22#include "content/browser/indexed_db/indexed_db_metadata.h"
23#include "content/browser/indexed_db/indexed_db_tracing.h"
24#include "content/browser/indexed_db/indexed_db_value.h"
25#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
26#include "content/browser/indexed_db/leveldb/leveldb_database.h"
27#include "content/browser/indexed_db/leveldb/leveldb_factory.h"
28#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
29#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
30#include "content/common/indexed_db/indexed_db_key.h"
31#include "content/common/indexed_db/indexed_db_key_path.h"
32#include "content/common/indexed_db/indexed_db_key_range.h"
33#include "content/public/browser/browser_thread.h"
34#include "net/url_request/url_request_context.h"
35#include "storage/browser/blob/blob_data_handle.h"
36#include "storage/browser/fileapi/file_stream_writer.h"
37#include "storage/browser/fileapi/file_writer_delegate.h"
38#include "storage/browser/fileapi/local_file_stream_writer.h"
39#include "storage/common/database/database_identifier.h"
40#include "third_party/WebKit/public/platform/WebIDBTypes.h"
41#include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
42#include "third_party/leveldatabase/env_chromium.h"
43
44using base::FilePath;
45using base::StringPiece;
46using storage::FileWriterDelegate;
47
48namespace content {
49
50namespace {
51
52FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) {
53  return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
54}
55
56FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase,
57                                    int64 database_id,
58                                    int64 key) {
59  FilePath path = GetBlobDirectoryName(pathBase, database_id);
60  path = path.AppendASCII(base::StringPrintf(
61      "%02x", static_cast<int>(key & 0x000000000000ff00) >> 8));
62  return path;
63}
64
65FilePath GetBlobFileNameForKey(const FilePath& pathBase,
66                               int64 database_id,
67                               int64 key) {
68  FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
69  path = path.AppendASCII(base::StringPrintf("%" PRIx64, key));
70  return path;
71}
72
73bool MakeIDBBlobDirectory(const FilePath& pathBase,
74                          int64 database_id,
75                          int64 key) {
76  FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
77  return base::CreateDirectory(path);
78}
79
80static std::string ComputeOriginIdentifier(const GURL& origin_url) {
81  return storage::GetIdentifierFromOrigin(origin_url) + "@1";
82}
83
84static base::FilePath ComputeFileName(const GURL& origin_url) {
85  return base::FilePath()
86      .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
87      .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
88}
89
90static base::FilePath ComputeBlobPath(const GURL& origin_url) {
91  return base::FilePath()
92      .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
93      .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
94}
95
96static base::FilePath ComputeCorruptionFileName(const GURL& origin_url) {
97  return ComputeFileName(origin_url)
98      .Append(FILE_PATH_LITERAL("corruption_info.json"));
99}
100
101}  // namespace
102
103static const int64 kKeyGeneratorInitialNumber =
104    1;  // From the IndexedDB specification.
105
106enum IndexedDBBackingStoreErrorSource {
107  // 0 - 2 are no longer used.
108  FIND_KEY_IN_INDEX = 3,
109  GET_IDBDATABASE_METADATA,
110  GET_INDEXES,
111  GET_KEY_GENERATOR_CURRENT_NUMBER,
112  GET_OBJECT_STORES,
113  GET_RECORD,
114  KEY_EXISTS_IN_OBJECT_STORE,
115  LOAD_CURRENT_ROW,
116  SET_UP_METADATA,
117  GET_PRIMARY_KEY_VIA_INDEX,
118  KEY_EXISTS_IN_INDEX,
119  VERSION_EXISTS,
120  DELETE_OBJECT_STORE,
121  SET_MAX_OBJECT_STORE_ID,
122  SET_MAX_INDEX_ID,
123  GET_NEW_DATABASE_ID,
124  GET_NEW_VERSION_NUMBER,
125  CREATE_IDBDATABASE_METADATA,
126  DELETE_DATABASE,
127  TRANSACTION_COMMIT_METHOD,  // TRANSACTION_COMMIT is a WinNT.h macro
128  GET_DATABASE_NAMES,
129  DELETE_INDEX,
130  CLEAR_OBJECT_STORE,
131  READ_BLOB_JOURNAL,
132  DECODE_BLOB_JOURNAL,
133  GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER,
134  GET_BLOB_INFO_FOR_RECORD,
135  INTERNAL_ERROR_MAX,
136};
137
138static void RecordInternalError(const char* type,
139                                IndexedDBBackingStoreErrorSource location) {
140  std::string name;
141  name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error");
142  base::Histogram::FactoryGet(name,
143                              1,
144                              INTERNAL_ERROR_MAX,
145                              INTERNAL_ERROR_MAX + 1,
146                              base::HistogramBase::kUmaTargetedHistogramFlag)
147      ->Add(location);
148}
149
150// Use to signal conditions caused by data corruption.
151// A macro is used instead of an inline function so that the assert and log
152// report the line number.
153#define REPORT_ERROR(type, location)                      \
154  do {                                                    \
155    LOG(ERROR) << "IndexedDB " type " Error: " #location; \
156    RecordInternalError(type, location);                  \
157  } while (0)
158
159#define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location)
160#define INTERNAL_CONSISTENCY_ERROR(location) \
161  REPORT_ERROR("Consistency", location)
162#define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location)
163
164// Use to signal conditions that usually indicate developer error, but
165// could be caused by data corruption.  A macro is used instead of an
166// inline function so that the assert and log report the line number.
167// TODO(cmumford): Improve test coverage so that all error conditions are
168// "tested" and then delete this macro.
169#define REPORT_ERROR_UNTESTED(type, location)             \
170  do {                                                    \
171    LOG(ERROR) << "IndexedDB " type " Error: " #location; \
172    NOTREACHED();                                         \
173    RecordInternalError(type, location);                  \
174  } while (0)
175
176#define INTERNAL_READ_ERROR_UNTESTED(location) \
177  REPORT_ERROR_UNTESTED("Read", location)
178#define INTERNAL_CONSISTENCY_ERROR_UNTESTED(location) \
179  REPORT_ERROR_UNTESTED("Consistency", location)
180#define INTERNAL_WRITE_ERROR_UNTESTED(location) \
181  REPORT_ERROR_UNTESTED("Write", location)
182
183static void PutBool(LevelDBTransaction* transaction,
184                    const StringPiece& key,
185                    bool value) {
186  std::string buffer;
187  EncodeBool(value, &buffer);
188  transaction->Put(key, &buffer);
189}
190
191// Was able to use LevelDB to read the data w/o error, but the data read was not
192// in the expected format.
193static leveldb::Status InternalInconsistencyStatus() {
194  return leveldb::Status::Corruption("Internal inconsistency");
195}
196
197static leveldb::Status InvalidDBKeyStatus() {
198  return leveldb::Status::InvalidArgument("Invalid database key ID");
199}
200
201static leveldb::Status IOErrorStatus() {
202  return leveldb::Status::IOError("IO Error");
203}
204
205template <typename DBOrTransaction>
206static leveldb::Status GetInt(DBOrTransaction* db,
207                              const StringPiece& key,
208                              int64* found_int,
209                              bool* found) {
210  std::string result;
211  leveldb::Status s = db->Get(key, &result, found);
212  if (!s.ok())
213    return s;
214  if (!*found)
215    return leveldb::Status::OK();
216  StringPiece slice(result);
217  if (DecodeInt(&slice, found_int) && slice.empty())
218    return s;
219  return InternalInconsistencyStatus();
220}
221
222static void PutInt(LevelDBTransaction* transaction,
223                   const StringPiece& key,
224                   int64 value) {
225  DCHECK_GE(value, 0);
226  std::string buffer;
227  EncodeInt(value, &buffer);
228  transaction->Put(key, &buffer);
229}
230
231template <typename DBOrTransaction>
232WARN_UNUSED_RESULT static leveldb::Status GetVarInt(DBOrTransaction* db,
233                                                    const StringPiece& key,
234                                                    int64* found_int,
235                                                    bool* found) {
236  std::string result;
237  leveldb::Status s = db->Get(key, &result, found);
238  if (!s.ok())
239    return s;
240  if (!*found)
241    return leveldb::Status::OK();
242  StringPiece slice(result);
243  if (DecodeVarInt(&slice, found_int) && slice.empty())
244    return s;
245  return InternalInconsistencyStatus();
246}
247
248static void PutVarInt(LevelDBTransaction* transaction,
249                      const StringPiece& key,
250                      int64 value) {
251  std::string buffer;
252  EncodeVarInt(value, &buffer);
253  transaction->Put(key, &buffer);
254}
255
256template <typename DBOrTransaction>
257WARN_UNUSED_RESULT static leveldb::Status GetString(
258    DBOrTransaction* db,
259    const StringPiece& key,
260    base::string16* found_string,
261    bool* found) {
262  std::string result;
263  *found = false;
264  leveldb::Status s = db->Get(key, &result, found);
265  if (!s.ok())
266    return s;
267  if (!*found)
268    return leveldb::Status::OK();
269  StringPiece slice(result);
270  if (DecodeString(&slice, found_string) && slice.empty())
271    return s;
272  return InternalInconsistencyStatus();
273}
274
275static void PutString(LevelDBTransaction* transaction,
276                      const StringPiece& key,
277                      const base::string16& value) {
278  std::string buffer;
279  EncodeString(value, &buffer);
280  transaction->Put(key, &buffer);
281}
282
283static void PutIDBKeyPath(LevelDBTransaction* transaction,
284                          const StringPiece& key,
285                          const IndexedDBKeyPath& value) {
286  std::string buffer;
287  EncodeIDBKeyPath(value, &buffer);
288  transaction->Put(key, &buffer);
289}
290
291static int CompareKeys(const StringPiece& a, const StringPiece& b) {
292  return Compare(a, b, false /*index_keys*/);
293}
294
295static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) {
296  return Compare(a, b, true /*index_keys*/);
297}
298
299int IndexedDBBackingStore::Comparator::Compare(const StringPiece& a,
300                                               const StringPiece& b) const {
301  return content::Compare(a, b, false /*index_keys*/);
302}
303
304const char* IndexedDBBackingStore::Comparator::Name() const {
305  return "idb_cmp1";
306}
307
308// 0 - Initial version.
309// 1 - Adds UserIntVersion to DatabaseMetaData.
310// 2 - Adds DataVersion to to global metadata.
311// 3 - Adds metadata needed for blob support.
312static const int64 kLatestKnownSchemaVersion = 3;
313WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) {
314  int64 db_schema_version = 0;
315  bool found = false;
316  leveldb::Status s =
317      GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found);
318  if (!s.ok())
319    return false;
320  if (!found) {
321    *known = true;
322    return true;
323  }
324  if (db_schema_version > kLatestKnownSchemaVersion) {
325    *known = false;
326    return true;
327  }
328
329  const uint32 latest_known_data_version =
330      blink::kSerializedScriptValueVersion;
331  int64 db_data_version = 0;
332  s = GetInt(db, DataVersionKey::Encode(), &db_data_version, &found);
333  if (!s.ok())
334    return false;
335  if (!found) {
336    *known = true;
337    return true;
338  }
339
340  if (db_data_version > latest_known_data_version) {
341    *known = false;
342    return true;
343  }
344
345  *known = true;
346  return true;
347}
348
349// TODO(ericu): Move this down into the member section of this file.  I'm
350// leaving it here for this CL as it's easier to see the diffs in place.
351WARN_UNUSED_RESULT leveldb::Status IndexedDBBackingStore::SetUpMetadata() {
352  const uint32 latest_known_data_version =
353      blink::kSerializedScriptValueVersion;
354  const std::string schema_version_key = SchemaVersionKey::Encode();
355  const std::string data_version_key = DataVersionKey::Encode();
356
357  scoped_refptr<LevelDBTransaction> transaction =
358      IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
359
360  int64 db_schema_version = 0;
361  int64 db_data_version = 0;
362  bool found = false;
363  leveldb::Status s =
364      GetInt(transaction.get(), schema_version_key, &db_schema_version, &found);
365  if (!s.ok()) {
366    INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
367    return s;
368  }
369  if (!found) {
370    // Initialize new backing store.
371    db_schema_version = kLatestKnownSchemaVersion;
372    PutInt(transaction.get(), schema_version_key, db_schema_version);
373    db_data_version = latest_known_data_version;
374    PutInt(transaction.get(), data_version_key, db_data_version);
375    // If a blob directory already exists for this database, blow it away.  It's
376    // leftover from a partially-purged previous generation of data.
377    if (!base::DeleteFile(blob_path_, true)) {
378      INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
379      return IOErrorStatus();
380    }
381  } else {
382    // Upgrade old backing store.
383    DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion);
384    if (db_schema_version < 1) {
385      db_schema_version = 1;
386      PutInt(transaction.get(), schema_version_key, db_schema_version);
387      const std::string start_key =
388          DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
389      const std::string stop_key =
390          DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
391      scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
392      for (s = it->Seek(start_key);
393           s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
394           s = it->Next()) {
395        int64 database_id = 0;
396        found = false;
397        s = GetInt(transaction.get(), it->Key(), &database_id, &found);
398        if (!s.ok()) {
399          INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
400          return s;
401        }
402        if (!found) {
403          INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
404          return InternalInconsistencyStatus();
405        }
406        std::string int_version_key = DatabaseMetaDataKey::Encode(
407            database_id, DatabaseMetaDataKey::USER_INT_VERSION);
408        PutVarInt(transaction.get(),
409                  int_version_key,
410                  IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
411      }
412    }
413    if (s.ok() && db_schema_version < 2) {
414      db_schema_version = 2;
415      PutInt(transaction.get(), schema_version_key, db_schema_version);
416      db_data_version = blink::kSerializedScriptValueVersion;
417      PutInt(transaction.get(), data_version_key, db_data_version);
418    }
419    if (db_schema_version < 3) {
420      db_schema_version = 3;
421      if (!base::DeleteFile(blob_path_, true)) {
422        INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
423        return IOErrorStatus();
424      }
425    }
426  }
427
428  if (!s.ok()) {
429    INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
430    return s;
431  }
432
433  // All new values will be written using this serialization version.
434  found = false;
435  s = GetInt(transaction.get(), data_version_key, &db_data_version, &found);
436  if (!s.ok()) {
437    INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
438    return s;
439  }
440  if (!found) {
441    INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
442    return InternalInconsistencyStatus();
443  }
444  if (db_data_version < latest_known_data_version) {
445    db_data_version = latest_known_data_version;
446    PutInt(transaction.get(), data_version_key, db_data_version);
447  }
448
449  DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion);
450  DCHECK_EQ(db_data_version, latest_known_data_version);
451
452  s = transaction->Commit();
453  if (!s.ok())
454    INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
455  return s;
456}
457
458template <typename DBOrTransaction>
459WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId(
460    DBOrTransaction* db,
461    int64 database_id,
462    int64* max_object_store_id) {
463  const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode(
464      database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
465  return GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id);
466}
467
468template <typename DBOrTransaction>
469WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId(
470    DBOrTransaction* db,
471    const std::string& max_object_store_id_key,
472    int64* max_object_store_id) {
473  *max_object_store_id = -1;
474  bool found = false;
475  leveldb::Status s =
476      GetInt(db, max_object_store_id_key, max_object_store_id, &found);
477  if (!s.ok())
478    return s;
479  if (!found)
480    *max_object_store_id = 0;
481
482  DCHECK_GE(*max_object_store_id, 0);
483  return s;
484}
485
486class DefaultLevelDBFactory : public LevelDBFactory {
487 public:
488  DefaultLevelDBFactory() {}
489  virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
490                                      const LevelDBComparator* comparator,
491                                      scoped_ptr<LevelDBDatabase>* db,
492                                      bool* is_disk_full) OVERRIDE {
493    return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full);
494  }
495  virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
496      OVERRIDE {
497    return LevelDBDatabase::Destroy(file_name);
498  }
499
500 private:
501  DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory);
502};
503
504static bool GetBlobKeyGeneratorCurrentNumber(
505    LevelDBTransaction* leveldb_transaction,
506    int64 database_id,
507    int64* blob_key_generator_current_number) {
508  const std::string key_gen_key = DatabaseMetaDataKey::Encode(
509      database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER);
510
511  // Default to initial number if not found.
512  int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber;
513  std::string data;
514
515  bool found = false;
516  bool ok = leveldb_transaction->Get(key_gen_key, &data, &found).ok();
517  if (!ok) {
518    INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER);
519    return false;
520  }
521  if (found) {
522    StringPiece slice(data);
523    if (!DecodeVarInt(&slice, &cur_number) || !slice.empty() ||
524        !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) {
525      INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER);
526      return false;
527    }
528  }
529  *blob_key_generator_current_number = cur_number;
530  return true;
531}
532
533static bool UpdateBlobKeyGeneratorCurrentNumber(
534    LevelDBTransaction* leveldb_transaction,
535    int64 database_id,
536    int64 blob_key_generator_current_number) {
537#ifndef NDEBUG
538  int64 old_number;
539  if (!GetBlobKeyGeneratorCurrentNumber(
540          leveldb_transaction, database_id, &old_number))
541    return false;
542  DCHECK_LT(old_number, blob_key_generator_current_number);
543#endif
544  DCHECK(
545      DatabaseMetaDataKey::IsValidBlobKey(blob_key_generator_current_number));
546  const std::string key = DatabaseMetaDataKey::Encode(
547      database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER);
548
549  PutVarInt(leveldb_transaction, key, blob_key_generator_current_number);
550  return true;
551}
552
553// TODO(ericu): Error recovery. If we persistently can't read the
554// blob journal, the safe thing to do is to clear it and leak the blobs,
555// though that may be costly. Still, database/directory deletion should always
556// clean things up, and we can write an fsck that will do a full correction if
557// need be.
558template <typename T>
559static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
560                                      T* leveldb_transaction,
561                                      BlobJournalType* journal) {
562  std::string data;
563  bool found = false;
564  leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
565  if (!s.ok()) {
566    INTERNAL_READ_ERROR(READ_BLOB_JOURNAL);
567    return s;
568  }
569  journal->clear();
570  if (!found || !data.size())
571    return leveldb::Status::OK();
572  StringPiece slice(data);
573  if (!DecodeBlobJournal(&slice, journal)) {
574    INTERNAL_CONSISTENCY_ERROR_UNTESTED(DECODE_BLOB_JOURNAL);
575    s = InternalInconsistencyStatus();
576  }
577  return s;
578}
579
580static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction,
581                             const std::string& level_db_key) {
582  leveldb_transaction->Remove(level_db_key);
583}
584
585static void UpdatePrimaryJournalWithBlobList(
586    LevelDBTransaction* leveldb_transaction,
587    const BlobJournalType& journal) {
588  const std::string leveldb_key = BlobJournalKey::Encode();
589  std::string data;
590  EncodeBlobJournal(journal, &data);
591  leveldb_transaction->Put(leveldb_key, &data);
592}
593
594static void UpdateLiveBlobJournalWithBlobList(
595    LevelDBTransaction* leveldb_transaction,
596    const BlobJournalType& journal) {
597  const std::string leveldb_key = LiveBlobJournalKey::Encode();
598  std::string data;
599  EncodeBlobJournal(journal, &data);
600  leveldb_transaction->Put(leveldb_key, &data);
601}
602
603static leveldb::Status MergeBlobsIntoLiveBlobJournal(
604    LevelDBTransaction* leveldb_transaction,
605    const BlobJournalType& journal) {
606  BlobJournalType old_journal;
607  const std::string key = LiveBlobJournalKey::Encode();
608  leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal);
609  if (!s.ok())
610    return s;
611
612  old_journal.insert(old_journal.end(), journal.begin(), journal.end());
613
614  UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal);
615  return leveldb::Status::OK();
616}
617
618static void UpdateBlobJournalWithDatabase(
619    LevelDBDirectTransaction* leveldb_transaction,
620    int64 database_id) {
621  BlobJournalType journal;
622  journal.push_back(
623      std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
624  const std::string key = BlobJournalKey::Encode();
625  std::string data;
626  EncodeBlobJournal(journal, &data);
627  leveldb_transaction->Put(key, &data);
628}
629
630static leveldb::Status MergeDatabaseIntoLiveBlobJournal(
631    LevelDBDirectTransaction* leveldb_transaction,
632    int64 database_id) {
633  BlobJournalType journal;
634  const std::string key = LiveBlobJournalKey::Encode();
635  leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal);
636  if (!s.ok())
637    return s;
638  journal.push_back(
639      std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
640  std::string data;
641  EncodeBlobJournal(journal, &data);
642  leveldb_transaction->Put(key, &data);
643  return leveldb::Status::OK();
644}
645
646// Blob Data is encoded as a series of:
647//   { is_file [bool], key [int64 as varInt],
648//     type [string-with-length, may be empty],
649//     (for Blobs only) size [int64 as varInt]
650//     (for Files only) fileName [string-with-length]
651//   }
652// There is no length field; just read until you run out of data.
653static std::string EncodeBlobData(
654    const std::vector<IndexedDBBlobInfo*>& blob_info) {
655  std::string ret;
656  std::vector<IndexedDBBlobInfo*>::const_iterator iter;
657  for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
658    const IndexedDBBlobInfo& info = **iter;
659    EncodeBool(info.is_file(), &ret);
660    EncodeVarInt(info.key(), &ret);
661    EncodeStringWithLength(info.type(), &ret);
662    if (info.is_file())
663      EncodeStringWithLength(info.file_name(), &ret);
664    else
665      EncodeVarInt(info.size(), &ret);
666  }
667  return ret;
668}
669
670static bool DecodeBlobData(const std::string& data,
671                           std::vector<IndexedDBBlobInfo>* output) {
672  std::vector<IndexedDBBlobInfo> ret;
673  output->clear();
674  StringPiece slice(data);
675  while (!slice.empty()) {
676    bool is_file;
677    int64 key;
678    base::string16 type;
679    int64 size;
680    base::string16 file_name;
681
682    if (!DecodeBool(&slice, &is_file))
683      return false;
684    if (!DecodeVarInt(&slice, &key) ||
685        !DatabaseMetaDataKey::IsValidBlobKey(key))
686      return false;
687    if (!DecodeStringWithLength(&slice, &type))
688      return false;
689    if (is_file) {
690      if (!DecodeStringWithLength(&slice, &file_name))
691        return false;
692      ret.push_back(IndexedDBBlobInfo(key, type, file_name));
693    } else {
694      if (!DecodeVarInt(&slice, &size) || size < 0)
695        return false;
696      ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key));
697    }
698  }
699  output->swap(ret);
700
701  return true;
702}
703
704IndexedDBBackingStore::IndexedDBBackingStore(
705    IndexedDBFactory* indexed_db_factory,
706    const GURL& origin_url,
707    const base::FilePath& blob_path,
708    net::URLRequestContext* request_context,
709    scoped_ptr<LevelDBDatabase> db,
710    scoped_ptr<LevelDBComparator> comparator,
711    base::SequencedTaskRunner* task_runner)
712    : indexed_db_factory_(indexed_db_factory),
713      origin_url_(origin_url),
714      blob_path_(blob_path),
715      origin_identifier_(ComputeOriginIdentifier(origin_url)),
716      request_context_(request_context),
717      task_runner_(task_runner),
718      db_(db.Pass()),
719      comparator_(comparator.Pass()),
720      active_blob_registry_(this) {
721}
722
723IndexedDBBackingStore::~IndexedDBBackingStore() {
724  if (!blob_path_.empty() && !child_process_ids_granted_.empty()) {
725    ChildProcessSecurityPolicyImpl* policy =
726        ChildProcessSecurityPolicyImpl::GetInstance();
727    std::set<int>::const_iterator iter;
728    for (iter = child_process_ids_granted_.begin();
729         iter != child_process_ids_granted_.end();
730         ++iter) {
731      policy->RevokeAllPermissionsForFile(*iter, blob_path_);
732    }
733  }
734  STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
735                                       incognito_blob_map_.end());
736  // db_'s destructor uses comparator_. The order of destruction is important.
737  db_.reset();
738  comparator_.reset();
739}
740
741IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
742    const std::string& primary_key,
743    int64 version)
744    : primary_key_(primary_key), version_(version) {
745  DCHECK(!primary_key.empty());
746}
747IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
748    : primary_key_(), version_(-1) {}
749IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
750
751IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
752IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
753
754enum IndexedDBBackingStoreOpenResult {
755  INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS,
756  INDEXED_DB_BACKING_STORE_OPEN_SUCCESS,
757  INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
758  INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA,
759  INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
760  INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
761  INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
762  INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
763  INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
764  INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
765  INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
766  INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED,
767  INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
768  INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY,
769  INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION,
770  INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR,
771  INDEXED_DB_BACKING_STORE_OPEN_MAX,
772};
773
774// static
775scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
776    IndexedDBFactory* indexed_db_factory,
777    const GURL& origin_url,
778    const base::FilePath& path_base,
779    net::URLRequestContext* request_context,
780    blink::WebIDBDataLoss* data_loss,
781    std::string* data_loss_message,
782    bool* disk_full,
783    base::SequencedTaskRunner* task_runner,
784    bool clean_journal,
785    leveldb::Status* status) {
786  *data_loss = blink::WebIDBDataLossNone;
787  DefaultLevelDBFactory leveldb_factory;
788  return IndexedDBBackingStore::Open(indexed_db_factory,
789                                     origin_url,
790                                     path_base,
791                                     request_context,
792                                     data_loss,
793                                     data_loss_message,
794                                     disk_full,
795                                     &leveldb_factory,
796                                     task_runner,
797                                     clean_journal,
798                                     status);
799}
800
801static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) {
802  if (origin_url.host() == "docs.google.com")
803    return ".Docs";
804  return std::string();
805}
806
807static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result,
808                                const GURL& origin_url) {
809  UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus",
810                            result,
811                            INDEXED_DB_BACKING_STORE_OPEN_MAX);
812  const std::string suffix = OriginToCustomHistogramSuffix(origin_url);
813  // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used
814  // to generate a graph. So as not to alter the meaning of that graph,
815  // continue to collect all stats there (above) but also now collect docs stats
816  // separately (below).
817  if (!suffix.empty()) {
818    base::LinearHistogram::FactoryGet(
819        "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix,
820        1,
821        INDEXED_DB_BACKING_STORE_OPEN_MAX,
822        INDEXED_DB_BACKING_STORE_OPEN_MAX + 1,
823        base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result);
824  }
825}
826
827static bool IsPathTooLong(const base::FilePath& leveldb_dir) {
828  int limit = base::GetMaximumPathComponentLength(leveldb_dir.DirName());
829  if (limit == -1) {
830    DLOG(WARNING) << "GetMaximumPathComponentLength returned -1";
831    // In limited testing, ChromeOS returns 143, other OSes 255.
832#if defined(OS_CHROMEOS)
833    limit = 143;
834#else
835    limit = 255;
836#endif
837  }
838  size_t component_length = leveldb_dir.BaseName().value().length();
839  if (component_length > static_cast<uint32_t>(limit)) {
840    DLOG(WARNING) << "Path component length (" << component_length
841                  << ") exceeds maximum (" << limit
842                  << ") allowed by this filesystem.";
843    const int min = 140;
844    const int max = 300;
845    const int num_buckets = 12;
846    UMA_HISTOGRAM_CUSTOM_COUNTS(
847        "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength",
848        component_length,
849        min,
850        max,
851        num_buckets);
852    return true;
853  }
854  return false;
855}
856
857leveldb::Status IndexedDBBackingStore::DestroyBackingStore(
858    const base::FilePath& path_base,
859    const GURL& origin_url) {
860  const base::FilePath file_path =
861      path_base.Append(ComputeFileName(origin_url));
862  DefaultLevelDBFactory leveldb_factory;
863  return leveldb_factory.DestroyLevelDB(file_path);
864}
865
866bool IndexedDBBackingStore::ReadCorruptionInfo(const base::FilePath& path_base,
867                                               const GURL& origin_url,
868                                               std::string* message) {
869  const base::FilePath info_path =
870      path_base.Append(ComputeCorruptionFileName(origin_url));
871
872  if (IsPathTooLong(info_path))
873    return false;
874
875  const int64 max_json_len = 4096;
876  int64 file_size(0);
877  if (!GetFileSize(info_path, &file_size) || file_size > max_json_len)
878    return false;
879  if (!file_size) {
880    NOTREACHED();
881    return false;
882  }
883
884  base::File file(info_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
885  bool success = false;
886  if (file.IsValid()) {
887    std::vector<char> bytes(file_size);
888    if (file_size == file.Read(0, &bytes[0], file_size)) {
889      std::string input_js(&bytes[0], file_size);
890      base::JSONReader reader;
891      scoped_ptr<base::Value> val(reader.ReadToValue(input_js));
892      if (val && val->GetType() == base::Value::TYPE_DICTIONARY) {
893        base::DictionaryValue* dict_val =
894            static_cast<base::DictionaryValue*>(val.get());
895        success = dict_val->GetString("message", message);
896      }
897    }
898    file.Close();
899  }
900
901  base::DeleteFile(info_path, false);
902
903  return success;
904}
905
906bool IndexedDBBackingStore::RecordCorruptionInfo(
907    const base::FilePath& path_base,
908    const GURL& origin_url,
909    const std::string& message) {
910  const base::FilePath info_path =
911      path_base.Append(ComputeCorruptionFileName(origin_url));
912  if (IsPathTooLong(info_path))
913    return false;
914
915  base::DictionaryValue root_dict;
916  root_dict.SetString("message", message);
917  std::string output_js;
918  base::JSONWriter::Write(&root_dict, &output_js);
919
920  base::File file(info_path,
921                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
922  if (!file.IsValid())
923    return false;
924  int written = file.Write(0, output_js.c_str(), output_js.length());
925  return size_t(written) == output_js.length();
926}
927
928// static
929scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
930    IndexedDBFactory* indexed_db_factory,
931    const GURL& origin_url,
932    const base::FilePath& path_base,
933    net::URLRequestContext* request_context,
934    blink::WebIDBDataLoss* data_loss,
935    std::string* data_loss_message,
936    bool* is_disk_full,
937    LevelDBFactory* leveldb_factory,
938    base::SequencedTaskRunner* task_runner,
939    bool clean_journal,
940    leveldb::Status* status) {
941  IDB_TRACE("IndexedDBBackingStore::Open");
942  DCHECK(!path_base.empty());
943  *data_loss = blink::WebIDBDataLossNone;
944  *data_loss_message = "";
945  *is_disk_full = false;
946
947  *status = leveldb::Status::OK();
948
949  scoped_ptr<LevelDBComparator> comparator(new Comparator());
950
951  if (!base::IsStringASCII(path_base.AsUTF8Unsafe())) {
952    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
953                        origin_url);
954  }
955  if (!base::CreateDirectory(path_base)) {
956    *status =
957        leveldb::Status::IOError("Unable to create IndexedDB database path");
958    LOG(ERROR) << status->ToString() << ": \"" << path_base.AsUTF8Unsafe()
959               << "\"";
960    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
961                        origin_url);
962    return scoped_refptr<IndexedDBBackingStore>();
963  }
964
965  const base::FilePath file_path =
966      path_base.Append(ComputeFileName(origin_url));
967  const base::FilePath blob_path =
968      path_base.Append(ComputeBlobPath(origin_url));
969
970  if (IsPathTooLong(file_path)) {
971    *status = leveldb::Status::IOError("File path too long");
972    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
973                        origin_url);
974    return scoped_refptr<IndexedDBBackingStore>();
975  }
976
977  scoped_ptr<LevelDBDatabase> db;
978  *status = leveldb_factory->OpenLevelDB(
979      file_path, comparator.get(), &db, is_disk_full);
980
981  DCHECK(!db == !status->ok());
982  if (!status->ok()) {
983    if (leveldb_env::IndicatesDiskFull(*status)) {
984      *is_disk_full = true;
985    } else if (leveldb_env::IsCorruption(*status)) {
986      *data_loss = blink::WebIDBDataLossTotal;
987      *data_loss_message = leveldb_env::GetCorruptionMessage(*status);
988    }
989  }
990
991  bool is_schema_known = false;
992  if (db) {
993    std::string corruption_message;
994    if (ReadCorruptionInfo(path_base, origin_url, &corruption_message)) {
995      LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) "
996                    "database.";
997      HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION,
998                          origin_url);
999      db.reset();
1000      *data_loss = blink::WebIDBDataLossTotal;
1001      *data_loss_message =
1002          "IndexedDB (database was corrupt): " + corruption_message;
1003    } else if (!IsSchemaKnown(db.get(), &is_schema_known)) {
1004      LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as "
1005                    "failure to open";
1006      HistogramOpenStatus(
1007          INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
1008          origin_url);
1009      db.reset();
1010      *data_loss = blink::WebIDBDataLossTotal;
1011      *data_loss_message = "I/O error checking schema";
1012    } else if (!is_schema_known) {
1013      LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it "
1014                    "as failure to open";
1015      HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA,
1016                          origin_url);
1017      db.reset();
1018      *data_loss = blink::WebIDBDataLossTotal;
1019      *data_loss_message = "Unknown schema";
1020    }
1021  }
1022
1023  DCHECK(status->ok() || !is_schema_known || leveldb_env::IsIOError(*status) ||
1024         leveldb_env::IsCorruption(*status));
1025
1026  if (db) {
1027    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url);
1028  } else if (leveldb_env::IsIOError(*status)) {
1029    LOG(ERROR) << "Unable to open backing store, not trying to recover - "
1030               << status->ToString();
1031    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, origin_url);
1032    return scoped_refptr<IndexedDBBackingStore>();
1033  } else {
1034    DCHECK(!is_schema_known || leveldb_env::IsCorruption(*status));
1035    LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
1036    *status = leveldb_factory->DestroyLevelDB(file_path);
1037    if (!status->ok()) {
1038      LOG(ERROR) << "IndexedDB backing store cleanup failed";
1039      HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
1040                          origin_url);
1041      return scoped_refptr<IndexedDBBackingStore>();
1042    }
1043
1044    LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening";
1045    leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, NULL);
1046    if (!db) {
1047      LOG(ERROR) << "IndexedDB backing store reopen after recovery failed";
1048      HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
1049                          origin_url);
1050      return scoped_refptr<IndexedDBBackingStore>();
1051    }
1052    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
1053                        origin_url);
1054  }
1055
1056  if (!db) {
1057    NOTREACHED();
1058    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
1059                        origin_url);
1060    return scoped_refptr<IndexedDBBackingStore>();
1061  }
1062
1063  scoped_refptr<IndexedDBBackingStore> backing_store =
1064      Create(indexed_db_factory,
1065             origin_url,
1066             blob_path,
1067             request_context,
1068             db.Pass(),
1069             comparator.Pass(),
1070             task_runner,
1071             status);
1072
1073  if (clean_journal && backing_store.get() &&
1074      !backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode()).ok()) {
1075    HistogramOpenStatus(
1076        INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, origin_url);
1077    return scoped_refptr<IndexedDBBackingStore>();
1078  }
1079  return backing_store;
1080}
1081
1082// static
1083scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
1084    const GURL& origin_url,
1085    base::SequencedTaskRunner* task_runner,
1086    leveldb::Status* status) {
1087  DefaultLevelDBFactory leveldb_factory;
1088  return IndexedDBBackingStore::OpenInMemory(
1089      origin_url, &leveldb_factory, task_runner, status);
1090}
1091
1092// static
1093scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
1094    const GURL& origin_url,
1095    LevelDBFactory* leveldb_factory,
1096    base::SequencedTaskRunner* task_runner,
1097    leveldb::Status* status) {
1098  IDB_TRACE("IndexedDBBackingStore::OpenInMemory");
1099
1100  scoped_ptr<LevelDBComparator> comparator(new Comparator());
1101  scoped_ptr<LevelDBDatabase> db =
1102      LevelDBDatabase::OpenInMemory(comparator.get());
1103  if (!db) {
1104    LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed.";
1105    HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
1106                        origin_url);
1107    return scoped_refptr<IndexedDBBackingStore>();
1108  }
1109  HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url);
1110
1111  return Create(NULL /* indexed_db_factory */,
1112                origin_url,
1113                base::FilePath(),
1114                NULL /* request_context */,
1115                db.Pass(),
1116                comparator.Pass(),
1117                task_runner,
1118                status);
1119}
1120
1121// static
1122scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
1123    IndexedDBFactory* indexed_db_factory,
1124    const GURL& origin_url,
1125    const base::FilePath& blob_path,
1126    net::URLRequestContext* request_context,
1127    scoped_ptr<LevelDBDatabase> db,
1128    scoped_ptr<LevelDBComparator> comparator,
1129    base::SequencedTaskRunner* task_runner,
1130    leveldb::Status* status) {
1131  // TODO(jsbell): Handle comparator name changes.
1132  scoped_refptr<IndexedDBBackingStore> backing_store(
1133      new IndexedDBBackingStore(indexed_db_factory,
1134                                origin_url,
1135                                blob_path,
1136                                request_context,
1137                                db.Pass(),
1138                                comparator.Pass(),
1139                                task_runner));
1140  *status = backing_store->SetUpMetadata();
1141  if (!status->ok())
1142    return scoped_refptr<IndexedDBBackingStore>();
1143
1144  return backing_store;
1145}
1146
1147void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) {
1148  if (!child_process_ids_granted_.count(child_process_id)) {
1149    child_process_ids_granted_.insert(child_process_id);
1150    ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
1151        child_process_id, blob_path_);
1152  }
1153}
1154
1155std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
1156    leveldb::Status* s) {
1157  *s = leveldb::Status::OK();
1158  std::vector<base::string16> found_names;
1159  const std::string start_key =
1160      DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
1161  const std::string stop_key =
1162      DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
1163
1164  DCHECK(found_names.empty());
1165
1166  scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
1167  for (*s = it->Seek(start_key);
1168       s->ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
1169       *s = it->Next()) {
1170    // Decode database name (in iterator key).
1171    StringPiece slice(it->Key());
1172    DatabaseNameKey database_name_key;
1173    if (!DatabaseNameKey::Decode(&slice, &database_name_key) ||
1174        !slice.empty()) {
1175      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
1176      continue;
1177    }
1178
1179    // Decode database id (in iterator value).
1180    int64 database_id = 0;
1181    StringPiece valueSlice(it->Value());
1182    if (!DecodeInt(&valueSlice, &database_id) || !valueSlice.empty()) {
1183      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
1184      continue;
1185    }
1186
1187    // Look up version by id.
1188    bool found = false;
1189    int64 database_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
1190    *s = GetVarInt(db_.get(),
1191                   DatabaseMetaDataKey::Encode(
1192                       database_id, DatabaseMetaDataKey::USER_INT_VERSION),
1193                   &database_version,
1194                   &found);
1195    if (!s->ok() || !found) {
1196      INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES);
1197      continue;
1198    }
1199
1200    // Ignore stale metadata from failed initial opens.
1201    if (database_version != IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
1202      found_names.push_back(database_name_key.database_name());
1203  }
1204
1205  if (!s->ok())
1206    INTERNAL_READ_ERROR(GET_DATABASE_NAMES);
1207
1208  return found_names;
1209}
1210
1211leveldb::Status IndexedDBBackingStore::GetIDBDatabaseMetaData(
1212    const base::string16& name,
1213    IndexedDBDatabaseMetadata* metadata,
1214    bool* found) {
1215  const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
1216  *found = false;
1217
1218  leveldb::Status s = GetInt(db_.get(), key, &metadata->id, found);
1219  if (!s.ok()) {
1220    INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
1221    return s;
1222  }
1223  if (!*found)
1224    return leveldb::Status::OK();
1225
1226  s = GetString(db_.get(),
1227                DatabaseMetaDataKey::Encode(metadata->id,
1228                                            DatabaseMetaDataKey::USER_VERSION),
1229                &metadata->version,
1230                found);
1231  if (!s.ok()) {
1232    INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1233    return s;
1234  }
1235  if (!*found) {
1236    INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1237    return InternalInconsistencyStatus();
1238  }
1239
1240  s = GetVarInt(db_.get(),
1241                DatabaseMetaDataKey::Encode(
1242                    metadata->id, DatabaseMetaDataKey::USER_INT_VERSION),
1243                &metadata->int_version,
1244                found);
1245  if (!s.ok()) {
1246    INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1247    return s;
1248  }
1249  if (!*found) {
1250    INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1251    return InternalInconsistencyStatus();
1252  }
1253
1254  if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
1255    metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
1256
1257  s = GetMaxObjectStoreId(
1258      db_.get(), metadata->id, &metadata->max_object_store_id);
1259  if (!s.ok()) {
1260    INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1261  }
1262
1263  // We don't cache this, we just check it if it's there.
1264  int64 blob_key_generator_current_number =
1265      DatabaseMetaDataKey::kInvalidBlobKey;
1266
1267  s = GetVarInt(
1268      db_.get(),
1269      DatabaseMetaDataKey::Encode(
1270          metadata->id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER),
1271      &blob_key_generator_current_number,
1272      found);
1273  if (!s.ok()) {
1274    INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1275    return s;
1276  }
1277  if (!*found) {
1278    // This database predates blob support.
1279    *found = true;
1280  } else if (!DatabaseMetaDataKey::IsValidBlobKey(
1281                 blob_key_generator_current_number)) {
1282    INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1283    return InternalInconsistencyStatus();
1284  }
1285
1286  return s;
1287}
1288
1289WARN_UNUSED_RESULT static leveldb::Status GetNewDatabaseId(
1290    LevelDBTransaction* transaction,
1291    int64* new_id) {
1292  *new_id = -1;
1293  int64 max_database_id = -1;
1294  bool found = false;
1295  leveldb::Status s =
1296      GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found);
1297  if (!s.ok()) {
1298    INTERNAL_READ_ERROR_UNTESTED(GET_NEW_DATABASE_ID);
1299    return s;
1300  }
1301  if (!found)
1302    max_database_id = 0;
1303
1304  DCHECK_GE(max_database_id, 0);
1305
1306  int64 database_id = max_database_id + 1;
1307  PutInt(transaction, MaxDatabaseIdKey::Encode(), database_id);
1308  *new_id = database_id;
1309  return leveldb::Status::OK();
1310}
1311
1312leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
1313    const base::string16& name,
1314    const base::string16& version,
1315    int64 int_version,
1316    int64* row_id) {
1317  // TODO(jsbell): Don't persist metadata if open fails. http://crbug.com/395472
1318  scoped_refptr<LevelDBTransaction> transaction =
1319      IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
1320
1321  leveldb::Status s = GetNewDatabaseId(transaction.get(), row_id);
1322  if (!s.ok())
1323    return s;
1324  DCHECK_GE(*row_id, 0);
1325
1326  if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
1327    int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
1328
1329  PutInt(transaction.get(),
1330         DatabaseNameKey::Encode(origin_identifier_, name),
1331         *row_id);
1332  PutString(
1333      transaction.get(),
1334      DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION),
1335      version);
1336  PutVarInt(transaction.get(),
1337            DatabaseMetaDataKey::Encode(*row_id,
1338                                        DatabaseMetaDataKey::USER_INT_VERSION),
1339            int_version);
1340  PutVarInt(
1341      transaction.get(),
1342      DatabaseMetaDataKey::Encode(
1343          *row_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER),
1344      DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber);
1345
1346  s = transaction->Commit();
1347  if (!s.ok())
1348    INTERNAL_WRITE_ERROR_UNTESTED(CREATE_IDBDATABASE_METADATA);
1349  return s;
1350}
1351
1352bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
1353    IndexedDBBackingStore::Transaction* transaction,
1354    int64 row_id,
1355    int64 int_version) {
1356  if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
1357    int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
1358  DCHECK_GE(int_version, 0) << "int_version was " << int_version;
1359  PutVarInt(transaction->transaction(),
1360            DatabaseMetaDataKey::Encode(row_id,
1361                                        DatabaseMetaDataKey::USER_INT_VERSION),
1362            int_version);
1363  return true;
1364}
1365
1366// If you're deleting a range that contains user keys that have blob info, this
1367// won't clean up the blobs.
1368static leveldb::Status DeleteRangeBasic(LevelDBTransaction* transaction,
1369                                        const std::string& begin,
1370                                        const std::string& end,
1371                                        bool upper_open) {
1372  scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
1373  leveldb::Status s;
1374  for (s = it->Seek(begin); s.ok() && it->IsValid() &&
1375                                (upper_open ? CompareKeys(it->Key(), end) < 0
1376                                            : CompareKeys(it->Key(), end) <= 0);
1377       s = it->Next())
1378    transaction->Remove(it->Key());
1379  return s;
1380}
1381
1382static leveldb::Status DeleteBlobsInRange(
1383    IndexedDBBackingStore::Transaction* transaction,
1384    int64 database_id,
1385    int64 object_store_id,
1386    const std::string& start_key,
1387    const std::string& end_key,
1388    bool upper_open) {
1389  scoped_ptr<LevelDBIterator> it = transaction->transaction()->CreateIterator();
1390  leveldb::Status s = it->Seek(start_key);
1391  for (; s.ok() && it->IsValid() &&
1392             (upper_open ? CompareKeys(it->Key(), end_key) < 0
1393                         : CompareKeys(it->Key(), end_key) <= 0);
1394       s = it->Next()) {
1395    StringPiece key_piece(it->Key());
1396    std::string user_key =
1397        BlobEntryKey::ReencodeToObjectStoreDataKey(&key_piece);
1398    if (!user_key.size()) {
1399      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
1400      return InternalInconsistencyStatus();
1401    }
1402    transaction->PutBlobInfo(
1403        database_id, object_store_id, user_key, NULL, NULL);
1404  }
1405  return s;
1406}
1407
1408static leveldb::Status DeleteBlobsInObjectStore(
1409    IndexedDBBackingStore::Transaction* transaction,
1410    int64 database_id,
1411    int64 object_store_id) {
1412  std::string start_key, stop_key;
1413  start_key =
1414      BlobEntryKey::EncodeMinKeyForObjectStore(database_id, object_store_id);
1415  stop_key =
1416      BlobEntryKey::EncodeStopKeyForObjectStore(database_id, object_store_id);
1417  return DeleteBlobsInRange(
1418      transaction, database_id, object_store_id, start_key, stop_key, true);
1419}
1420
1421leveldb::Status IndexedDBBackingStore::DeleteDatabase(
1422    const base::string16& name) {
1423  IDB_TRACE("IndexedDBBackingStore::DeleteDatabase");
1424  scoped_ptr<LevelDBDirectTransaction> transaction =
1425      LevelDBDirectTransaction::Create(db_.get());
1426
1427  leveldb::Status s;
1428  s = CleanUpBlobJournal(BlobJournalKey::Encode());
1429  if (!s.ok())
1430    return s;
1431
1432  IndexedDBDatabaseMetadata metadata;
1433  bool success = false;
1434  s = GetIDBDatabaseMetaData(name, &metadata, &success);
1435  if (!s.ok())
1436    return s;
1437  if (!success)
1438    return leveldb::Status::OK();
1439
1440  const std::string start_key = DatabaseMetaDataKey::Encode(
1441      metadata.id, DatabaseMetaDataKey::ORIGIN_NAME);
1442  const std::string stop_key = DatabaseMetaDataKey::Encode(
1443      metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME);
1444  scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
1445  for (s = it->Seek(start_key);
1446       s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
1447       s = it->Next())
1448    transaction->Remove(it->Key());
1449  if (!s.ok()) {
1450    INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE);
1451    return s;
1452  }
1453
1454  const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
1455  transaction->Remove(key);
1456
1457  bool need_cleanup = false;
1458  if (active_blob_registry()->MarkDeletedCheckIfUsed(
1459          metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) {
1460    s = MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id);
1461    if (!s.ok())
1462      return s;
1463  } else {
1464    UpdateBlobJournalWithDatabase(transaction.get(), metadata.id);
1465    need_cleanup = true;
1466  }
1467
1468  s = transaction->Commit();
1469  if (!s.ok()) {
1470    INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE);
1471    return s;
1472  }
1473
1474  if (need_cleanup)
1475    CleanUpBlobJournal(BlobJournalKey::Encode());
1476
1477  db_->Compact(start_key, stop_key);
1478  return s;
1479}
1480
1481static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it,
1482                                            const std::string& stop_key,
1483                                            int64 object_store_id,
1484                                            int64 meta_data_type) {
1485  if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0)
1486    return false;
1487
1488  StringPiece slice(it->Key());
1489  ObjectStoreMetaDataKey meta_data_key;
1490  bool ok =
1491      ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty();
1492  DCHECK(ok);
1493  if (meta_data_key.ObjectStoreId() != object_store_id)
1494    return false;
1495  if (meta_data_key.MetaDataType() != meta_data_type)
1496    return false;
1497  return ok;
1498}
1499
1500// TODO(jsbell): This should do some error handling rather than
1501// plowing ahead when bad data is encountered.
1502leveldb::Status IndexedDBBackingStore::GetObjectStores(
1503    int64 database_id,
1504    IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) {
1505  IDB_TRACE("IndexedDBBackingStore::GetObjectStores");
1506  if (!KeyPrefix::IsValidDatabaseId(database_id))
1507    return InvalidDBKeyStatus();
1508  const std::string start_key =
1509      ObjectStoreMetaDataKey::Encode(database_id, 1, 0);
1510  const std::string stop_key =
1511      ObjectStoreMetaDataKey::EncodeMaxKey(database_id);
1512
1513  DCHECK(object_stores->empty());
1514
1515  scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
1516  leveldb::Status s = it->Seek(start_key);
1517  while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) {
1518    StringPiece slice(it->Key());
1519    ObjectStoreMetaDataKey meta_data_key;
1520    bool ok =
1521        ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty();
1522    DCHECK(ok);
1523    if (!ok || meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) {
1524      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1525      // Possible stale metadata, but don't fail the load.
1526      s = it->Next();
1527      if (!s.ok())
1528        break;
1529      continue;
1530    }
1531
1532    int64 object_store_id = meta_data_key.ObjectStoreId();
1533
1534    // TODO(jsbell): Do this by direct key lookup rather than iteration, to
1535    // simplify.
1536    base::string16 object_store_name;
1537    {
1538      StringPiece slice(it->Value());
1539      if (!DecodeString(&slice, &object_store_name) || !slice.empty())
1540        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1541    }
1542
1543    s = it->Next();
1544    if (!s.ok())
1545      break;
1546    if (!CheckObjectStoreAndMetaDataType(it.get(),
1547                                         stop_key,
1548                                         object_store_id,
1549                                         ObjectStoreMetaDataKey::KEY_PATH)) {
1550      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1551      break;
1552    }
1553    IndexedDBKeyPath key_path;
1554    {
1555      StringPiece slice(it->Value());
1556      if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty())
1557        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1558    }
1559
1560    s = it->Next();
1561    if (!s.ok())
1562      break;
1563    if (!CheckObjectStoreAndMetaDataType(
1564             it.get(),
1565             stop_key,
1566             object_store_id,
1567             ObjectStoreMetaDataKey::AUTO_INCREMENT)) {
1568      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1569      break;
1570    }
1571    bool auto_increment;
1572    {
1573      StringPiece slice(it->Value());
1574      if (!DecodeBool(&slice, &auto_increment) || !slice.empty())
1575        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1576    }
1577
1578    s = it->Next();  // Is evictable.
1579    if (!s.ok())
1580      break;
1581    if (!CheckObjectStoreAndMetaDataType(it.get(),
1582                                         stop_key,
1583                                         object_store_id,
1584                                         ObjectStoreMetaDataKey::EVICTABLE)) {
1585      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1586      break;
1587    }
1588
1589    s = it->Next();  // Last version.
1590    if (!s.ok())
1591      break;
1592    if (!CheckObjectStoreAndMetaDataType(
1593             it.get(),
1594             stop_key,
1595             object_store_id,
1596             ObjectStoreMetaDataKey::LAST_VERSION)) {
1597      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1598      break;
1599    }
1600
1601    s = it->Next();  // Maximum index id allocated.
1602    if (!s.ok())
1603      break;
1604    if (!CheckObjectStoreAndMetaDataType(
1605             it.get(),
1606             stop_key,
1607             object_store_id,
1608             ObjectStoreMetaDataKey::MAX_INDEX_ID)) {
1609      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1610      break;
1611    }
1612    int64 max_index_id;
1613    {
1614      StringPiece slice(it->Value());
1615      if (!DecodeInt(&slice, &max_index_id) || !slice.empty())
1616        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1617    }
1618
1619    s = it->Next();  // [optional] has key path (is not null)
1620    if (!s.ok())
1621      break;
1622    if (CheckObjectStoreAndMetaDataType(it.get(),
1623                                        stop_key,
1624                                        object_store_id,
1625                                        ObjectStoreMetaDataKey::HAS_KEY_PATH)) {
1626      bool has_key_path;
1627      {
1628        StringPiece slice(it->Value());
1629        if (!DecodeBool(&slice, &has_key_path))
1630          INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1631      }
1632      // This check accounts for two layers of legacy coding:
1633      // (1) Initially, has_key_path was added to distinguish null vs. string.
1634      // (2) Later, null vs. string vs. array was stored in the key_path itself.
1635      // So this check is only relevant for string-type key_paths.
1636      if (!has_key_path &&
1637          (key_path.type() == blink::WebIDBKeyPathTypeString &&
1638           !key_path.string().empty())) {
1639        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1640        break;
1641      }
1642      if (!has_key_path)
1643        key_path = IndexedDBKeyPath();
1644      s = it->Next();
1645      if (!s.ok())
1646        break;
1647    }
1648
1649    int64 key_generator_current_number = -1;
1650    if (CheckObjectStoreAndMetaDataType(
1651            it.get(),
1652            stop_key,
1653            object_store_id,
1654            ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) {
1655      StringPiece slice(it->Value());
1656      if (!DecodeInt(&slice, &key_generator_current_number) || !slice.empty())
1657        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
1658
1659      // TODO(jsbell): Return key_generator_current_number, cache in
1660      // object store, and write lazily to backing store.  For now,
1661      // just assert that if it was written it was valid.
1662      DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber);
1663      s = it->Next();
1664      if (!s.ok())
1665        break;
1666    }
1667
1668    IndexedDBObjectStoreMetadata metadata(object_store_name,
1669                                          object_store_id,
1670                                          key_path,
1671                                          auto_increment,
1672                                          max_index_id);
1673    s = GetIndexes(database_id, object_store_id, &metadata.indexes);
1674    if (!s.ok())
1675      break;
1676    (*object_stores)[object_store_id] = metadata;
1677  }
1678
1679  if (!s.ok())
1680    INTERNAL_READ_ERROR_UNTESTED(GET_OBJECT_STORES);
1681
1682  return s;
1683}
1684
1685WARN_UNUSED_RESULT static leveldb::Status SetMaxObjectStoreId(
1686    LevelDBTransaction* transaction,
1687    int64 database_id,
1688    int64 object_store_id) {
1689  const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode(
1690      database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
1691  int64 max_object_store_id = -1;
1692  leveldb::Status s = GetMaxObjectStoreId(
1693      transaction, max_object_store_id_key, &max_object_store_id);
1694  if (!s.ok()) {
1695    INTERNAL_READ_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID);
1696    return s;
1697  }
1698
1699  if (object_store_id <= max_object_store_id) {
1700    INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID);
1701    return InternalInconsistencyStatus();
1702  }
1703  PutInt(transaction, max_object_store_id_key, object_store_id);
1704  return s;
1705}
1706
1707void IndexedDBBackingStore::Compact() { db_->CompactAll(); }
1708
1709leveldb::Status IndexedDBBackingStore::CreateObjectStore(
1710    IndexedDBBackingStore::Transaction* transaction,
1711    int64 database_id,
1712    int64 object_store_id,
1713    const base::string16& name,
1714    const IndexedDBKeyPath& key_path,
1715    bool auto_increment) {
1716  IDB_TRACE("IndexedDBBackingStore::CreateObjectStore");
1717  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1718    return InvalidDBKeyStatus();
1719  LevelDBTransaction* leveldb_transaction = transaction->transaction();
1720  leveldb::Status s =
1721      SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id);
1722  if (!s.ok())
1723    return s;
1724
1725  const std::string name_key = ObjectStoreMetaDataKey::Encode(
1726      database_id, object_store_id, ObjectStoreMetaDataKey::NAME);
1727  const std::string key_path_key = ObjectStoreMetaDataKey::Encode(
1728      database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH);
1729  const std::string auto_increment_key = ObjectStoreMetaDataKey::Encode(
1730      database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT);
1731  const std::string evictable_key = ObjectStoreMetaDataKey::Encode(
1732      database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE);
1733  const std::string last_version_key = ObjectStoreMetaDataKey::Encode(
1734      database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
1735  const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode(
1736      database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
1737  const std::string has_key_path_key = ObjectStoreMetaDataKey::Encode(
1738      database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH);
1739  const std::string key_generator_current_number_key =
1740      ObjectStoreMetaDataKey::Encode(
1741          database_id,
1742          object_store_id,
1743          ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
1744  const std::string names_key = ObjectStoreNamesKey::Encode(database_id, name);
1745
1746  PutString(leveldb_transaction, name_key, name);
1747  PutIDBKeyPath(leveldb_transaction, key_path_key, key_path);
1748  PutInt(leveldb_transaction, auto_increment_key, auto_increment);
1749  PutInt(leveldb_transaction, evictable_key, false);
1750  PutInt(leveldb_transaction, last_version_key, 1);
1751  PutInt(leveldb_transaction, max_index_id_key, kMinimumIndexId);
1752  PutBool(leveldb_transaction, has_key_path_key, !key_path.IsNull());
1753  PutInt(leveldb_transaction,
1754         key_generator_current_number_key,
1755         kKeyGeneratorInitialNumber);
1756  PutInt(leveldb_transaction, names_key, object_store_id);
1757  return s;
1758}
1759
1760leveldb::Status IndexedDBBackingStore::DeleteObjectStore(
1761    IndexedDBBackingStore::Transaction* transaction,
1762    int64 database_id,
1763    int64 object_store_id) {
1764  IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore");
1765  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1766    return InvalidDBKeyStatus();
1767  LevelDBTransaction* leveldb_transaction = transaction->transaction();
1768
1769  base::string16 object_store_name;
1770  bool found = false;
1771  leveldb::Status s =
1772      GetString(leveldb_transaction,
1773                ObjectStoreMetaDataKey::Encode(
1774                    database_id, object_store_id, ObjectStoreMetaDataKey::NAME),
1775                &object_store_name,
1776                &found);
1777  if (!s.ok()) {
1778    INTERNAL_READ_ERROR_UNTESTED(DELETE_OBJECT_STORE);
1779    return s;
1780  }
1781  if (!found) {
1782    INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE);
1783    return InternalInconsistencyStatus();
1784  }
1785
1786  s = DeleteBlobsInObjectStore(transaction, database_id, object_store_id);
1787  if (!s.ok()) {
1788    INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE);
1789    return s;
1790  }
1791
1792  s = DeleteRangeBasic(
1793      leveldb_transaction,
1794      ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0),
1795      ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id),
1796      true);
1797
1798  if (s.ok()) {
1799    leveldb_transaction->Remove(
1800        ObjectStoreNamesKey::Encode(database_id, object_store_name));
1801
1802    s = DeleteRangeBasic(
1803        leveldb_transaction,
1804        IndexFreeListKey::Encode(database_id, object_store_id, 0),
1805        IndexFreeListKey::EncodeMaxKey(database_id, object_store_id),
1806        true);
1807  }
1808
1809  if (s.ok()) {
1810    s = DeleteRangeBasic(
1811        leveldb_transaction,
1812        IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0),
1813        IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id),
1814        true);
1815  }
1816
1817  if (!s.ok()) {
1818    INTERNAL_WRITE_ERROR_UNTESTED(DELETE_OBJECT_STORE);
1819    return s;
1820  }
1821
1822  return ClearObjectStore(transaction, database_id, object_store_id);
1823}
1824
1825leveldb::Status IndexedDBBackingStore::GetRecord(
1826    IndexedDBBackingStore::Transaction* transaction,
1827    int64 database_id,
1828    int64 object_store_id,
1829    const IndexedDBKey& key,
1830    IndexedDBValue* record) {
1831  IDB_TRACE("IndexedDBBackingStore::GetRecord");
1832  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1833    return InvalidDBKeyStatus();
1834  LevelDBTransaction* leveldb_transaction = transaction->transaction();
1835
1836  const std::string leveldb_key =
1837      ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1838  std::string data;
1839
1840  record->clear();
1841
1842  bool found = false;
1843  leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
1844  if (!s.ok()) {
1845    INTERNAL_READ_ERROR(GET_RECORD);
1846    return s;
1847  }
1848  if (!found)
1849    return s;
1850  if (data.empty()) {
1851    INTERNAL_READ_ERROR_UNTESTED(GET_RECORD);
1852    return leveldb::Status::NotFound("Record contained no data");
1853  }
1854
1855  int64 version;
1856  StringPiece slice(data);
1857  if (!DecodeVarInt(&slice, &version)) {
1858    INTERNAL_READ_ERROR_UNTESTED(GET_RECORD);
1859    return InternalInconsistencyStatus();
1860  }
1861
1862  record->bits = slice.as_string();
1863  return transaction->GetBlobInfoForRecord(database_id, leveldb_key, record);
1864}
1865
1866WARN_UNUSED_RESULT static leveldb::Status GetNewVersionNumber(
1867    LevelDBTransaction* transaction,
1868    int64 database_id,
1869    int64 object_store_id,
1870    int64* new_version_number) {
1871  const std::string last_version_key = ObjectStoreMetaDataKey::Encode(
1872      database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
1873
1874  *new_version_number = -1;
1875  int64 last_version = -1;
1876  bool found = false;
1877  leveldb::Status s =
1878      GetInt(transaction, last_version_key, &last_version, &found);
1879  if (!s.ok()) {
1880    INTERNAL_READ_ERROR_UNTESTED(GET_NEW_VERSION_NUMBER);
1881    return s;
1882  }
1883  if (!found)
1884    last_version = 0;
1885
1886  DCHECK_GE(last_version, 0);
1887
1888  int64 version = last_version + 1;
1889  PutInt(transaction, last_version_key, version);
1890
1891  // TODO(jsbell): Think about how we want to handle the overflow scenario.
1892  DCHECK(version > last_version);
1893
1894  *new_version_number = version;
1895  return s;
1896}
1897
1898leveldb::Status IndexedDBBackingStore::PutRecord(
1899    IndexedDBBackingStore::Transaction* transaction,
1900    int64 database_id,
1901    int64 object_store_id,
1902    const IndexedDBKey& key,
1903    IndexedDBValue* value,
1904    ScopedVector<storage::BlobDataHandle>* handles,
1905    RecordIdentifier* record_identifier) {
1906  IDB_TRACE("IndexedDBBackingStore::PutRecord");
1907  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1908    return InvalidDBKeyStatus();
1909  DCHECK(key.IsValid());
1910
1911  LevelDBTransaction* leveldb_transaction = transaction->transaction();
1912  int64 version = -1;
1913  leveldb::Status s = GetNewVersionNumber(
1914      leveldb_transaction, database_id, object_store_id, &version);
1915  if (!s.ok())
1916    return s;
1917  DCHECK_GE(version, 0);
1918  const std::string object_store_data_key =
1919      ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1920
1921  std::string v;
1922  EncodeVarInt(version, &v);
1923  v.append(value->bits);
1924
1925  leveldb_transaction->Put(object_store_data_key, &v);
1926  s = transaction->PutBlobInfoIfNeeded(database_id,
1927                                       object_store_id,
1928                                       object_store_data_key,
1929                                       &value->blob_info,
1930                                       handles);
1931  if (!s.ok())
1932    return s;
1933  DCHECK(!handles->size());
1934
1935  const std::string exists_entry_key =
1936      ExistsEntryKey::Encode(database_id, object_store_id, key);
1937  std::string version_encoded;
1938  EncodeInt(version, &version_encoded);
1939  leveldb_transaction->Put(exists_entry_key, &version_encoded);
1940
1941  std::string key_encoded;
1942  EncodeIDBKey(key, &key_encoded);
1943  record_identifier->Reset(key_encoded, version);
1944  return s;
1945}
1946
1947leveldb::Status IndexedDBBackingStore::ClearObjectStore(
1948    IndexedDBBackingStore::Transaction* transaction,
1949    int64 database_id,
1950    int64 object_store_id) {
1951  IDB_TRACE("IndexedDBBackingStore::ClearObjectStore");
1952  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1953    return InvalidDBKeyStatus();
1954  const std::string start_key =
1955      KeyPrefix(database_id, object_store_id).Encode();
1956  const std::string stop_key =
1957      KeyPrefix(database_id, object_store_id + 1).Encode();
1958
1959  leveldb::Status s =
1960      DeleteRangeBasic(transaction->transaction(), start_key, stop_key, true);
1961  if (!s.ok()) {
1962    INTERNAL_WRITE_ERROR(CLEAR_OBJECT_STORE);
1963    return s;
1964  }
1965  return DeleteBlobsInObjectStore(transaction, database_id, object_store_id);
1966}
1967
1968leveldb::Status IndexedDBBackingStore::DeleteRecord(
1969    IndexedDBBackingStore::Transaction* transaction,
1970    int64 database_id,
1971    int64 object_store_id,
1972    const RecordIdentifier& record_identifier) {
1973  IDB_TRACE("IndexedDBBackingStore::DeleteRecord");
1974  if (!KeyPrefix::ValidIds(database_id, object_store_id))
1975    return InvalidDBKeyStatus();
1976  LevelDBTransaction* leveldb_transaction = transaction->transaction();
1977
1978  const std::string object_store_data_key = ObjectStoreDataKey::Encode(
1979      database_id, object_store_id, record_identifier.primary_key());
1980  leveldb_transaction->Remove(object_store_data_key);
1981  leveldb::Status s = transaction->PutBlobInfoIfNeeded(
1982      database_id, object_store_id, object_store_data_key, NULL, NULL);
1983  if (!s.ok())
1984    return s;
1985
1986  const std::string exists_entry_key = ExistsEntryKey::Encode(
1987      database_id, object_store_id, record_identifier.primary_key());
1988  leveldb_transaction->Remove(exists_entry_key);
1989  return leveldb::Status::OK();
1990}
1991
1992leveldb::Status IndexedDBBackingStore::DeleteRange(
1993    IndexedDBBackingStore::Transaction* transaction,
1994    int64 database_id,
1995    int64 object_store_id,
1996    const IndexedDBKeyRange& key_range) {
1997  leveldb::Status s;
1998  scoped_ptr<IndexedDBBackingStore::Cursor> start_cursor =
1999      OpenObjectStoreCursor(transaction,
2000                            database_id,
2001                            object_store_id,
2002                            key_range,
2003                            blink::WebIDBCursorDirectionNext,
2004                            &s);
2005  if (!s.ok())
2006    return s;
2007  if (!start_cursor)
2008    return leveldb::Status::OK();  // Empty range == delete success.
2009
2010  scoped_ptr<IndexedDBBackingStore::Cursor> end_cursor =
2011      OpenObjectStoreCursor(transaction,
2012                            database_id,
2013                            object_store_id,
2014                            key_range,
2015                            blink::WebIDBCursorDirectionPrev,
2016                            &s);
2017
2018  if (!s.ok())
2019    return s;
2020  if (!end_cursor)
2021    return leveldb::Status::OK();  // Empty range == delete success.
2022
2023  BlobEntryKey start_blob_key, end_blob_key;
2024
2025  std::string start_key = ObjectStoreDataKey::Encode(
2026      database_id, object_store_id, start_cursor->key());
2027  base::StringPiece start_key_piece(start_key);
2028  if (!BlobEntryKey::FromObjectStoreDataKey(&start_key_piece, &start_blob_key))
2029    return InternalInconsistencyStatus();
2030  std::string stop_key = ObjectStoreDataKey::Encode(
2031      database_id, object_store_id, end_cursor->key());
2032  base::StringPiece stop_key_piece(stop_key);
2033  if (!BlobEntryKey::FromObjectStoreDataKey(&stop_key_piece, &end_blob_key))
2034    return InternalInconsistencyStatus();
2035
2036  s = DeleteBlobsInRange(transaction,
2037                         database_id,
2038                         object_store_id,
2039                         start_blob_key.Encode(),
2040                         end_blob_key.Encode(),
2041                         false);
2042  if (!s.ok())
2043    return s;
2044  s = DeleteRangeBasic(transaction->transaction(), start_key, stop_key, false);
2045  if (!s.ok())
2046    return s;
2047  start_key =
2048      ExistsEntryKey::Encode(database_id, object_store_id, start_cursor->key());
2049  stop_key =
2050      ExistsEntryKey::Encode(database_id, object_store_id, end_cursor->key());
2051  return DeleteRangeBasic(
2052      transaction->transaction(), start_key, stop_key, false);
2053}
2054
2055leveldb::Status IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
2056    IndexedDBBackingStore::Transaction* transaction,
2057    int64 database_id,
2058    int64 object_store_id,
2059    int64* key_generator_current_number) {
2060  if (!KeyPrefix::ValidIds(database_id, object_store_id))
2061    return InvalidDBKeyStatus();
2062  LevelDBTransaction* leveldb_transaction = transaction->transaction();
2063
2064  const std::string key_generator_current_number_key =
2065      ObjectStoreMetaDataKey::Encode(
2066          database_id,
2067          object_store_id,
2068          ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
2069
2070  *key_generator_current_number = -1;
2071  std::string data;
2072
2073  bool found = false;
2074  leveldb::Status s =
2075      leveldb_transaction->Get(key_generator_current_number_key, &data, &found);
2076  if (!s.ok()) {
2077    INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
2078    return s;
2079  }
2080  if (found && !data.empty()) {
2081    StringPiece slice(data);
2082    if (!DecodeInt(&slice, key_generator_current_number) || !slice.empty()) {
2083      INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
2084      return InternalInconsistencyStatus();
2085    }
2086    return s;
2087  }
2088
2089  // Previously, the key generator state was not stored explicitly
2090  // but derived from the maximum numeric key present in existing
2091  // data. This violates the spec as the data may be cleared but the
2092  // key generator state must be preserved.
2093  // TODO(jsbell): Fix this for all stores on database open?
2094  const std::string start_key =
2095      ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
2096  const std::string stop_key =
2097      ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
2098
2099  scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
2100  int64 max_numeric_key = 0;
2101
2102  for (s = it->Seek(start_key);
2103       s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
2104       s = it->Next()) {
2105    StringPiece slice(it->Key());
2106    ObjectStoreDataKey data_key;
2107    if (!ObjectStoreDataKey::Decode(&slice, &data_key) || !slice.empty()) {
2108      INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
2109      return InternalInconsistencyStatus();
2110    }
2111    scoped_ptr<IndexedDBKey> user_key = data_key.user_key();
2112    if (user_key->type() == blink::WebIDBKeyTypeNumber) {
2113      int64 n = static_cast<int64>(user_key->number());
2114      if (n > max_numeric_key)
2115        max_numeric_key = n;
2116    }
2117  }
2118
2119  if (s.ok())
2120    *key_generator_current_number = max_numeric_key + 1;
2121  else
2122    INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
2123
2124  return s;
2125}
2126
2127leveldb::Status IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
2128    IndexedDBBackingStore::Transaction* transaction,
2129    int64 database_id,
2130    int64 object_store_id,
2131    int64 new_number,
2132    bool check_current) {
2133  if (!KeyPrefix::ValidIds(database_id, object_store_id))
2134    return InvalidDBKeyStatus();
2135
2136  if (check_current) {
2137    int64 current_number;
2138    leveldb::Status s = GetKeyGeneratorCurrentNumber(
2139        transaction, database_id, object_store_id, &current_number);
2140    if (!s.ok())
2141      return s;
2142    if (new_number <= current_number)
2143      return s;
2144  }
2145
2146  const std::string key_generator_current_number_key =
2147      ObjectStoreMetaDataKey::Encode(
2148          database_id,
2149          object_store_id,
2150          ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
2151  PutInt(
2152      transaction->transaction(), key_generator_current_number_key, new_number);
2153  return leveldb::Status::OK();
2154}
2155
2156leveldb::Status IndexedDBBackingStore::KeyExistsInObjectStore(
2157    IndexedDBBackingStore::Transaction* transaction,
2158    int64 database_id,
2159    int64 object_store_id,
2160    const IndexedDBKey& key,
2161    RecordIdentifier* found_record_identifier,
2162    bool* found) {
2163  IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore");
2164  if (!KeyPrefix::ValidIds(database_id, object_store_id))
2165    return InvalidDBKeyStatus();
2166  *found = false;
2167  const std::string leveldb_key =
2168      ObjectStoreDataKey::Encode(database_id, object_store_id, key);
2169  std::string data;
2170
2171  leveldb::Status s =
2172      transaction->transaction()->Get(leveldb_key, &data, found);
2173  if (!s.ok()) {
2174    INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE);
2175    return s;
2176  }
2177  if (!*found)
2178    return leveldb::Status::OK();
2179  if (!data.size()) {
2180    INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE);
2181    return InternalInconsistencyStatus();
2182  }
2183
2184  int64 version;
2185  StringPiece slice(data);
2186  if (!DecodeVarInt(&slice, &version))
2187    return InternalInconsistencyStatus();
2188
2189  std::string encoded_key;
2190  EncodeIDBKey(key, &encoded_key);
2191  found_record_identifier->Reset(encoded_key, version);
2192  return s;
2193}
2194
2195class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
2196    : public IndexedDBBackingStore::Transaction::ChainedBlobWriter {
2197 public:
2198  typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec
2199      WriteDescriptorVec;
2200  ChainedBlobWriterImpl(
2201      int64 database_id,
2202      IndexedDBBackingStore* backing_store,
2203      WriteDescriptorVec* blobs,
2204      scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
2205      : waiting_for_callback_(false),
2206        database_id_(database_id),
2207        backing_store_(backing_store),
2208        callback_(callback),
2209        aborted_(false) {
2210    blobs_.swap(*blobs);
2211    iter_ = blobs_.begin();
2212    backing_store->task_runner()->PostTask(
2213        FROM_HERE, base::Bind(&ChainedBlobWriterImpl::WriteNextFile, this));
2214  }
2215
2216  virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE {
2217    delegate_.reset(delegate.release());
2218  }
2219
2220  virtual void ReportWriteCompletion(bool succeeded,
2221                                     int64 bytes_written) OVERRIDE {
2222    DCHECK(waiting_for_callback_);
2223    DCHECK(!succeeded || bytes_written >= 0);
2224    waiting_for_callback_ = false;
2225    if (delegate_.get())  // Only present for Blob, not File.
2226      content::BrowserThread::DeleteSoon(
2227          content::BrowserThread::IO, FROM_HERE, delegate_.release());
2228    if (aborted_) {
2229      self_ref_ = NULL;
2230      return;
2231    }
2232    if (iter_->size() != -1 && iter_->size() != bytes_written)
2233      succeeded = false;
2234    if (succeeded) {
2235      ++iter_;
2236      WriteNextFile();
2237    } else {
2238      callback_->Run(false);
2239    }
2240  }
2241
2242  virtual void Abort() OVERRIDE {
2243    if (!waiting_for_callback_)
2244      return;
2245    self_ref_ = this;
2246    aborted_ = true;
2247  }
2248
2249 private:
2250  virtual ~ChainedBlobWriterImpl() {}
2251
2252  void WriteNextFile() {
2253    DCHECK(!waiting_for_callback_);
2254    DCHECK(!aborted_);
2255    if (iter_ == blobs_.end()) {
2256      DCHECK(!self_ref_.get());
2257      callback_->Run(true);
2258      return;
2259    } else {
2260      if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) {
2261        callback_->Run(false);
2262        return;
2263      }
2264      waiting_for_callback_ = true;
2265    }
2266  }
2267
2268  bool waiting_for_callback_;
2269  scoped_refptr<ChainedBlobWriterImpl> self_ref_;
2270  WriteDescriptorVec blobs_;
2271  WriteDescriptorVec::const_iterator iter_;
2272  int64 database_id_;
2273  IndexedDBBackingStore* backing_store_;
2274  scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_;
2275  scoped_ptr<FileWriterDelegate> delegate_;
2276  bool aborted_;
2277
2278  DISALLOW_COPY_AND_ASSIGN(ChainedBlobWriterImpl);
2279};
2280
2281class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
2282                          public base::RefCountedThreadSafe<LocalWriteClosure> {
2283 public:
2284  LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter*
2285                        chained_blob_writer,
2286                    base::SequencedTaskRunner* task_runner)
2287      : chained_blob_writer_(chained_blob_writer),
2288        task_runner_(task_runner),
2289        bytes_written_(0) {}
2290
2291  void Run(base::File::Error rv,
2292           int64 bytes,
2293           FileWriterDelegate::WriteProgressStatus write_status) {
2294    DCHECK_GE(bytes, 0);
2295    bytes_written_ += bytes;
2296    if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING)
2297      return;  // We don't care about progress events.
2298    if (rv == base::File::FILE_OK) {
2299      DCHECK_EQ(write_status, FileWriterDelegate::SUCCESS_COMPLETED);
2300    } else {
2301      DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED ||
2302             write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED);
2303    }
2304    task_runner_->PostTask(
2305        FROM_HERE,
2306        base::Bind(&IndexedDBBackingStore::Transaction::ChainedBlobWriter::
2307                       ReportWriteCompletion,
2308                   chained_blob_writer_,
2309                   write_status == FileWriterDelegate::SUCCESS_COMPLETED,
2310                   bytes_written_));
2311  }
2312
2313  void writeBlobToFileOnIOThread(const FilePath& file_path,
2314                                 const GURL& blob_url,
2315                                 net::URLRequestContext* request_context) {
2316    DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
2317    scoped_ptr<storage::FileStreamWriter> writer(
2318        storage::FileStreamWriter::CreateForLocalFile(
2319            task_runner_.get(),
2320            file_path,
2321            0,
2322            storage::FileStreamWriter::CREATE_NEW_FILE));
2323    scoped_ptr<FileWriterDelegate> delegate(
2324        new FileWriterDelegate(writer.Pass(),
2325                               FileWriterDelegate::FLUSH_ON_COMPLETION));
2326
2327    DCHECK(blob_url.is_valid());
2328    scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest(
2329        blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL));
2330
2331    delegate->Start(blob_request.Pass(),
2332                    base::Bind(&LocalWriteClosure::Run, this));
2333    chained_blob_writer_->set_delegate(delegate.Pass());
2334  }
2335
2336 private:
2337  virtual ~LocalWriteClosure() {
2338    // Make sure the last reference to a ChainedBlobWriter is released (and
2339    // deleted) on the IDB thread since it owns a transaction which has thread
2340    // affinity.
2341    IndexedDBBackingStore::Transaction::ChainedBlobWriter* raw_tmp =
2342        chained_blob_writer_.get();
2343    raw_tmp->AddRef();
2344    chained_blob_writer_ = NULL;
2345    task_runner_->ReleaseSoon(FROM_HERE, raw_tmp);
2346  }
2347  friend class base::RefCountedThreadSafe<LocalWriteClosure>;
2348
2349  scoped_refptr<IndexedDBBackingStore::Transaction::ChainedBlobWriter>
2350      chained_blob_writer_;
2351  scoped_refptr<base::SequencedTaskRunner> task_runner_;
2352  int64 bytes_written_;
2353
2354  DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure);
2355};
2356
2357bool IndexedDBBackingStore::WriteBlobFile(
2358    int64 database_id,
2359    const Transaction::WriteDescriptor& descriptor,
2360    Transaction::ChainedBlobWriter* chained_blob_writer) {
2361
2362  if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key()))
2363    return false;
2364
2365  FilePath path = GetBlobFileName(database_id, descriptor.key());
2366
2367  if (descriptor.is_file()) {
2368    DCHECK(!descriptor.file_path().empty());
2369    if (!base::CopyFile(descriptor.file_path(), path))
2370      return false;
2371
2372    base::File::Info info;
2373    if (base::GetFileInfo(descriptor.file_path(), &info)) {
2374      if (descriptor.size() != -1) {
2375        if (descriptor.size() != info.size)
2376          return false;
2377        // The round-trip can be lossy; round to nearest millisecond.
2378        int64 delta = (descriptor.last_modified() -
2379            info.last_modified).InMilliseconds();
2380        if (std::abs(delta) > 1)
2381          return false;
2382      }
2383      if (!base::TouchFile(path, info.last_accessed, info.last_modified)) {
2384        // TODO(ericu): Complain quietly; timestamp's probably not vital.
2385      }
2386    } else {
2387      // TODO(ericu): Complain quietly; timestamp's probably not vital.
2388    }
2389
2390    task_runner_->PostTask(
2391        FROM_HERE,
2392        base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
2393                   chained_blob_writer,
2394                   true,
2395                   info.size));
2396  } else {
2397    DCHECK(descriptor.url().is_valid());
2398    scoped_refptr<LocalWriteClosure> write_closure(
2399        new LocalWriteClosure(chained_blob_writer, task_runner_.get()));
2400    content::BrowserThread::PostTask(
2401        content::BrowserThread::IO,
2402        FROM_HERE,
2403        base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread,
2404                   write_closure.get(),
2405                   path,
2406                   descriptor.url(),
2407                   request_context_));
2408  }
2409  return true;
2410}
2411
2412void IndexedDBBackingStore::ReportBlobUnused(int64 database_id,
2413                                             int64 blob_key) {
2414  DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
2415  bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey;
2416  DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key));
2417  scoped_refptr<LevelDBTransaction> transaction =
2418      IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
2419
2420  std::string live_blob_key = LiveBlobJournalKey::Encode();
2421  BlobJournalType live_blob_journal;
2422  if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal)
2423           .ok())
2424    return;
2425  DCHECK(live_blob_journal.size());
2426
2427  std::string primary_key = BlobJournalKey::Encode();
2428  BlobJournalType primary_journal;
2429  if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok())
2430    return;
2431
2432  // There are several cases to handle.  If blob_key is kAllBlobsKey, we want to
2433  // remove all entries with database_id from the live_blob journal and add only
2434  // kAllBlobsKey to the primary journal.  Otherwise if IsValidBlobKey(blob_key)
2435  // and we hit kAllBlobsKey for the right database_id in the journal, we leave
2436  // the kAllBlobsKey entry in the live_blob journal but add the specific blob
2437  // to the primary.  Otherwise if IsValidBlobKey(blob_key) and we find a
2438  // matching (database_id, blob_key) tuple, we should move it to the primary
2439  // journal.
2440  BlobJournalType new_live_blob_journal;
2441  for (BlobJournalType::iterator journal_iter = live_blob_journal.begin();
2442       journal_iter != live_blob_journal.end();
2443       ++journal_iter) {
2444    int64 current_database_id = journal_iter->first;
2445    int64 current_blob_key = journal_iter->second;
2446    bool current_all_blobs =
2447        current_blob_key == DatabaseMetaDataKey::kAllBlobsKey;
2448    DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) ||
2449           current_all_blobs);
2450    if (current_database_id == database_id &&
2451        (all_blobs || current_all_blobs || blob_key == current_blob_key)) {
2452      if (!all_blobs) {
2453        primary_journal.push_back(
2454            std::make_pair(database_id, current_blob_key));
2455        if (current_all_blobs)
2456          new_live_blob_journal.push_back(*journal_iter);
2457        new_live_blob_journal.insert(new_live_blob_journal.end(),
2458                                     ++journal_iter,
2459                                     live_blob_journal.end());  // All the rest.
2460        break;
2461      }
2462    } else {
2463      new_live_blob_journal.push_back(*journal_iter);
2464    }
2465  }
2466  if (all_blobs) {
2467    primary_journal.push_back(
2468        std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
2469  }
2470  UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal);
2471  UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal);
2472  transaction->Commit();
2473  // We could just do the deletions/cleaning here, but if there are a lot of
2474  // blobs about to be garbage collected, it'd be better to wait and do them all
2475  // at once.
2476  StartJournalCleaningTimer();
2477}
2478
2479// The this reference is a raw pointer that's declared Unretained inside the
2480// timer code, so this won't confuse IndexedDBFactory's check for
2481// HasLastBackingStoreReference.  It's safe because if the backing store is
2482// deleted, the timer will automatically be canceled on destruction.
2483void IndexedDBBackingStore::StartJournalCleaningTimer() {
2484  journal_cleaning_timer_.Start(
2485      FROM_HERE,
2486      base::TimeDelta::FromSeconds(5),
2487      this,
2488      &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn);
2489}
2490
2491// This assumes a file path of dbId/second-to-LSB-of-counter/counter.
2492FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) {
2493  return GetBlobFileNameForKey(blob_path_, database_id, key);
2494}
2495
2496static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
2497                                     const std::string& stop_key,
2498                                     int64 index_id,
2499                                     unsigned char meta_data_type) {
2500  if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0)
2501    return false;
2502
2503  StringPiece slice(it->Key());
2504  IndexMetaDataKey meta_data_key;
2505  bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
2506  DCHECK(ok);
2507  if (meta_data_key.IndexId() != index_id)
2508    return false;
2509  if (meta_data_key.meta_data_type() != meta_data_type)
2510    return false;
2511  return true;
2512}
2513
2514// TODO(jsbell): This should do some error handling rather than plowing ahead
2515// when bad data is encountered.
2516leveldb::Status IndexedDBBackingStore::GetIndexes(
2517    int64 database_id,
2518    int64 object_store_id,
2519    IndexedDBObjectStoreMetadata::IndexMap* indexes) {
2520  IDB_TRACE("IndexedDBBackingStore::GetIndexes");
2521  if (!KeyPrefix::ValidIds(database_id, object_store_id))
2522    return InvalidDBKeyStatus();
2523  const std::string start_key =
2524      IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0);
2525  const std::string stop_key =
2526      IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0);
2527
2528  DCHECK(indexes->empty());
2529
2530  scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
2531  leveldb::Status s = it->Seek(start_key);
2532  while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) {
2533    StringPiece slice(it->Key());
2534    IndexMetaDataKey meta_data_key;
2535    bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
2536    DCHECK(ok);
2537    if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) {
2538      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2539      // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
2540      // the load.
2541      s = it->Next();
2542      if (!s.ok())
2543        break;
2544      continue;
2545    }
2546
2547    // TODO(jsbell): Do this by direct key lookup rather than iteration, to
2548    // simplify.
2549    int64 index_id = meta_data_key.IndexId();
2550    base::string16 index_name;
2551    {
2552      StringPiece slice(it->Value());
2553      if (!DecodeString(&slice, &index_name) || !slice.empty())
2554        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2555    }
2556
2557    s = it->Next();  // unique flag
2558    if (!s.ok())
2559      break;
2560    if (!CheckIndexAndMetaDataKey(
2561             it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) {
2562      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2563      break;
2564    }
2565    bool index_unique;
2566    {
2567      StringPiece slice(it->Value());
2568      if (!DecodeBool(&slice, &index_unique) || !slice.empty())
2569        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2570    }
2571
2572    s = it->Next();  // key_path
2573    if (!s.ok())
2574      break;
2575    if (!CheckIndexAndMetaDataKey(
2576             it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) {
2577      INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2578      break;
2579    }
2580    IndexedDBKeyPath key_path;
2581    {
2582      StringPiece slice(it->Value());
2583      if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty())
2584        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2585    }
2586
2587    s = it->Next();  // [optional] multi_entry flag
2588    if (!s.ok())
2589      break;
2590    bool index_multi_entry = false;
2591    if (CheckIndexAndMetaDataKey(
2592            it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) {
2593      StringPiece slice(it->Value());
2594      if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty())
2595        INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2596
2597      s = it->Next();
2598      if (!s.ok())
2599        break;
2600    }
2601
2602    (*indexes)[index_id] = IndexedDBIndexMetadata(
2603        index_name, index_id, key_path, index_unique, index_multi_entry);
2604  }
2605
2606  if (!s.ok())
2607    INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES);
2608
2609  return s;
2610}
2611
2612bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) {
2613  FilePath fileName = GetBlobFileName(database_id, key);
2614  return base::DeleteFile(fileName, false);
2615}
2616
2617bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) {
2618  FilePath dirName = GetBlobDirectoryName(blob_path_, database_id);
2619  return base::DeleteFile(dirName, true);
2620}
2621
2622leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
2623    const std::string& level_db_key) {
2624  scoped_refptr<LevelDBTransaction> journal_transaction =
2625      IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
2626  BlobJournalType journal;
2627  leveldb::Status s =
2628      GetBlobJournal(level_db_key, journal_transaction.get(), &journal);
2629  if (!s.ok())
2630    return s;
2631  if (!journal.size())
2632    return leveldb::Status::OK();
2633  BlobJournalType::iterator journal_iter;
2634  for (journal_iter = journal.begin(); journal_iter != journal.end();
2635       ++journal_iter) {
2636    int64 database_id = journal_iter->first;
2637    int64 blob_key = journal_iter->second;
2638    DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
2639    if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
2640      if (!RemoveBlobDirectory(database_id))
2641        return IOErrorStatus();
2642    } else {
2643      DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
2644      if (!RemoveBlobFile(database_id, blob_key))
2645        return IOErrorStatus();
2646    }
2647  }
2648  ClearBlobJournal(journal_transaction.get(), level_db_key);
2649  return journal_transaction->Commit();
2650}
2651
2652leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
2653    int64 database_id,
2654    const std::string& object_store_data_key,
2655    IndexedDBValue* value) {
2656  BlobChangeRecord* change_record = NULL;
2657  BlobChangeMap::const_iterator blob_iter =
2658      blob_change_map_.find(object_store_data_key);
2659  if (blob_iter != blob_change_map_.end()) {
2660    change_record = blob_iter->second;
2661  } else {
2662    blob_iter = incognito_blob_map_.find(object_store_data_key);
2663    if (blob_iter != incognito_blob_map_.end())
2664      change_record = blob_iter->second;
2665  }
2666  if (change_record) {
2667    // Either we haven't written the blob to disk yet or we're in incognito
2668    // mode, so we have to send back the one they sent us.  This change record
2669    // includes the original UUID.
2670    value->blob_info = change_record->blob_info();
2671    return leveldb::Status::OK();
2672  }
2673
2674  BlobEntryKey blob_entry_key;
2675  StringPiece leveldb_key_piece(object_store_data_key);
2676  if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
2677                                            &blob_entry_key)) {
2678    NOTREACHED();
2679    return InternalInconsistencyStatus();
2680  }
2681  std::string encoded_key = blob_entry_key.Encode();
2682  bool found;
2683  std::string encoded_value;
2684  leveldb::Status s = transaction()->Get(encoded_key, &encoded_value, &found);
2685  if (!s.ok())
2686    return s;
2687  if (found) {
2688    if (!DecodeBlobData(encoded_value, &value->blob_info)) {
2689      INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD);
2690      return InternalInconsistencyStatus();
2691    }
2692    std::vector<IndexedDBBlobInfo>::iterator iter;
2693    for (iter = value->blob_info.begin(); iter != value->blob_info.end();
2694         ++iter) {
2695      iter->set_file_path(
2696          backing_store_->GetBlobFileName(database_id, iter->key()));
2697      iter->set_mark_used_callback(
2698          backing_store_->active_blob_registry()->GetAddBlobRefCallback(
2699              database_id, iter->key()));
2700      iter->set_release_callback(
2701          backing_store_->active_blob_registry()->GetFinalReleaseCallback(
2702              database_id, iter->key()));
2703      if (iter->is_file()) {
2704        base::File::Info info;
2705        if (base::GetFileInfo(iter->file_path(), &info)) {
2706          // This should always work, but it isn't fatal if it doesn't; it just
2707          // means a potential slow synchronous call from the renderer later.
2708          iter->set_last_modified(info.last_modified);
2709          iter->set_size(info.size);
2710        }
2711      }
2712    }
2713  }
2714  return leveldb::Status::OK();
2715}
2716
2717void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() {
2718  CleanUpBlobJournal(BlobJournalKey::Encode());
2719}
2720
2721WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId(
2722    LevelDBTransaction* transaction,
2723    int64 database_id,
2724    int64 object_store_id,
2725    int64 index_id) {
2726  int64 max_index_id = -1;
2727  const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode(
2728      database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
2729  bool found = false;
2730  leveldb::Status s =
2731      GetInt(transaction, max_index_id_key, &max_index_id, &found);
2732  if (!s.ok()) {
2733    INTERNAL_READ_ERROR_UNTESTED(SET_MAX_INDEX_ID);
2734    return s;
2735  }
2736  if (!found)
2737    max_index_id = kMinimumIndexId;
2738
2739  if (index_id <= max_index_id) {
2740    INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_INDEX_ID);
2741    return InternalInconsistencyStatus();
2742  }
2743
2744  PutInt(transaction, max_index_id_key, index_id);
2745  return s;
2746}
2747
2748leveldb::Status IndexedDBBackingStore::CreateIndex(
2749    IndexedDBBackingStore::Transaction* transaction,
2750    int64 database_id,
2751    int64 object_store_id,
2752    int64 index_id,
2753    const base::string16& name,
2754    const IndexedDBKeyPath& key_path,
2755    bool is_unique,
2756    bool is_multi_entry) {
2757  IDB_TRACE("IndexedDBBackingStore::CreateIndex");
2758  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2759    return InvalidDBKeyStatus();
2760  LevelDBTransaction* leveldb_transaction = transaction->transaction();
2761  leveldb::Status s = SetMaxIndexId(
2762      leveldb_transaction, database_id, object_store_id, index_id);
2763
2764  if (!s.ok())
2765    return s;
2766
2767  const std::string name_key = IndexMetaDataKey::Encode(
2768      database_id, object_store_id, index_id, IndexMetaDataKey::NAME);
2769  const std::string unique_key = IndexMetaDataKey::Encode(
2770      database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE);
2771  const std::string key_path_key = IndexMetaDataKey::Encode(
2772      database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH);
2773  const std::string multi_entry_key = IndexMetaDataKey::Encode(
2774      database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY);
2775
2776  PutString(leveldb_transaction, name_key, name);
2777  PutBool(leveldb_transaction, unique_key, is_unique);
2778  PutIDBKeyPath(leveldb_transaction, key_path_key, key_path);
2779  PutBool(leveldb_transaction, multi_entry_key, is_multi_entry);
2780  return s;
2781}
2782
2783leveldb::Status IndexedDBBackingStore::DeleteIndex(
2784    IndexedDBBackingStore::Transaction* transaction,
2785    int64 database_id,
2786    int64 object_store_id,
2787    int64 index_id) {
2788  IDB_TRACE("IndexedDBBackingStore::DeleteIndex");
2789  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2790    return InvalidDBKeyStatus();
2791  LevelDBTransaction* leveldb_transaction = transaction->transaction();
2792
2793  const std::string index_meta_data_start =
2794      IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0);
2795  const std::string index_meta_data_end =
2796      IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
2797  leveldb::Status s = DeleteRangeBasic(
2798      leveldb_transaction, index_meta_data_start, index_meta_data_end, true);
2799
2800  if (s.ok()) {
2801    const std::string index_data_start =
2802        IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
2803    const std::string index_data_end =
2804        IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
2805    s = DeleteRangeBasic(
2806        leveldb_transaction, index_data_start, index_data_end, true);
2807  }
2808
2809  if (!s.ok())
2810    INTERNAL_WRITE_ERROR_UNTESTED(DELETE_INDEX);
2811
2812  return s;
2813}
2814
2815leveldb::Status IndexedDBBackingStore::PutIndexDataForRecord(
2816    IndexedDBBackingStore::Transaction* transaction,
2817    int64 database_id,
2818    int64 object_store_id,
2819    int64 index_id,
2820    const IndexedDBKey& key,
2821    const RecordIdentifier& record_identifier) {
2822  IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord");
2823  DCHECK(key.IsValid());
2824  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2825    return InvalidDBKeyStatus();
2826
2827  std::string encoded_key;
2828  EncodeIDBKey(key, &encoded_key);
2829
2830  const std::string index_data_key =
2831      IndexDataKey::Encode(database_id,
2832                           object_store_id,
2833                           index_id,
2834                           encoded_key,
2835                           record_identifier.primary_key(),
2836                           0);
2837
2838  std::string data;
2839  EncodeVarInt(record_identifier.version(), &data);
2840  data.append(record_identifier.primary_key());
2841
2842  transaction->transaction()->Put(index_data_key, &data);
2843  return leveldb::Status::OK();
2844}
2845
2846static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
2847                                           const std::string& target,
2848                                           std::string* found_key,
2849                                           leveldb::Status* s) {
2850  scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
2851  *s = it->Seek(target);
2852  if (!s->ok())
2853    return false;
2854
2855  if (!it->IsValid()) {
2856    *s = it->SeekToLast();
2857    if (!s->ok() || !it->IsValid())
2858      return false;
2859  }
2860
2861  while (CompareIndexKeys(it->Key(), target) > 0) {
2862    *s = it->Prev();
2863    if (!s->ok() || !it->IsValid())
2864      return false;
2865  }
2866
2867  do {
2868    *found_key = it->Key().as_string();
2869
2870    // There can be several index keys that compare equal. We want the last one.
2871    *s = it->Next();
2872  } while (s->ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target));
2873
2874  return true;
2875}
2876
2877static leveldb::Status VersionExists(LevelDBTransaction* transaction,
2878                                     int64 database_id,
2879                                     int64 object_store_id,
2880                                     int64 version,
2881                                     const std::string& encoded_primary_key,
2882                                     bool* exists) {
2883  const std::string key =
2884      ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key);
2885  std::string data;
2886
2887  leveldb::Status s = transaction->Get(key, &data, exists);
2888  if (!s.ok()) {
2889    INTERNAL_READ_ERROR_UNTESTED(VERSION_EXISTS);
2890    return s;
2891  }
2892  if (!*exists)
2893    return s;
2894
2895  StringPiece slice(data);
2896  int64 decoded;
2897  if (!DecodeInt(&slice, &decoded) || !slice.empty())
2898    return InternalInconsistencyStatus();
2899  *exists = (decoded == version);
2900  return s;
2901}
2902
2903leveldb::Status IndexedDBBackingStore::FindKeyInIndex(
2904    IndexedDBBackingStore::Transaction* transaction,
2905    int64 database_id,
2906    int64 object_store_id,
2907    int64 index_id,
2908    const IndexedDBKey& key,
2909    std::string* found_encoded_primary_key,
2910    bool* found) {
2911  IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex");
2912  DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id));
2913
2914  DCHECK(found_encoded_primary_key->empty());
2915  *found = false;
2916
2917  LevelDBTransaction* leveldb_transaction = transaction->transaction();
2918  const std::string leveldb_key =
2919      IndexDataKey::Encode(database_id, object_store_id, index_id, key);
2920  scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
2921  leveldb::Status s = it->Seek(leveldb_key);
2922  if (!s.ok()) {
2923    INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
2924    return s;
2925  }
2926
2927  for (;;) {
2928    if (!it->IsValid())
2929      return leveldb::Status::OK();
2930    if (CompareIndexKeys(it->Key(), leveldb_key) > 0)
2931      return leveldb::Status::OK();
2932
2933    StringPiece slice(it->Value());
2934
2935    int64 version;
2936    if (!DecodeVarInt(&slice, &version)) {
2937      INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
2938      return InternalInconsistencyStatus();
2939    }
2940    *found_encoded_primary_key = slice.as_string();
2941
2942    bool exists = false;
2943    s = VersionExists(leveldb_transaction,
2944                      database_id,
2945                      object_store_id,
2946                      version,
2947                      *found_encoded_primary_key,
2948                      &exists);
2949    if (!s.ok())
2950      return s;
2951    if (!exists) {
2952      // Delete stale index data entry and continue.
2953      leveldb_transaction->Remove(it->Key());
2954      s = it->Next();
2955      continue;
2956    }
2957    *found = true;
2958    return s;
2959  }
2960}
2961
2962leveldb::Status IndexedDBBackingStore::GetPrimaryKeyViaIndex(
2963    IndexedDBBackingStore::Transaction* transaction,
2964    int64 database_id,
2965    int64 object_store_id,
2966    int64 index_id,
2967    const IndexedDBKey& key,
2968    scoped_ptr<IndexedDBKey>* primary_key) {
2969  IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex");
2970  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2971    return InvalidDBKeyStatus();
2972
2973  bool found = false;
2974  std::string found_encoded_primary_key;
2975  leveldb::Status s = FindKeyInIndex(transaction,
2976                                     database_id,
2977                                     object_store_id,
2978                                     index_id,
2979                                     key,
2980                                     &found_encoded_primary_key,
2981                                     &found);
2982  if (!s.ok()) {
2983    INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
2984    return s;
2985  }
2986  if (!found)
2987    return s;
2988  if (!found_encoded_primary_key.size()) {
2989    INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
2990    return InvalidDBKeyStatus();
2991  }
2992
2993  StringPiece slice(found_encoded_primary_key);
2994  if (DecodeIDBKey(&slice, primary_key) && slice.empty())
2995    return s;
2996  else
2997    return InvalidDBKeyStatus();
2998}
2999
3000leveldb::Status IndexedDBBackingStore::KeyExistsInIndex(
3001    IndexedDBBackingStore::Transaction* transaction,
3002    int64 database_id,
3003    int64 object_store_id,
3004    int64 index_id,
3005    const IndexedDBKey& index_key,
3006    scoped_ptr<IndexedDBKey>* found_primary_key,
3007    bool* exists) {
3008  IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex");
3009  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
3010    return InvalidDBKeyStatus();
3011
3012  *exists = false;
3013  std::string found_encoded_primary_key;
3014  leveldb::Status s = FindKeyInIndex(transaction,
3015                                     database_id,
3016                                     object_store_id,
3017                                     index_id,
3018                                     index_key,
3019                                     &found_encoded_primary_key,
3020                                     exists);
3021  if (!s.ok()) {
3022    INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
3023    return s;
3024  }
3025  if (!*exists)
3026    return leveldb::Status::OK();
3027  if (found_encoded_primary_key.empty()) {
3028    INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
3029    return InvalidDBKeyStatus();
3030  }
3031
3032  StringPiece slice(found_encoded_primary_key);
3033  if (DecodeIDBKey(&slice, found_primary_key) && slice.empty())
3034    return s;
3035  else
3036    return InvalidDBKeyStatus();
3037}
3038
3039IndexedDBBackingStore::Cursor::Cursor(
3040    const IndexedDBBackingStore::Cursor* other)
3041    : backing_store_(other->backing_store_),
3042      transaction_(other->transaction_),
3043      database_id_(other->database_id_),
3044      cursor_options_(other->cursor_options_),
3045      current_key_(new IndexedDBKey(*other->current_key_)) {
3046  if (other->iterator_) {
3047    iterator_ = transaction_->transaction()->CreateIterator();
3048
3049    if (other->iterator_->IsValid()) {
3050      leveldb::Status s = iterator_->Seek(other->iterator_->Key());
3051      // TODO(cmumford): Handle this error (crbug.com/363397)
3052      DCHECK(iterator_->IsValid());
3053    }
3054  }
3055}
3056
3057IndexedDBBackingStore::Cursor::Cursor(
3058    scoped_refptr<IndexedDBBackingStore> backing_store,
3059    IndexedDBBackingStore::Transaction* transaction,
3060    int64 database_id,
3061    const CursorOptions& cursor_options)
3062    : backing_store_(backing_store.get()),
3063      transaction_(transaction),
3064      database_id_(database_id),
3065      cursor_options_(cursor_options) {
3066}
3067IndexedDBBackingStore::Cursor::~Cursor() {}
3068
3069bool IndexedDBBackingStore::Cursor::FirstSeek(leveldb::Status* s) {
3070  iterator_ = transaction_->transaction()->CreateIterator();
3071  if (cursor_options_.forward)
3072    *s = iterator_->Seek(cursor_options_.low_key);
3073  else
3074    *s = iterator_->Seek(cursor_options_.high_key);
3075  if (!s->ok())
3076    return false;
3077
3078  return Continue(0, READY, s);
3079}
3080
3081bool IndexedDBBackingStore::Cursor::Advance(uint32 count, leveldb::Status* s) {
3082  *s = leveldb::Status::OK();
3083  while (count--) {
3084    if (!Continue(s))
3085      return false;
3086  }
3087  return true;
3088}
3089
3090bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
3091                                             const IndexedDBKey* primary_key,
3092                                             IteratorState next_state,
3093                                             leveldb::Status* s) {
3094  DCHECK(!key || key->IsValid());
3095  DCHECK(!primary_key || primary_key->IsValid());
3096  *s = leveldb::Status::OK();
3097
3098  // TODO(alecflett): avoid a copy here?
3099  IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
3100
3101  // When iterating with PrevNoDuplicate, spec requires that the
3102  // value we yield for each key is the first duplicate in forwards
3103  // order.
3104  IndexedDBKey last_duplicate_key;
3105
3106  bool forward = cursor_options_.forward;
3107  bool first_iteration_forward = forward;
3108  bool flipped = false;
3109
3110  for (;;) {
3111    if (next_state == SEEK) {
3112      // TODO(jsbell): Optimize seeking for reverse cursors as well.
3113      if (first_iteration_forward && key) {
3114        first_iteration_forward = false;
3115        std::string leveldb_key;
3116        if (primary_key) {
3117          leveldb_key = EncodeKey(*key, *primary_key);
3118        } else {
3119          leveldb_key = EncodeKey(*key);
3120        }
3121        *s = iterator_->Seek(leveldb_key);
3122      } else if (forward) {
3123        *s = iterator_->Next();
3124      } else {
3125        *s = iterator_->Prev();
3126      }
3127      if (!s->ok())
3128        return false;
3129    } else {
3130      next_state = SEEK;  // for subsequent iterations
3131    }
3132
3133    if (!iterator_->IsValid()) {
3134      if (!forward && last_duplicate_key.IsValid()) {
3135        // We need to walk forward because we hit the end of
3136        // the data.
3137        forward = true;
3138        flipped = true;
3139        continue;
3140      }
3141
3142      return false;
3143    }
3144
3145    if (IsPastBounds()) {
3146      if (!forward && last_duplicate_key.IsValid()) {
3147        // We need to walk forward because now we're beyond the
3148        // bounds defined by the cursor.
3149        forward = true;
3150        flipped = true;
3151        continue;
3152      }
3153
3154      return false;
3155    }
3156
3157    if (!HaveEnteredRange())
3158      continue;
3159
3160    // The row may not load because there's a stale entry in the
3161    // index. This is not fatal.
3162    if (!LoadCurrentRow())
3163      continue;
3164
3165    if (key) {
3166      if (forward) {
3167        if (primary_key && current_key_->Equals(*key) &&
3168            this->primary_key().IsLessThan(*primary_key))
3169          continue;
3170        if (!flipped && current_key_->IsLessThan(*key))
3171          continue;
3172      } else {
3173        if (primary_key && key->Equals(*current_key_) &&
3174            primary_key->IsLessThan(this->primary_key()))
3175          continue;
3176        if (key->IsLessThan(*current_key_))
3177          continue;
3178      }
3179    }
3180
3181    if (cursor_options_.unique) {
3182      if (previous_key.IsValid() && current_key_->Equals(previous_key)) {
3183        // We should never be able to walk forward all the way
3184        // to the previous key.
3185        DCHECK(!last_duplicate_key.IsValid());
3186        continue;
3187      }
3188
3189      if (!forward) {
3190        if (!last_duplicate_key.IsValid()) {
3191          last_duplicate_key = *current_key_;
3192          continue;
3193        }
3194
3195        // We need to walk forward because we hit the boundary
3196        // between key ranges.
3197        if (!last_duplicate_key.Equals(*current_key_)) {
3198          forward = true;
3199          flipped = true;
3200          continue;
3201        }
3202
3203        continue;
3204      }
3205    }
3206    break;
3207  }
3208
3209  DCHECK(!last_duplicate_key.IsValid() ||
3210         (forward && last_duplicate_key.Equals(*current_key_)));
3211  return true;
3212}
3213
3214bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const {
3215  if (cursor_options_.forward) {
3216    int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
3217    if (cursor_options_.low_open) {
3218      return compare > 0;
3219    }
3220    return compare >= 0;
3221  }
3222  int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
3223  if (cursor_options_.high_open) {
3224    return compare < 0;
3225  }
3226  return compare <= 0;
3227}
3228
3229bool IndexedDBBackingStore::Cursor::IsPastBounds() const {
3230  if (cursor_options_.forward) {
3231    int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
3232    if (cursor_options_.high_open) {
3233      return compare >= 0;
3234    }
3235    return compare > 0;
3236  }
3237  int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
3238  if (cursor_options_.low_open) {
3239    return compare <= 0;
3240  }
3241  return compare < 0;
3242}
3243
3244const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const {
3245  return *current_key_;
3246}
3247
3248const IndexedDBBackingStore::RecordIdentifier&
3249IndexedDBBackingStore::Cursor::record_identifier() const {
3250  return record_identifier_;
3251}
3252
3253class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor {
3254 public:
3255  ObjectStoreKeyCursorImpl(
3256      scoped_refptr<IndexedDBBackingStore> backing_store,
3257      IndexedDBBackingStore::Transaction* transaction,
3258      int64 database_id,
3259      const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3260      : IndexedDBBackingStore::Cursor(backing_store,
3261                                      transaction,
3262                                      database_id,
3263                                      cursor_options) {}
3264
3265  virtual Cursor* Clone() OVERRIDE {
3266    return new ObjectStoreKeyCursorImpl(this);
3267  }
3268
3269  // IndexedDBBackingStore::Cursor
3270  virtual IndexedDBValue* value() OVERRIDE {
3271    NOTREACHED();
3272    return NULL;
3273  }
3274  virtual bool LoadCurrentRow() OVERRIDE;
3275
3276 protected:
3277  virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3278    return ObjectStoreDataKey::Encode(
3279        cursor_options_.database_id, cursor_options_.object_store_id, key);
3280  }
3281  virtual std::string EncodeKey(const IndexedDBKey& key,
3282                                const IndexedDBKey& primary_key) OVERRIDE {
3283    NOTREACHED();
3284    return std::string();
3285  }
3286
3287 private:
3288  explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other)
3289      : IndexedDBBackingStore::Cursor(other) {}
3290
3291  DISALLOW_COPY_AND_ASSIGN(ObjectStoreKeyCursorImpl);
3292};
3293
3294bool ObjectStoreKeyCursorImpl::LoadCurrentRow() {
3295  StringPiece slice(iterator_->Key());
3296  ObjectStoreDataKey object_store_data_key;
3297  if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) {
3298    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3299    return false;
3300  }
3301
3302  current_key_ = object_store_data_key.user_key();
3303
3304  int64 version;
3305  slice = StringPiece(iterator_->Value());
3306  if (!DecodeVarInt(&slice, &version)) {
3307    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3308    return false;
3309  }
3310
3311  // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
3312  std::string encoded_key;
3313  EncodeIDBKey(*current_key_, &encoded_key);
3314  record_identifier_.Reset(encoded_key, version);
3315
3316  return true;
3317}
3318
3319class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor {
3320 public:
3321  ObjectStoreCursorImpl(
3322      scoped_refptr<IndexedDBBackingStore> backing_store,
3323      IndexedDBBackingStore::Transaction* transaction,
3324      int64 database_id,
3325      const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3326      : IndexedDBBackingStore::Cursor(backing_store,
3327                                      transaction,
3328                                      database_id,
3329                                      cursor_options) {}
3330
3331  virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); }
3332
3333  // IndexedDBBackingStore::Cursor
3334  virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
3335  virtual bool LoadCurrentRow() OVERRIDE;
3336
3337 protected:
3338  virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3339    return ObjectStoreDataKey::Encode(
3340        cursor_options_.database_id, cursor_options_.object_store_id, key);
3341  }
3342  virtual std::string EncodeKey(const IndexedDBKey& key,
3343                                const IndexedDBKey& primary_key) OVERRIDE {
3344    NOTREACHED();
3345    return std::string();
3346  }
3347
3348 private:
3349  explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other)
3350      : IndexedDBBackingStore::Cursor(other),
3351        current_value_(other->current_value_) {}
3352
3353  IndexedDBValue current_value_;
3354
3355  DISALLOW_COPY_AND_ASSIGN(ObjectStoreCursorImpl);
3356};
3357
3358bool ObjectStoreCursorImpl::LoadCurrentRow() {
3359  StringPiece key_slice(iterator_->Key());
3360  ObjectStoreDataKey object_store_data_key;
3361  if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) {
3362    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3363    return false;
3364  }
3365
3366  current_key_ = object_store_data_key.user_key();
3367
3368  int64 version;
3369  StringPiece value_slice = StringPiece(iterator_->Value());
3370  if (!DecodeVarInt(&value_slice, &version)) {
3371    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3372    return false;
3373  }
3374
3375  // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
3376  std::string encoded_key;
3377  EncodeIDBKey(*current_key_, &encoded_key);
3378  record_identifier_.Reset(encoded_key, version);
3379
3380  if (!transaction_->GetBlobInfoForRecord(database_id_,
3381                                          iterator_->Key().as_string(),
3382                                          &current_value_).ok()) {
3383    return false;
3384  }
3385  current_value_.bits = value_slice.as_string();
3386  return true;
3387}
3388
3389class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor {
3390 public:
3391  IndexKeyCursorImpl(
3392      scoped_refptr<IndexedDBBackingStore> backing_store,
3393      IndexedDBBackingStore::Transaction* transaction,
3394      int64 database_id,
3395      const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3396      : IndexedDBBackingStore::Cursor(backing_store,
3397                                      transaction,
3398                                      database_id,
3399                                      cursor_options) {}
3400
3401  virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); }
3402
3403  // IndexedDBBackingStore::Cursor
3404  virtual IndexedDBValue* value() OVERRIDE {
3405    NOTREACHED();
3406    return NULL;
3407  }
3408  virtual const IndexedDBKey& primary_key() const OVERRIDE {
3409    return *primary_key_;
3410  }
3411  virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
3412      const OVERRIDE {
3413    NOTREACHED();
3414    return record_identifier_;
3415  }
3416  virtual bool LoadCurrentRow() OVERRIDE;
3417
3418 protected:
3419  virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3420    return IndexDataKey::Encode(cursor_options_.database_id,
3421                                cursor_options_.object_store_id,
3422                                cursor_options_.index_id,
3423                                key);
3424  }
3425  virtual std::string EncodeKey(const IndexedDBKey& key,
3426                                const IndexedDBKey& primary_key) OVERRIDE {
3427    return IndexDataKey::Encode(cursor_options_.database_id,
3428                                cursor_options_.object_store_id,
3429                                cursor_options_.index_id,
3430                                key,
3431                                primary_key);
3432  }
3433
3434 private:
3435  explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other)
3436      : IndexedDBBackingStore::Cursor(other),
3437        primary_key_(new IndexedDBKey(*other->primary_key_)) {}
3438
3439  scoped_ptr<IndexedDBKey> primary_key_;
3440
3441  DISALLOW_COPY_AND_ASSIGN(IndexKeyCursorImpl);
3442};
3443
3444bool IndexKeyCursorImpl::LoadCurrentRow() {
3445  StringPiece slice(iterator_->Key());
3446  IndexDataKey index_data_key;
3447  if (!IndexDataKey::Decode(&slice, &index_data_key)) {
3448    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3449    return false;
3450  }
3451
3452  current_key_ = index_data_key.user_key();
3453  DCHECK(current_key_);
3454
3455  slice = StringPiece(iterator_->Value());
3456  int64 index_data_version;
3457  if (!DecodeVarInt(&slice, &index_data_version)) {
3458    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3459    return false;
3460  }
3461
3462  if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) {
3463    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3464    return false;
3465  }
3466
3467  std::string primary_leveldb_key =
3468      ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
3469                                 index_data_key.ObjectStoreId(),
3470                                 *primary_key_);
3471
3472  std::string result;
3473  bool found = false;
3474  leveldb::Status s =
3475      transaction_->transaction()->Get(primary_leveldb_key, &result, &found);
3476  if (!s.ok()) {
3477    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3478    return false;
3479  }
3480  if (!found) {
3481    transaction_->transaction()->Remove(iterator_->Key());
3482    return false;
3483  }
3484  if (!result.size()) {
3485    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3486    return false;
3487  }
3488
3489  int64 object_store_data_version;
3490  slice = StringPiece(result);
3491  if (!DecodeVarInt(&slice, &object_store_data_version)) {
3492    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3493    return false;
3494  }
3495
3496  if (object_store_data_version != index_data_version) {
3497    transaction_->transaction()->Remove(iterator_->Key());
3498    return false;
3499  }
3500
3501  return true;
3502}
3503
3504class IndexCursorImpl : public IndexedDBBackingStore::Cursor {
3505 public:
3506  IndexCursorImpl(
3507      scoped_refptr<IndexedDBBackingStore> backing_store,
3508      IndexedDBBackingStore::Transaction* transaction,
3509      int64 database_id,
3510      const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3511      : IndexedDBBackingStore::Cursor(backing_store,
3512                                      transaction,
3513                                      database_id,
3514                                      cursor_options) {}
3515
3516  virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); }
3517
3518  // IndexedDBBackingStore::Cursor
3519  virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
3520  virtual const IndexedDBKey& primary_key() const OVERRIDE {
3521    return *primary_key_;
3522  }
3523  virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
3524      const OVERRIDE {
3525    NOTREACHED();
3526    return record_identifier_;
3527  }
3528  virtual bool LoadCurrentRow() OVERRIDE;
3529
3530 protected:
3531  virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3532    return IndexDataKey::Encode(cursor_options_.database_id,
3533                                cursor_options_.object_store_id,
3534                                cursor_options_.index_id,
3535                                key);
3536  }
3537  virtual std::string EncodeKey(const IndexedDBKey& key,
3538                                const IndexedDBKey& primary_key) OVERRIDE {
3539    return IndexDataKey::Encode(cursor_options_.database_id,
3540                                cursor_options_.object_store_id,
3541                                cursor_options_.index_id,
3542                                key,
3543                                primary_key);
3544  }
3545
3546 private:
3547  explicit IndexCursorImpl(const IndexCursorImpl* other)
3548      : IndexedDBBackingStore::Cursor(other),
3549        primary_key_(new IndexedDBKey(*other->primary_key_)),
3550        current_value_(other->current_value_),
3551        primary_leveldb_key_(other->primary_leveldb_key_) {}
3552
3553  scoped_ptr<IndexedDBKey> primary_key_;
3554  IndexedDBValue current_value_;
3555  std::string primary_leveldb_key_;
3556
3557  DISALLOW_COPY_AND_ASSIGN(IndexCursorImpl);
3558};
3559
3560bool IndexCursorImpl::LoadCurrentRow() {
3561  StringPiece slice(iterator_->Key());
3562  IndexDataKey index_data_key;
3563  if (!IndexDataKey::Decode(&slice, &index_data_key)) {
3564    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3565    return false;
3566  }
3567
3568  current_key_ = index_data_key.user_key();
3569  DCHECK(current_key_);
3570
3571  slice = StringPiece(iterator_->Value());
3572  int64 index_data_version;
3573  if (!DecodeVarInt(&slice, &index_data_version)) {
3574    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3575    return false;
3576  }
3577  if (!DecodeIDBKey(&slice, &primary_key_)) {
3578    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3579    return false;
3580  }
3581
3582  DCHECK_EQ(index_data_key.DatabaseId(), database_id_);
3583  primary_leveldb_key_ =
3584      ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
3585                                 index_data_key.ObjectStoreId(),
3586                                 *primary_key_);
3587
3588  std::string result;
3589  bool found = false;
3590  leveldb::Status s =
3591      transaction_->transaction()->Get(primary_leveldb_key_, &result, &found);
3592  if (!s.ok()) {
3593    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3594    return false;
3595  }
3596  if (!found) {
3597    transaction_->transaction()->Remove(iterator_->Key());
3598    return false;
3599  }
3600  if (!result.size()) {
3601    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3602    return false;
3603  }
3604
3605  int64 object_store_data_version;
3606  slice = StringPiece(result);
3607  if (!DecodeVarInt(&slice, &object_store_data_version)) {
3608    INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3609    return false;
3610  }
3611
3612  if (object_store_data_version != index_data_version) {
3613    transaction_->transaction()->Remove(iterator_->Key());
3614    return false;
3615  }
3616
3617  current_value_.bits = slice.as_string();
3618  return transaction_->GetBlobInfoForRecord(database_id_,
3619                                            primary_leveldb_key_,
3620                                            &current_value_).ok();
3621}
3622
3623bool ObjectStoreCursorOptions(
3624    LevelDBTransaction* transaction,
3625    int64 database_id,
3626    int64 object_store_id,
3627    const IndexedDBKeyRange& range,
3628    blink::WebIDBCursorDirection direction,
3629    IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
3630  cursor_options->database_id = database_id;
3631  cursor_options->object_store_id = object_store_id;
3632
3633  bool lower_bound = range.lower().IsValid();
3634  bool upper_bound = range.upper().IsValid();
3635  cursor_options->forward =
3636      (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3637       direction == blink::WebIDBCursorDirectionNext);
3638  cursor_options->unique =
3639      (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3640       direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
3641
3642  if (!lower_bound) {
3643    cursor_options->low_key =
3644        ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
3645    cursor_options->low_open = true;  // Not included.
3646  } else {
3647    cursor_options->low_key =
3648        ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower());
3649    cursor_options->low_open = range.lowerOpen();
3650  }
3651
3652  leveldb::Status s;
3653
3654  if (!upper_bound) {
3655    cursor_options->high_key =
3656        ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
3657
3658    if (cursor_options->forward) {
3659      cursor_options->high_open = true;  // Not included.
3660    } else {
3661      // We need a key that exists.
3662      // TODO(cmumford): Handle this error (crbug.com/363397)
3663      if (!FindGreatestKeyLessThanOrEqual(transaction,
3664                                          cursor_options->high_key,
3665                                          &cursor_options->high_key,
3666                                          &s))
3667        return false;
3668      cursor_options->high_open = false;
3669    }
3670  } else {
3671    cursor_options->high_key =
3672        ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper());
3673    cursor_options->high_open = range.upperOpen();
3674
3675    if (!cursor_options->forward) {
3676      // For reverse cursors, we need a key that exists.
3677      std::string found_high_key;
3678      // TODO(cmumford): Handle this error (crbug.com/363397)
3679      if (!FindGreatestKeyLessThanOrEqual(
3680              transaction, cursor_options->high_key, &found_high_key, &s))
3681        return false;
3682
3683      // If the target key should not be included, but we end up with a smaller
3684      // key, we should include that.
3685      if (cursor_options->high_open &&
3686          CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
3687        cursor_options->high_open = false;
3688
3689      cursor_options->high_key = found_high_key;
3690    }
3691  }
3692
3693  return true;
3694}
3695
3696bool IndexCursorOptions(
3697    LevelDBTransaction* transaction,
3698    int64 database_id,
3699    int64 object_store_id,
3700    int64 index_id,
3701    const IndexedDBKeyRange& range,
3702    blink::WebIDBCursorDirection direction,
3703    IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
3704  DCHECK(transaction);
3705  if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
3706    return false;
3707
3708  cursor_options->database_id = database_id;
3709  cursor_options->object_store_id = object_store_id;
3710  cursor_options->index_id = index_id;
3711
3712  bool lower_bound = range.lower().IsValid();
3713  bool upper_bound = range.upper().IsValid();
3714  cursor_options->forward =
3715      (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3716       direction == blink::WebIDBCursorDirectionNext);
3717  cursor_options->unique =
3718      (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3719       direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
3720
3721  if (!lower_bound) {
3722    cursor_options->low_key =
3723        IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
3724    cursor_options->low_open = false;  // Included.
3725  } else {
3726    cursor_options->low_key = IndexDataKey::Encode(
3727        database_id, object_store_id, index_id, range.lower());
3728    cursor_options->low_open = range.lowerOpen();
3729  }
3730
3731  leveldb::Status s;
3732
3733  if (!upper_bound) {
3734    cursor_options->high_key =
3735        IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
3736    cursor_options->high_open = false;  // Included.
3737
3738    if (!cursor_options->forward) {  // We need a key that exists.
3739      if (!FindGreatestKeyLessThanOrEqual(transaction,
3740                                          cursor_options->high_key,
3741                                          &cursor_options->high_key,
3742                                          &s))
3743        return false;
3744      cursor_options->high_open = false;
3745    }
3746  } else {
3747    cursor_options->high_key = IndexDataKey::Encode(
3748        database_id, object_store_id, index_id, range.upper());
3749    cursor_options->high_open = range.upperOpen();
3750
3751    std::string found_high_key;
3752    // Seek to the *last* key in the set of non-unique keys
3753    // TODO(cmumford): Handle this error (crbug.com/363397)
3754    if (!FindGreatestKeyLessThanOrEqual(
3755            transaction, cursor_options->high_key, &found_high_key, &s))
3756      return false;
3757
3758    // If the target key should not be included, but we end up with a smaller
3759    // key, we should include that.
3760    if (cursor_options->high_open &&
3761        CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
3762      cursor_options->high_open = false;
3763
3764    cursor_options->high_key = found_high_key;
3765  }
3766
3767  return true;
3768}
3769
3770scoped_ptr<IndexedDBBackingStore::Cursor>
3771IndexedDBBackingStore::OpenObjectStoreCursor(
3772    IndexedDBBackingStore::Transaction* transaction,
3773    int64 database_id,
3774    int64 object_store_id,
3775    const IndexedDBKeyRange& range,
3776    blink::WebIDBCursorDirection direction,
3777    leveldb::Status* s) {
3778  IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor");
3779  *s = leveldb::Status::OK();
3780  LevelDBTransaction* leveldb_transaction = transaction->transaction();
3781  IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3782  if (!ObjectStoreCursorOptions(leveldb_transaction,
3783                                database_id,
3784                                object_store_id,
3785                                range,
3786                                direction,
3787                                &cursor_options))
3788    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3789  scoped_ptr<ObjectStoreCursorImpl> cursor(new ObjectStoreCursorImpl(
3790      this, transaction, database_id, cursor_options));
3791  if (!cursor->FirstSeek(s))
3792    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3793
3794  return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3795}
3796
3797scoped_ptr<IndexedDBBackingStore::Cursor>
3798IndexedDBBackingStore::OpenObjectStoreKeyCursor(
3799    IndexedDBBackingStore::Transaction* transaction,
3800    int64 database_id,
3801    int64 object_store_id,
3802    const IndexedDBKeyRange& range,
3803    blink::WebIDBCursorDirection direction,
3804    leveldb::Status* s) {
3805  IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor");
3806  *s = leveldb::Status::OK();
3807  LevelDBTransaction* leveldb_transaction = transaction->transaction();
3808  IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3809  if (!ObjectStoreCursorOptions(leveldb_transaction,
3810                                database_id,
3811                                object_store_id,
3812                                range,
3813                                direction,
3814                                &cursor_options))
3815    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3816  scoped_ptr<ObjectStoreKeyCursorImpl> cursor(new ObjectStoreKeyCursorImpl(
3817      this, transaction, database_id, cursor_options));
3818  if (!cursor->FirstSeek(s))
3819    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3820
3821  return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3822}
3823
3824scoped_ptr<IndexedDBBackingStore::Cursor>
3825IndexedDBBackingStore::OpenIndexKeyCursor(
3826    IndexedDBBackingStore::Transaction* transaction,
3827    int64 database_id,
3828    int64 object_store_id,
3829    int64 index_id,
3830    const IndexedDBKeyRange& range,
3831    blink::WebIDBCursorDirection direction,
3832    leveldb::Status* s) {
3833  IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor");
3834  *s = leveldb::Status::OK();
3835  LevelDBTransaction* leveldb_transaction = transaction->transaction();
3836  IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3837  if (!IndexCursorOptions(leveldb_transaction,
3838                          database_id,
3839                          object_store_id,
3840                          index_id,
3841                          range,
3842                          direction,
3843                          &cursor_options))
3844    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3845  scoped_ptr<IndexKeyCursorImpl> cursor(
3846      new IndexKeyCursorImpl(this, transaction, database_id, cursor_options));
3847  if (!cursor->FirstSeek(s))
3848    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3849
3850  return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3851}
3852
3853scoped_ptr<IndexedDBBackingStore::Cursor>
3854IndexedDBBackingStore::OpenIndexCursor(
3855    IndexedDBBackingStore::Transaction* transaction,
3856    int64 database_id,
3857    int64 object_store_id,
3858    int64 index_id,
3859    const IndexedDBKeyRange& range,
3860    blink::WebIDBCursorDirection direction,
3861    leveldb::Status* s) {
3862  IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor");
3863  LevelDBTransaction* leveldb_transaction = transaction->transaction();
3864  IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3865  if (!IndexCursorOptions(leveldb_transaction,
3866                          database_id,
3867                          object_store_id,
3868                          index_id,
3869                          range,
3870                          direction,
3871                          &cursor_options))
3872    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3873  scoped_ptr<IndexCursorImpl> cursor(
3874      new IndexCursorImpl(this, transaction, database_id, cursor_options));
3875  if (!cursor->FirstSeek(s))
3876    return scoped_ptr<IndexedDBBackingStore::Cursor>();
3877
3878  return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3879}
3880
3881IndexedDBBackingStore::Transaction::Transaction(
3882    IndexedDBBackingStore* backing_store)
3883    : backing_store_(backing_store), database_id_(-1) {
3884}
3885
3886IndexedDBBackingStore::Transaction::~Transaction() {
3887  STLDeleteContainerPairSecondPointers(
3888      blob_change_map_.begin(), blob_change_map_.end());
3889  STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
3890                                       incognito_blob_map_.end());
3891}
3892
3893void IndexedDBBackingStore::Transaction::Begin() {
3894  IDB_TRACE("IndexedDBBackingStore::Transaction::Begin");
3895  DCHECK(!transaction_.get());
3896  transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
3897      backing_store_->db_.get());
3898
3899  // If incognito, this snapshots blobs just as the above transaction_
3900  // constructor snapshots the leveldb.
3901  BlobChangeMap::const_iterator iter;
3902  for (iter = backing_store_->incognito_blob_map_.begin();
3903       iter != backing_store_->incognito_blob_map_.end();
3904       ++iter)
3905    incognito_blob_map_[iter->first] = iter->second->Clone().release();
3906}
3907
3908static GURL getURLFromUUID(const string& uuid) {
3909  return GURL("blob:uuid/" + uuid);
3910}
3911
3912leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
3913    BlobEntryKeyValuePairVec* new_blob_entries,
3914    WriteDescriptorVec* new_files_to_write) {
3915  if (backing_store_->is_incognito())
3916    return leveldb::Status::OK();
3917
3918  BlobChangeMap::iterator iter = blob_change_map_.begin();
3919  new_blob_entries->clear();
3920  new_files_to_write->clear();
3921  if (iter != blob_change_map_.end()) {
3922    // Create LevelDBTransaction for the name generator seed and add-journal.
3923    scoped_refptr<LevelDBTransaction> pre_transaction =
3924        IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
3925            backing_store_->db_.get());
3926    BlobJournalType journal;
3927    for (; iter != blob_change_map_.end(); ++iter) {
3928      std::vector<IndexedDBBlobInfo>::iterator info_iter;
3929      std::vector<IndexedDBBlobInfo*> new_blob_keys;
3930      for (info_iter = iter->second->mutable_blob_info().begin();
3931           info_iter != iter->second->mutable_blob_info().end();
3932           ++info_iter) {
3933        int64 next_blob_key = -1;
3934        bool result = GetBlobKeyGeneratorCurrentNumber(
3935            pre_transaction.get(), database_id_, &next_blob_key);
3936        if (!result || next_blob_key < 0)
3937          return InternalInconsistencyStatus();
3938        BlobJournalEntryType journal_entry =
3939            std::make_pair(database_id_, next_blob_key);
3940        journal.push_back(journal_entry);
3941        if (info_iter->is_file()) {
3942          new_files_to_write->push_back(
3943              WriteDescriptor(info_iter->file_path(),
3944                              next_blob_key,
3945                              info_iter->size(),
3946                              info_iter->last_modified()));
3947        } else {
3948          new_files_to_write->push_back(
3949              WriteDescriptor(getURLFromUUID(info_iter->uuid()),
3950                              next_blob_key,
3951                              info_iter->size()));
3952        }
3953        info_iter->set_key(next_blob_key);
3954        new_blob_keys.push_back(&*info_iter);
3955        result = UpdateBlobKeyGeneratorCurrentNumber(
3956            pre_transaction.get(), database_id_, next_blob_key + 1);
3957        if (!result)
3958          return InternalInconsistencyStatus();
3959      }
3960      BlobEntryKey blob_entry_key;
3961      StringPiece key_piece(iter->second->key());
3962      if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
3963        NOTREACHED();
3964        return InternalInconsistencyStatus();
3965      }
3966      new_blob_entries->push_back(
3967          std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys)));
3968    }
3969    UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal);
3970    leveldb::Status s = pre_transaction->Commit();
3971    if (!s.ok())
3972      return InternalInconsistencyStatus();
3973  }
3974  return leveldb::Status::OK();
3975}
3976
3977bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
3978  if (backing_store_->is_incognito())
3979    return true;
3980
3981  BlobChangeMap::const_iterator iter = blob_change_map_.begin();
3982  // Look up all old files to remove as part of the transaction, store their
3983  // names in blobs_to_remove_, and remove their old blob data entries.
3984  if (iter != blob_change_map_.end()) {
3985    for (; iter != blob_change_map_.end(); ++iter) {
3986      BlobEntryKey blob_entry_key;
3987      StringPiece key_piece(iter->second->key());
3988      if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
3989        NOTREACHED();
3990        INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
3991        transaction_ = NULL;
3992        return false;
3993      }
3994      if (database_id_ < 0)
3995        database_id_ = blob_entry_key.database_id();
3996      else
3997        DCHECK_EQ(database_id_, blob_entry_key.database_id());
3998      std::string blob_entry_key_bytes = blob_entry_key.Encode();
3999      bool found;
4000      std::string blob_entry_value_bytes;
4001      leveldb::Status s = transaction_->Get(
4002          blob_entry_key_bytes, &blob_entry_value_bytes, &found);
4003      if (s.ok() && found) {
4004        std::vector<IndexedDBBlobInfo> blob_info;
4005        if (!DecodeBlobData(blob_entry_value_bytes, &blob_info)) {
4006          INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4007          transaction_ = NULL;
4008          return false;
4009        }
4010        std::vector<IndexedDBBlobInfo>::iterator blob_info_iter;
4011        for (blob_info_iter = blob_info.begin();
4012             blob_info_iter != blob_info.end();
4013             ++blob_info_iter)
4014          blobs_to_remove_.push_back(
4015              std::make_pair(database_id_, blob_info_iter->key()));
4016        transaction_->Remove(blob_entry_key_bytes);
4017      }
4018    }
4019  }
4020  return true;
4021}
4022
4023leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
4024  IndexedDBActiveBlobRegistry* registry =
4025      backing_store_->active_blob_registry();
4026  BlobJournalType::iterator iter;
4027  BlobJournalType primary_journal, live_blob_journal;
4028  for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end();
4029       ++iter) {
4030    if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second))
4031      live_blob_journal.push_back(*iter);
4032    else
4033      primary_journal.push_back(*iter);
4034  }
4035  UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal);
4036  leveldb::Status s =
4037      MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal);
4038  if (!s.ok())
4039    return s;
4040  // To signal how many blobs need attention right now.
4041  blobs_to_remove_.swap(primary_journal);
4042  return leveldb::Status::OK();
4043}
4044
4045leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
4046    scoped_refptr<BlobWriteCallback> callback) {
4047  IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne");
4048  DCHECK(transaction_.get());
4049  DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
4050
4051  leveldb::Status s;
4052
4053  s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
4054  if (!s.ok()) {
4055    INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
4056    transaction_ = NULL;
4057    return s;
4058  }
4059
4060  BlobEntryKeyValuePairVec new_blob_entries;
4061  WriteDescriptorVec new_files_to_write;
4062  s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write);
4063  if (!s.ok()) {
4064    INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4065    transaction_ = NULL;
4066    return s;
4067  }
4068
4069  DCHECK(!new_files_to_write.size() ||
4070         KeyPrefix::IsValidDatabaseId(database_id_));
4071  if (!CollectBlobFilesToRemove()) {
4072    INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4073    transaction_ = NULL;
4074    return InternalInconsistencyStatus();
4075  }
4076
4077  if (new_files_to_write.size()) {
4078    // This kicks off the writes of the new blobs, if any.
4079    // This call will zero out new_blob_entries and new_files_to_write.
4080    WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback);
4081    // Remove the add journal, if any; once the blobs are written, and we
4082    // commit, this will do the cleanup.
4083    ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode());
4084  } else {
4085    callback->Run(true);
4086  }
4087
4088  return leveldb::Status::OK();
4089}
4090
4091leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
4092  IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo");
4093  leveldb::Status s;
4094  if (blobs_to_remove_.size()) {
4095    s = SortBlobsToRemove();
4096    if (!s.ok()) {
4097      INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4098      transaction_ = NULL;
4099      return s;
4100    }
4101  }
4102
4103  s = transaction_->Commit();
4104  transaction_ = NULL;
4105
4106  if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) {
4107    BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
4108    BlobChangeMap::iterator iter;
4109    for (iter = blob_change_map_.begin(); iter != blob_change_map_.end();
4110         ++iter) {
4111      BlobChangeMap::iterator target_record = target_map.find(iter->first);
4112      if (target_record != target_map.end()) {
4113        delete target_record->second;
4114        target_map.erase(target_record);
4115      }
4116      if (iter->second) {
4117        target_map[iter->first] = iter->second;
4118        iter->second = NULL;
4119      }
4120    }
4121  }
4122  if (!s.ok())
4123    INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
4124  else if (blobs_to_remove_.size())
4125    s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
4126
4127  return s;
4128}
4129
4130
4131class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
4132    : public IndexedDBBackingStore::BlobWriteCallback {
4133 public:
4134  BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction,
4135                           scoped_refptr<BlobWriteCallback> callback)
4136      : transaction_(transaction), callback_(callback) {}
4137  virtual void Run(bool succeeded) OVERRIDE {
4138    callback_->Run(succeeded);
4139    if (succeeded)  // Else it's already been deleted during rollback.
4140      transaction_->chained_blob_writer_ = NULL;
4141  }
4142
4143 private:
4144  virtual ~BlobWriteCallbackWrapper() {}
4145  friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>;
4146
4147  IndexedDBBackingStore::Transaction* transaction_;
4148  scoped_refptr<BlobWriteCallback> callback_;
4149
4150  DISALLOW_COPY_AND_ASSIGN(BlobWriteCallbackWrapper);
4151};
4152
4153void IndexedDBBackingStore::Transaction::WriteNewBlobs(
4154    BlobEntryKeyValuePairVec* new_blob_entries,
4155    WriteDescriptorVec* new_files_to_write,
4156    scoped_refptr<BlobWriteCallback> callback) {
4157  DCHECK_GT(new_files_to_write->size(), 0UL);
4158  DCHECK_GT(database_id_, 0);
4159  BlobEntryKeyValuePairVec::iterator blob_entry_iter;
4160  for (blob_entry_iter = new_blob_entries->begin();
4161       blob_entry_iter != new_blob_entries->end();
4162       ++blob_entry_iter) {
4163    // Add the new blob-table entry for each blob to the main transaction, or
4164    // remove any entry that may exist if there's no new one.
4165    if (!blob_entry_iter->second.size())
4166      transaction_->Remove(blob_entry_iter->first.Encode());
4167    else
4168      transaction_->Put(blob_entry_iter->first.Encode(),
4169                        &blob_entry_iter->second);
4170  }
4171  // Creating the writer will start it going asynchronously.
4172  chained_blob_writer_ =
4173      new ChainedBlobWriterImpl(database_id_,
4174                                backing_store_,
4175                                new_files_to_write,
4176                                new BlobWriteCallbackWrapper(this, callback));
4177}
4178
4179void IndexedDBBackingStore::Transaction::Rollback() {
4180  IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
4181  if (chained_blob_writer_.get()) {
4182    chained_blob_writer_->Abort();
4183    chained_blob_writer_ = NULL;
4184  }
4185  if (transaction_.get() == NULL)
4186    return;
4187  transaction_->Rollback();
4188  transaction_ = NULL;
4189}
4190
4191IndexedDBBackingStore::BlobChangeRecord::BlobChangeRecord(
4192    const std::string& key,
4193    int64 object_store_id)
4194    : key_(key), object_store_id_(object_store_id) {
4195}
4196
4197IndexedDBBackingStore::BlobChangeRecord::~BlobChangeRecord() {
4198}
4199
4200void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo(
4201    std::vector<IndexedDBBlobInfo>* blob_info) {
4202  blob_info_.clear();
4203  if (blob_info)
4204    blob_info_.swap(*blob_info);
4205}
4206
4207void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
4208    ScopedVector<storage::BlobDataHandle>* handles) {
4209  handles_.clear();
4210  if (handles)
4211    handles_.swap(*handles);
4212}
4213
4214scoped_ptr<IndexedDBBackingStore::BlobChangeRecord>
4215IndexedDBBackingStore::BlobChangeRecord::Clone() const {
4216  scoped_ptr<IndexedDBBackingStore::BlobChangeRecord> record(
4217      new BlobChangeRecord(key_, object_store_id_));
4218  record->blob_info_ = blob_info_;
4219
4220  ScopedVector<storage::BlobDataHandle>::const_iterator iter;
4221  for (iter = handles_.begin(); iter != handles_.end(); ++iter)
4222    record->handles_.push_back(new storage::BlobDataHandle(**iter));
4223  return record.Pass();
4224}
4225
4226leveldb::Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
4227    int64 database_id,
4228    int64 object_store_id,
4229    const std::string& object_store_data_key,
4230    std::vector<IndexedDBBlobInfo>* blob_info,
4231    ScopedVector<storage::BlobDataHandle>* handles) {
4232  if (!blob_info || blob_info->empty()) {
4233    blob_change_map_.erase(object_store_data_key);
4234    incognito_blob_map_.erase(object_store_data_key);
4235
4236    BlobEntryKey blob_entry_key;
4237    StringPiece leveldb_key_piece(object_store_data_key);
4238    if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
4239                                              &blob_entry_key)) {
4240      NOTREACHED();
4241      return InternalInconsistencyStatus();
4242    }
4243    std::string value;
4244    bool found = false;
4245    leveldb::Status s =
4246        transaction()->Get(blob_entry_key.Encode(), &value, &found);
4247    if (!s.ok())
4248      return s;
4249    if (!found)
4250      return leveldb::Status::OK();
4251  }
4252  PutBlobInfo(
4253      database_id, object_store_id, object_store_data_key, blob_info, handles);
4254  return leveldb::Status::OK();
4255}
4256
4257// This is storing an info, even if empty, even if the previous key had no blob
4258// info that we know of.  It duplicates a bunch of information stored in the
4259// leveldb transaction, but only w.r.t. the user keys altered--we don't keep the
4260// changes to exists or index keys here.
4261void IndexedDBBackingStore::Transaction::PutBlobInfo(
4262    int64 database_id,
4263    int64 object_store_id,
4264    const std::string& object_store_data_key,
4265    std::vector<IndexedDBBlobInfo>* blob_info,
4266    ScopedVector<storage::BlobDataHandle>* handles) {
4267  DCHECK_GT(object_store_data_key.size(), 0UL);
4268  if (database_id_ < 0)
4269    database_id_ = database_id;
4270  DCHECK_EQ(database_id_, database_id);
4271
4272  BlobChangeMap::iterator it = blob_change_map_.find(object_store_data_key);
4273  BlobChangeRecord* record = NULL;
4274  if (it == blob_change_map_.end()) {
4275    record = new BlobChangeRecord(object_store_data_key, object_store_id);
4276    blob_change_map_[object_store_data_key] = record;
4277  } else {
4278    record = it->second;
4279  }
4280  DCHECK_EQ(record->object_store_id(), object_store_id);
4281  record->SetBlobInfo(blob_info);
4282  record->SetHandles(handles);
4283  DCHECK(!handles || !handles->size());
4284}
4285
4286IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
4287    const GURL& url,
4288    int64_t key,
4289    int64_t size)
4290    : is_file_(false), url_(url), key_(key), size_(size) {
4291}
4292
4293IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
4294    const FilePath& file_path,
4295    int64_t key,
4296    int64_t size,
4297    base::Time last_modified)
4298    : is_file_(true),
4299      file_path_(file_path),
4300      key_(key),
4301      size_(size),
4302      last_modified_(last_modified) {
4303}
4304
4305}  // namespace content
4306