Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_backing_store.cc
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/file_util.h"
8 #include "base/files/file_path.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 "third_party/WebKit/public/platform/WebIDBTypes.h"
36 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
37 #include "third_party/leveldatabase/env_chromium.h"
38 #include "webkit/browser/blob/blob_data_handle.h"
39 #include "webkit/browser/fileapi/file_stream_writer.h"
40 #include "webkit/browser/fileapi/file_writer_delegate.h"
41 #include "webkit/browser/fileapi/local_file_stream_writer.h"
42 #include "webkit/common/database/database_identifier.h"
43
44 using base::FilePath;
45 using base::StringPiece;
46 using fileapi::FileWriterDelegate;
47
48 namespace content {
49
50 namespace {
51
52 FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) {
53   return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
54 }
55
56 FilePath 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
65 FilePath 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
73 bool 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
80 static std::string ComputeOriginIdentifier(const GURL& origin_url) {
81   return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1";
82 }
83
84 static base::FilePath ComputeFileName(const GURL& origin_url) {
85   return base::FilePath()
86       .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
87       .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
88 }
89
90 static base::FilePath ComputeBlobPath(const GURL& origin_url) {
91   return base::FilePath()
92       .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
93       .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
94 }
95
96 static 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
103 static const int64 kKeyGeneratorInitialNumber =
104     1;  // From the IndexedDB specification.
105
106 enum 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
138 static 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
183 static 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.
193 static leveldb::Status InternalInconsistencyStatus() {
194   return leveldb::Status::Corruption("Internal inconsistency");
195 }
196
197 static leveldb::Status InvalidDBKeyStatus() {
198   return leveldb::Status::InvalidArgument("Invalid database key ID");
199 }
200
201 static leveldb::Status IOErrorStatus() {
202   return leveldb::Status::IOError("IO Error");
203 }
204
205 template <typename DBOrTransaction>
206 static 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
222 static 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
231 template <typename DBOrTransaction>
232 WARN_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
248 static 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
256 template <typename DBOrTransaction>
257 WARN_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
275 static 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
283 static 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
291 static int CompareKeys(const StringPiece& a, const StringPiece& b) {
292   return Compare(a, b, false /*index_keys*/);
293 }
294
295 static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) {
296   return Compare(a, b, true /*index_keys*/);
297 }
298
299 int IndexedDBBackingStore::Comparator::Compare(const StringPiece& a,
300                                                const StringPiece& b) const {
301   return content::Compare(a, b, false /*index_keys*/);
302 }
303
304 const 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.
312 static const int64 kLatestKnownSchemaVersion = 3;
313 WARN_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.
351 WARN_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
458 template <typename DBOrTransaction>
459 WARN_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
468 template <typename DBOrTransaction>
469 WARN_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
486 class 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
504 static 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
533 static 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.
558 template <typename T>
559 static 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
580 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction,
581                              const std::string& level_db_key) {
582   leveldb_transaction->Remove(level_db_key);
583 }
584
585 static 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
594 static 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
603 static 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
618 static 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
630 static 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.
653 static 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
670 static 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
704 IndexedDBBackingStore::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
723 IndexedDBBackingStore::~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
741 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
742     const std::string& primary_key,
743     int64 version)
744     : primary_key_(primary_key), version_(version) {
745   DCHECK(!primary_key.empty());
746 }
747 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
748     : primary_key_(), version_(-1) {}
749 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
750
751 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
752 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
753
754 enum 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
775 scoped_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
801 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) {
802   if (origin_url.host() == "docs.google.com")
803     return ".Docs";
804   return std::string();
805 }
806
807 static 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
827 static 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
857 leveldb::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
866 bool 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
906 bool 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
929 scoped_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 &&
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
1083 scoped_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
1093 scoped_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
1122 scoped_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
1147 void 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
1155 std::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
1211 leveldb::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
1289 WARN_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
1312 leveldb::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
1352 bool 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.
1368 static 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
1382 static 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
1408 static 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
1421 leveldb::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
1481 static 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.
1502 leveldb::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
1685 WARN_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
1707 void IndexedDBBackingStore::Compact() { db_->CompactAll(); }
1708
1709 leveldb::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
1760 leveldb::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
1825 leveldb::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
1866 WARN_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
1898 leveldb::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<webkit_blob::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
1947 leveldb::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
1968 leveldb::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
1992 leveldb::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
2055 leveldb::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
2127 leveldb::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
2156 leveldb::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
2195 class 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_);
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
2281 class 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<fileapi::FileStreamWriter> writer(
2318         fileapi::FileStreamWriter::CreateForLocalFile(
2319             task_runner_, file_path, 0,
2320             fileapi::FileStreamWriter::CREATE_NEW_FILE));
2321     scoped_ptr<FileWriterDelegate> delegate(
2322         new FileWriterDelegate(writer.Pass(),
2323                                FileWriterDelegate::FLUSH_ON_COMPLETION));
2324
2325     DCHECK(blob_url.is_valid());
2326     scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest(
2327         blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL));
2328
2329     delegate->Start(blob_request.Pass(),
2330                     base::Bind(&LocalWriteClosure::Run, this));
2331     chained_blob_writer_->set_delegate(delegate.Pass());
2332   }
2333
2334  private:
2335   virtual ~LocalWriteClosure() {
2336     // Make sure the last reference to a ChainedBlobWriter is released (and
2337     // deleted) on the IDB thread since it owns a transaction which has thread
2338     // affinity.
2339     IndexedDBBackingStore::Transaction::ChainedBlobWriter* raw_tmp =
2340         chained_blob_writer_.get();
2341     raw_tmp->AddRef();
2342     chained_blob_writer_ = NULL;
2343     task_runner_->ReleaseSoon(FROM_HERE, raw_tmp);
2344   }
2345   friend class base::RefCountedThreadSafe<LocalWriteClosure>;
2346
2347   scoped_refptr<IndexedDBBackingStore::Transaction::ChainedBlobWriter>
2348       chained_blob_writer_;
2349   scoped_refptr<base::SequencedTaskRunner> task_runner_;
2350   int64 bytes_written_;
2351
2352   DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure);
2353 };
2354
2355 bool IndexedDBBackingStore::WriteBlobFile(
2356     int64 database_id,
2357     const Transaction::WriteDescriptor& descriptor,
2358     Transaction::ChainedBlobWriter* chained_blob_writer) {
2359
2360   if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key()))
2361     return false;
2362
2363   FilePath path = GetBlobFileName(database_id, descriptor.key());
2364
2365   if (descriptor.is_file()) {
2366     DCHECK(!descriptor.file_path().empty());
2367     if (!base::CopyFile(descriptor.file_path(), path))
2368       return false;
2369
2370     base::File::Info info;
2371     if (base::GetFileInfo(descriptor.file_path(), &info)) {
2372       if (descriptor.size() != -1) {
2373         if (descriptor.size() != info.size)
2374           return false;
2375         // The round-trip can be lossy; round to nearest millisecond.
2376         int64 delta = (descriptor.last_modified() -
2377             info.last_modified).InMilliseconds();
2378         if (std::abs(delta) > 1)
2379           return false;
2380       }
2381       if (!base::TouchFile(path, info.last_accessed, info.last_modified)) {
2382         // TODO(ericu): Complain quietly; timestamp's probably not vital.
2383       }
2384     } else {
2385       // TODO(ericu): Complain quietly; timestamp's probably not vital.
2386     }
2387
2388     task_runner_->PostTask(
2389         FROM_HERE,
2390         base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
2391                    chained_blob_writer,
2392                    true,
2393                    info.size));
2394   } else {
2395     DCHECK(descriptor.url().is_valid());
2396     scoped_refptr<LocalWriteClosure> write_closure(
2397         new LocalWriteClosure(chained_blob_writer, task_runner_));
2398     content::BrowserThread::PostTask(
2399         content::BrowserThread::IO,
2400         FROM_HERE,
2401         base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread,
2402                    write_closure.get(),
2403                    path,
2404                    descriptor.url(),
2405                    request_context_));
2406   }
2407   return true;
2408 }
2409
2410 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id,
2411                                              int64 blob_key) {
2412   DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
2413   bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey;
2414   DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key));
2415   scoped_refptr<LevelDBTransaction> transaction =
2416       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
2417
2418   std::string live_blob_key = LiveBlobJournalKey::Encode();
2419   BlobJournalType live_blob_journal;
2420   if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal)
2421            .ok())
2422     return;
2423   DCHECK(live_blob_journal.size());
2424
2425   std::string primary_key = BlobJournalKey::Encode();
2426   BlobJournalType primary_journal;
2427   if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok())
2428     return;
2429
2430   // There are several cases to handle.  If blob_key is kAllBlobsKey, we want to
2431   // remove all entries with database_id from the live_blob journal and add only
2432   // kAllBlobsKey to the primary journal.  Otherwise if IsValidBlobKey(blob_key)
2433   // and we hit kAllBlobsKey for the right database_id in the journal, we leave
2434   // the kAllBlobsKey entry in the live_blob journal but add the specific blob
2435   // to the primary.  Otherwise if IsValidBlobKey(blob_key) and we find a
2436   // matching (database_id, blob_key) tuple, we should move it to the primary
2437   // journal.
2438   BlobJournalType new_live_blob_journal;
2439   for (BlobJournalType::iterator journal_iter = live_blob_journal.begin();
2440        journal_iter != live_blob_journal.end();
2441        ++journal_iter) {
2442     int64 current_database_id = journal_iter->first;
2443     int64 current_blob_key = journal_iter->second;
2444     bool current_all_blobs =
2445         current_blob_key == DatabaseMetaDataKey::kAllBlobsKey;
2446     DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) ||
2447            current_all_blobs);
2448     if (current_database_id == database_id &&
2449         (all_blobs || current_all_blobs || blob_key == current_blob_key)) {
2450       if (!all_blobs) {
2451         primary_journal.push_back(
2452             std::make_pair(database_id, current_blob_key));
2453         if (current_all_blobs)
2454           new_live_blob_journal.push_back(*journal_iter);
2455         new_live_blob_journal.insert(new_live_blob_journal.end(),
2456                                      ++journal_iter,
2457                                      live_blob_journal.end());  // All the rest.
2458         break;
2459       }
2460     } else {
2461       new_live_blob_journal.push_back(*journal_iter);
2462     }
2463   }
2464   if (all_blobs) {
2465     primary_journal.push_back(
2466         std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
2467   }
2468   UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal);
2469   UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal);
2470   transaction->Commit();
2471   // We could just do the deletions/cleaning here, but if there are a lot of
2472   // blobs about to be garbage collected, it'd be better to wait and do them all
2473   // at once.
2474   StartJournalCleaningTimer();
2475 }
2476
2477 // The this reference is a raw pointer that's declared Unretained inside the
2478 // timer code, so this won't confuse IndexedDBFactory's check for
2479 // HasLastBackingStoreReference.  It's safe because if the backing store is
2480 // deleted, the timer will automatically be canceled on destruction.
2481 void IndexedDBBackingStore::StartJournalCleaningTimer() {
2482   journal_cleaning_timer_.Start(
2483       FROM_HERE,
2484       base::TimeDelta::FromSeconds(5),
2485       this,
2486       &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn);
2487 }
2488
2489 // This assumes a file path of dbId/second-to-LSB-of-counter/counter.
2490 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) {
2491   return GetBlobFileNameForKey(blob_path_, database_id, key);
2492 }
2493
2494 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
2495                                      const std::string& stop_key,
2496                                      int64 index_id,
2497                                      unsigned char meta_data_type) {
2498   if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0)
2499     return false;
2500
2501   StringPiece slice(it->Key());
2502   IndexMetaDataKey meta_data_key;
2503   bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
2504   DCHECK(ok);
2505   if (meta_data_key.IndexId() != index_id)
2506     return false;
2507   if (meta_data_key.meta_data_type() != meta_data_type)
2508     return false;
2509   return true;
2510 }
2511
2512 // TODO(jsbell): This should do some error handling rather than plowing ahead
2513 // when bad data is encountered.
2514 leveldb::Status IndexedDBBackingStore::GetIndexes(
2515     int64 database_id,
2516     int64 object_store_id,
2517     IndexedDBObjectStoreMetadata::IndexMap* indexes) {
2518   IDB_TRACE("IndexedDBBackingStore::GetIndexes");
2519   if (!KeyPrefix::ValidIds(database_id, object_store_id))
2520     return InvalidDBKeyStatus();
2521   const std::string start_key =
2522       IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0);
2523   const std::string stop_key =
2524       IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0);
2525
2526   DCHECK(indexes->empty());
2527
2528   scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
2529   leveldb::Status s = it->Seek(start_key);
2530   while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) {
2531     StringPiece slice(it->Key());
2532     IndexMetaDataKey meta_data_key;
2533     bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
2534     DCHECK(ok);
2535     if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) {
2536       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2537       // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
2538       // the load.
2539       s = it->Next();
2540       if (!s.ok())
2541         break;
2542       continue;
2543     }
2544
2545     // TODO(jsbell): Do this by direct key lookup rather than iteration, to
2546     // simplify.
2547     int64 index_id = meta_data_key.IndexId();
2548     base::string16 index_name;
2549     {
2550       StringPiece slice(it->Value());
2551       if (!DecodeString(&slice, &index_name) || !slice.empty())
2552         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2553     }
2554
2555     s = it->Next();  // unique flag
2556     if (!s.ok())
2557       break;
2558     if (!CheckIndexAndMetaDataKey(
2559              it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) {
2560       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2561       break;
2562     }
2563     bool index_unique;
2564     {
2565       StringPiece slice(it->Value());
2566       if (!DecodeBool(&slice, &index_unique) || !slice.empty())
2567         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2568     }
2569
2570     s = it->Next();  // key_path
2571     if (!s.ok())
2572       break;
2573     if (!CheckIndexAndMetaDataKey(
2574              it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) {
2575       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2576       break;
2577     }
2578     IndexedDBKeyPath key_path;
2579     {
2580       StringPiece slice(it->Value());
2581       if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty())
2582         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2583     }
2584
2585     s = it->Next();  // [optional] multi_entry flag
2586     if (!s.ok())
2587       break;
2588     bool index_multi_entry = false;
2589     if (CheckIndexAndMetaDataKey(
2590             it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) {
2591       StringPiece slice(it->Value());
2592       if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty())
2593         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
2594
2595       s = it->Next();
2596       if (!s.ok())
2597         break;
2598     }
2599
2600     (*indexes)[index_id] = IndexedDBIndexMetadata(
2601         index_name, index_id, key_path, index_unique, index_multi_entry);
2602   }
2603
2604   if (!s.ok())
2605     INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES);
2606
2607   return s;
2608 }
2609
2610 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) {
2611   FilePath fileName = GetBlobFileName(database_id, key);
2612   return base::DeleteFile(fileName, false);
2613 }
2614
2615 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) {
2616   FilePath dirName = GetBlobDirectoryName(blob_path_, database_id);
2617   return base::DeleteFile(dirName, true);
2618 }
2619
2620 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
2621     const std::string& level_db_key) {
2622   scoped_refptr<LevelDBTransaction> journal_transaction =
2623       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
2624   BlobJournalType journal;
2625   leveldb::Status s =
2626       GetBlobJournal(level_db_key, journal_transaction.get(), &journal);
2627   if (!s.ok())
2628     return s;
2629   if (!journal.size())
2630     return leveldb::Status::OK();
2631   BlobJournalType::iterator journal_iter;
2632   for (journal_iter = journal.begin(); journal_iter != journal.end();
2633        ++journal_iter) {
2634     int64 database_id = journal_iter->first;
2635     int64 blob_key = journal_iter->second;
2636     DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
2637     if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
2638       if (!RemoveBlobDirectory(database_id))
2639         return IOErrorStatus();
2640     } else {
2641       DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
2642       if (!RemoveBlobFile(database_id, blob_key))
2643         return IOErrorStatus();
2644     }
2645   }
2646   ClearBlobJournal(journal_transaction.get(), level_db_key);
2647   return journal_transaction->Commit();
2648 }
2649
2650 leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
2651     int64 database_id,
2652     const std::string& object_store_data_key,
2653     IndexedDBValue* value) {
2654   BlobChangeRecord* change_record = NULL;
2655   BlobChangeMap::const_iterator blob_iter =
2656       blob_change_map_.find(object_store_data_key);
2657   if (blob_iter != blob_change_map_.end()) {
2658     change_record = blob_iter->second;
2659   } else {
2660     blob_iter = incognito_blob_map_.find(object_store_data_key);
2661     if (blob_iter != incognito_blob_map_.end())
2662       change_record = blob_iter->second;
2663   }
2664   if (change_record) {
2665     // Either we haven't written the blob to disk yet or we're in incognito
2666     // mode, so we have to send back the one they sent us.  This change record
2667     // includes the original UUID.
2668     value->blob_info = change_record->blob_info();
2669     return leveldb::Status::OK();
2670   }
2671
2672   BlobEntryKey blob_entry_key;
2673   StringPiece leveldb_key_piece(object_store_data_key);
2674   if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
2675                                             &blob_entry_key)) {
2676     NOTREACHED();
2677     return InternalInconsistencyStatus();
2678   }
2679   scoped_ptr<LevelDBIterator> it = transaction()->CreateIterator();
2680   std::string encoded_key = blob_entry_key.Encode();
2681   leveldb::Status s = it->Seek(encoded_key);
2682   if (!s.ok())
2683     return s;
2684   if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) {
2685     if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) {
2686       INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD);
2687       return InternalInconsistencyStatus();
2688     }
2689     std::vector<IndexedDBBlobInfo>::iterator iter;
2690     for (iter = value->blob_info.begin(); iter != value->blob_info.end();
2691          ++iter) {
2692       iter->set_file_path(
2693           backing_store_->GetBlobFileName(database_id, iter->key()));
2694       iter->set_mark_used_callback(
2695           backing_store_->active_blob_registry()->GetAddBlobRefCallback(
2696               database_id, iter->key()));
2697       iter->set_release_callback(
2698           backing_store_->active_blob_registry()->GetFinalReleaseCallback(
2699               database_id, iter->key()));
2700       if (iter->is_file()) {
2701         base::File::Info info;
2702         if (base::GetFileInfo(iter->file_path(), &info)) {
2703           // This should always work, but it isn't fatal if it doesn't; it just
2704           // means a potential slow synchronous call from the renderer later.
2705           iter->set_last_modified(info.last_modified);
2706           iter->set_size(info.size);
2707         }
2708       }
2709     }
2710   }
2711   return leveldb::Status::OK();
2712 }
2713
2714 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() {
2715   CleanUpBlobJournal(BlobJournalKey::Encode());
2716 }
2717
2718 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId(
2719     LevelDBTransaction* transaction,
2720     int64 database_id,
2721     int64 object_store_id,
2722     int64 index_id) {
2723   int64 max_index_id = -1;
2724   const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode(
2725       database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
2726   bool found = false;
2727   leveldb::Status s =
2728       GetInt(transaction, max_index_id_key, &max_index_id, &found);
2729   if (!s.ok()) {
2730     INTERNAL_READ_ERROR_UNTESTED(SET_MAX_INDEX_ID);
2731     return s;
2732   }
2733   if (!found)
2734     max_index_id = kMinimumIndexId;
2735
2736   if (index_id <= max_index_id) {
2737     INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_INDEX_ID);
2738     return InternalInconsistencyStatus();
2739   }
2740
2741   PutInt(transaction, max_index_id_key, index_id);
2742   return s;
2743 }
2744
2745 leveldb::Status IndexedDBBackingStore::CreateIndex(
2746     IndexedDBBackingStore::Transaction* transaction,
2747     int64 database_id,
2748     int64 object_store_id,
2749     int64 index_id,
2750     const base::string16& name,
2751     const IndexedDBKeyPath& key_path,
2752     bool is_unique,
2753     bool is_multi_entry) {
2754   IDB_TRACE("IndexedDBBackingStore::CreateIndex");
2755   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2756     return InvalidDBKeyStatus();
2757   LevelDBTransaction* leveldb_transaction = transaction->transaction();
2758   leveldb::Status s = SetMaxIndexId(
2759       leveldb_transaction, database_id, object_store_id, index_id);
2760
2761   if (!s.ok())
2762     return s;
2763
2764   const std::string name_key = IndexMetaDataKey::Encode(
2765       database_id, object_store_id, index_id, IndexMetaDataKey::NAME);
2766   const std::string unique_key = IndexMetaDataKey::Encode(
2767       database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE);
2768   const std::string key_path_key = IndexMetaDataKey::Encode(
2769       database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH);
2770   const std::string multi_entry_key = IndexMetaDataKey::Encode(
2771       database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY);
2772
2773   PutString(leveldb_transaction, name_key, name);
2774   PutBool(leveldb_transaction, unique_key, is_unique);
2775   PutIDBKeyPath(leveldb_transaction, key_path_key, key_path);
2776   PutBool(leveldb_transaction, multi_entry_key, is_multi_entry);
2777   return s;
2778 }
2779
2780 leveldb::Status IndexedDBBackingStore::DeleteIndex(
2781     IndexedDBBackingStore::Transaction* transaction,
2782     int64 database_id,
2783     int64 object_store_id,
2784     int64 index_id) {
2785   IDB_TRACE("IndexedDBBackingStore::DeleteIndex");
2786   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2787     return InvalidDBKeyStatus();
2788   LevelDBTransaction* leveldb_transaction = transaction->transaction();
2789
2790   const std::string index_meta_data_start =
2791       IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0);
2792   const std::string index_meta_data_end =
2793       IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
2794   leveldb::Status s = DeleteRangeBasic(
2795       leveldb_transaction, index_meta_data_start, index_meta_data_end, true);
2796
2797   if (s.ok()) {
2798     const std::string index_data_start =
2799         IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
2800     const std::string index_data_end =
2801         IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
2802     s = DeleteRangeBasic(
2803         leveldb_transaction, index_data_start, index_data_end, true);
2804   }
2805
2806   if (!s.ok())
2807     INTERNAL_WRITE_ERROR_UNTESTED(DELETE_INDEX);
2808
2809   return s;
2810 }
2811
2812 leveldb::Status IndexedDBBackingStore::PutIndexDataForRecord(
2813     IndexedDBBackingStore::Transaction* transaction,
2814     int64 database_id,
2815     int64 object_store_id,
2816     int64 index_id,
2817     const IndexedDBKey& key,
2818     const RecordIdentifier& record_identifier) {
2819   IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord");
2820   DCHECK(key.IsValid());
2821   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2822     return InvalidDBKeyStatus();
2823
2824   std::string encoded_key;
2825   EncodeIDBKey(key, &encoded_key);
2826
2827   const std::string index_data_key =
2828       IndexDataKey::Encode(database_id,
2829                            object_store_id,
2830                            index_id,
2831                            encoded_key,
2832                            record_identifier.primary_key(),
2833                            0);
2834
2835   std::string data;
2836   EncodeVarInt(record_identifier.version(), &data);
2837   data.append(record_identifier.primary_key());
2838
2839   transaction->transaction()->Put(index_data_key, &data);
2840   return leveldb::Status::OK();
2841 }
2842
2843 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
2844                                            const std::string& target,
2845                                            std::string* found_key,
2846                                            leveldb::Status* s) {
2847   scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
2848   *s = it->Seek(target);
2849   if (!s->ok())
2850     return false;
2851
2852   if (!it->IsValid()) {
2853     *s = it->SeekToLast();
2854     if (!s->ok() || !it->IsValid())
2855       return false;
2856   }
2857
2858   while (CompareIndexKeys(it->Key(), target) > 0) {
2859     *s = it->Prev();
2860     if (!s->ok() || !it->IsValid())
2861       return false;
2862   }
2863
2864   do {
2865     *found_key = it->Key().as_string();
2866
2867     // There can be several index keys that compare equal. We want the last one.
2868     *s = it->Next();
2869   } while (s->ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target));
2870
2871   return true;
2872 }
2873
2874 static leveldb::Status VersionExists(LevelDBTransaction* transaction,
2875                                      int64 database_id,
2876                                      int64 object_store_id,
2877                                      int64 version,
2878                                      const std::string& encoded_primary_key,
2879                                      bool* exists) {
2880   const std::string key =
2881       ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key);
2882   std::string data;
2883
2884   leveldb::Status s = transaction->Get(key, &data, exists);
2885   if (!s.ok()) {
2886     INTERNAL_READ_ERROR_UNTESTED(VERSION_EXISTS);
2887     return s;
2888   }
2889   if (!*exists)
2890     return s;
2891
2892   StringPiece slice(data);
2893   int64 decoded;
2894   if (!DecodeInt(&slice, &decoded) || !slice.empty())
2895     return InternalInconsistencyStatus();
2896   *exists = (decoded == version);
2897   return s;
2898 }
2899
2900 leveldb::Status IndexedDBBackingStore::FindKeyInIndex(
2901     IndexedDBBackingStore::Transaction* transaction,
2902     int64 database_id,
2903     int64 object_store_id,
2904     int64 index_id,
2905     const IndexedDBKey& key,
2906     std::string* found_encoded_primary_key,
2907     bool* found) {
2908   IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex");
2909   DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id));
2910
2911   DCHECK(found_encoded_primary_key->empty());
2912   *found = false;
2913
2914   LevelDBTransaction* leveldb_transaction = transaction->transaction();
2915   const std::string leveldb_key =
2916       IndexDataKey::Encode(database_id, object_store_id, index_id, key);
2917   scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
2918   leveldb::Status s = it->Seek(leveldb_key);
2919   if (!s.ok()) {
2920     INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
2921     return s;
2922   }
2923
2924   for (;;) {
2925     if (!it->IsValid())
2926       return leveldb::Status::OK();
2927     if (CompareIndexKeys(it->Key(), leveldb_key) > 0)
2928       return leveldb::Status::OK();
2929
2930     StringPiece slice(it->Value());
2931
2932     int64 version;
2933     if (!DecodeVarInt(&slice, &version)) {
2934       INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
2935       return InternalInconsistencyStatus();
2936     }
2937     *found_encoded_primary_key = slice.as_string();
2938
2939     bool exists = false;
2940     s = VersionExists(leveldb_transaction,
2941                       database_id,
2942                       object_store_id,
2943                       version,
2944                       *found_encoded_primary_key,
2945                       &exists);
2946     if (!s.ok())
2947       return s;
2948     if (!exists) {
2949       // Delete stale index data entry and continue.
2950       leveldb_transaction->Remove(it->Key());
2951       s = it->Next();
2952       continue;
2953     }
2954     *found = true;
2955     return s;
2956   }
2957 }
2958
2959 leveldb::Status IndexedDBBackingStore::GetPrimaryKeyViaIndex(
2960     IndexedDBBackingStore::Transaction* transaction,
2961     int64 database_id,
2962     int64 object_store_id,
2963     int64 index_id,
2964     const IndexedDBKey& key,
2965     scoped_ptr<IndexedDBKey>* primary_key) {
2966   IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex");
2967   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2968     return InvalidDBKeyStatus();
2969
2970   bool found = false;
2971   std::string found_encoded_primary_key;
2972   leveldb::Status s = FindKeyInIndex(transaction,
2973                                      database_id,
2974                                      object_store_id,
2975                                      index_id,
2976                                      key,
2977                                      &found_encoded_primary_key,
2978                                      &found);
2979   if (!s.ok()) {
2980     INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
2981     return s;
2982   }
2983   if (!found)
2984     return s;
2985   if (!found_encoded_primary_key.size()) {
2986     INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
2987     return InvalidDBKeyStatus();
2988   }
2989
2990   StringPiece slice(found_encoded_primary_key);
2991   if (DecodeIDBKey(&slice, primary_key) && slice.empty())
2992     return s;
2993   else
2994     return InvalidDBKeyStatus();
2995 }
2996
2997 leveldb::Status IndexedDBBackingStore::KeyExistsInIndex(
2998     IndexedDBBackingStore::Transaction* transaction,
2999     int64 database_id,
3000     int64 object_store_id,
3001     int64 index_id,
3002     const IndexedDBKey& index_key,
3003     scoped_ptr<IndexedDBKey>* found_primary_key,
3004     bool* exists) {
3005   IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex");
3006   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
3007     return InvalidDBKeyStatus();
3008
3009   *exists = false;
3010   std::string found_encoded_primary_key;
3011   leveldb::Status s = FindKeyInIndex(transaction,
3012                                      database_id,
3013                                      object_store_id,
3014                                      index_id,
3015                                      index_key,
3016                                      &found_encoded_primary_key,
3017                                      exists);
3018   if (!s.ok()) {
3019     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
3020     return s;
3021   }
3022   if (!*exists)
3023     return leveldb::Status::OK();
3024   if (found_encoded_primary_key.empty()) {
3025     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
3026     return InvalidDBKeyStatus();
3027   }
3028
3029   StringPiece slice(found_encoded_primary_key);
3030   if (DecodeIDBKey(&slice, found_primary_key) && slice.empty())
3031     return s;
3032   else
3033     return InvalidDBKeyStatus();
3034 }
3035
3036 IndexedDBBackingStore::Cursor::Cursor(
3037     const IndexedDBBackingStore::Cursor* other)
3038     : backing_store_(other->backing_store_),
3039       transaction_(other->transaction_),
3040       database_id_(other->database_id_),
3041       cursor_options_(other->cursor_options_),
3042       current_key_(new IndexedDBKey(*other->current_key_)) {
3043   if (other->iterator_) {
3044     iterator_ = transaction_->transaction()->CreateIterator();
3045
3046     if (other->iterator_->IsValid()) {
3047       leveldb::Status s = iterator_->Seek(other->iterator_->Key());
3048       // TODO(cmumford): Handle this error (crbug.com/363397)
3049       DCHECK(iterator_->IsValid());
3050     }
3051   }
3052 }
3053
3054 IndexedDBBackingStore::Cursor::Cursor(
3055     scoped_refptr<IndexedDBBackingStore> backing_store,
3056     IndexedDBBackingStore::Transaction* transaction,
3057     int64 database_id,
3058     const CursorOptions& cursor_options)
3059     : backing_store_(backing_store),
3060       transaction_(transaction),
3061       database_id_(database_id),
3062       cursor_options_(cursor_options) {
3063 }
3064 IndexedDBBackingStore::Cursor::~Cursor() {}
3065
3066 bool IndexedDBBackingStore::Cursor::FirstSeek(leveldb::Status* s) {
3067   iterator_ = transaction_->transaction()->CreateIterator();
3068   if (cursor_options_.forward)
3069     *s = iterator_->Seek(cursor_options_.low_key);
3070   else
3071     *s = iterator_->Seek(cursor_options_.high_key);
3072   if (!s->ok())
3073     return false;
3074
3075   return Continue(0, READY, s);
3076 }
3077
3078 bool IndexedDBBackingStore::Cursor::Advance(uint32 count, leveldb::Status* s) {
3079   *s = leveldb::Status::OK();
3080   while (count--) {
3081     if (!Continue(s))
3082       return false;
3083   }
3084   return true;
3085 }
3086
3087 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
3088                                              const IndexedDBKey* primary_key,
3089                                              IteratorState next_state,
3090                                              leveldb::Status* s) {
3091   DCHECK(!key || key->IsValid());
3092   DCHECK(!primary_key || primary_key->IsValid());
3093   *s = leveldb::Status::OK();
3094
3095   // TODO(alecflett): avoid a copy here?
3096   IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
3097
3098   // When iterating with PrevNoDuplicate, spec requires that the
3099   // value we yield for each key is the first duplicate in forwards
3100   // order.
3101   IndexedDBKey last_duplicate_key;
3102
3103   bool forward = cursor_options_.forward;
3104   bool first_iteration_forward = forward;
3105   bool flipped = false;
3106
3107   for (;;) {
3108     if (next_state == SEEK) {
3109       // TODO(jsbell): Optimize seeking for reverse cursors as well.
3110       if (first_iteration_forward && key) {
3111         first_iteration_forward = false;
3112         std::string leveldb_key;
3113         if (primary_key) {
3114           leveldb_key = EncodeKey(*key, *primary_key);
3115         } else {
3116           leveldb_key = EncodeKey(*key);
3117         }
3118         *s = iterator_->Seek(leveldb_key);
3119       } else if (forward) {
3120         *s = iterator_->Next();
3121       } else {
3122         *s = iterator_->Prev();
3123       }
3124       if (!s->ok())
3125         return false;
3126     } else {
3127       next_state = SEEK;  // for subsequent iterations
3128     }
3129
3130     if (!iterator_->IsValid()) {
3131       if (!forward && last_duplicate_key.IsValid()) {
3132         // We need to walk forward because we hit the end of
3133         // the data.
3134         forward = true;
3135         flipped = true;
3136         continue;
3137       }
3138
3139       return false;
3140     }
3141
3142     if (IsPastBounds()) {
3143       if (!forward && last_duplicate_key.IsValid()) {
3144         // We need to walk forward because now we're beyond the
3145         // bounds defined by the cursor.
3146         forward = true;
3147         flipped = true;
3148         continue;
3149       }
3150
3151       return false;
3152     }
3153
3154     if (!HaveEnteredRange())
3155       continue;
3156
3157     // The row may not load because there's a stale entry in the
3158     // index. This is not fatal.
3159     if (!LoadCurrentRow())
3160       continue;
3161
3162     if (key) {
3163       if (forward) {
3164         if (primary_key && current_key_->Equals(*key) &&
3165             this->primary_key().IsLessThan(*primary_key))
3166           continue;
3167         if (!flipped && current_key_->IsLessThan(*key))
3168           continue;
3169       } else {
3170         if (primary_key && key->Equals(*current_key_) &&
3171             primary_key->IsLessThan(this->primary_key()))
3172           continue;
3173         if (key->IsLessThan(*current_key_))
3174           continue;
3175       }
3176     }
3177
3178     if (cursor_options_.unique) {
3179       if (previous_key.IsValid() && current_key_->Equals(previous_key)) {
3180         // We should never be able to walk forward all the way
3181         // to the previous key.
3182         DCHECK(!last_duplicate_key.IsValid());
3183         continue;
3184       }
3185
3186       if (!forward) {
3187         if (!last_duplicate_key.IsValid()) {
3188           last_duplicate_key = *current_key_;
3189           continue;
3190         }
3191
3192         // We need to walk forward because we hit the boundary
3193         // between key ranges.
3194         if (!last_duplicate_key.Equals(*current_key_)) {
3195           forward = true;
3196           flipped = true;
3197           continue;
3198         }
3199
3200         continue;
3201       }
3202     }
3203     break;
3204   }
3205
3206   DCHECK(!last_duplicate_key.IsValid() ||
3207          (forward && last_duplicate_key.Equals(*current_key_)));
3208   return true;
3209 }
3210
3211 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const {
3212   if (cursor_options_.forward) {
3213     int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
3214     if (cursor_options_.low_open) {
3215       return compare > 0;
3216     }
3217     return compare >= 0;
3218   }
3219   int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
3220   if (cursor_options_.high_open) {
3221     return compare < 0;
3222   }
3223   return compare <= 0;
3224 }
3225
3226 bool IndexedDBBackingStore::Cursor::IsPastBounds() const {
3227   if (cursor_options_.forward) {
3228     int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
3229     if (cursor_options_.high_open) {
3230       return compare >= 0;
3231     }
3232     return compare > 0;
3233   }
3234   int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
3235   if (cursor_options_.low_open) {
3236     return compare <= 0;
3237   }
3238   return compare < 0;
3239 }
3240
3241 const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const {
3242   return *current_key_;
3243 }
3244
3245 const IndexedDBBackingStore::RecordIdentifier&
3246 IndexedDBBackingStore::Cursor::record_identifier() const {
3247   return record_identifier_;
3248 }
3249
3250 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor {
3251  public:
3252   ObjectStoreKeyCursorImpl(
3253       scoped_refptr<IndexedDBBackingStore> backing_store,
3254       IndexedDBBackingStore::Transaction* transaction,
3255       int64 database_id,
3256       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3257       : IndexedDBBackingStore::Cursor(backing_store,
3258                                       transaction,
3259                                       database_id,
3260                                       cursor_options) {}
3261
3262   virtual Cursor* Clone() OVERRIDE {
3263     return new ObjectStoreKeyCursorImpl(this);
3264   }
3265
3266   // IndexedDBBackingStore::Cursor
3267   virtual IndexedDBValue* value() OVERRIDE {
3268     NOTREACHED();
3269     return NULL;
3270   }
3271   virtual bool LoadCurrentRow() OVERRIDE;
3272
3273  protected:
3274   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3275     return ObjectStoreDataKey::Encode(
3276         cursor_options_.database_id, cursor_options_.object_store_id, key);
3277   }
3278   virtual std::string EncodeKey(const IndexedDBKey& key,
3279                                 const IndexedDBKey& primary_key) OVERRIDE {
3280     NOTREACHED();
3281     return std::string();
3282   }
3283
3284  private:
3285   explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other)
3286       : IndexedDBBackingStore::Cursor(other) {}
3287
3288   DISALLOW_COPY_AND_ASSIGN(ObjectStoreKeyCursorImpl);
3289 };
3290
3291 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() {
3292   StringPiece slice(iterator_->Key());
3293   ObjectStoreDataKey object_store_data_key;
3294   if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) {
3295     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3296     return false;
3297   }
3298
3299   current_key_ = object_store_data_key.user_key();
3300
3301   int64 version;
3302   slice = StringPiece(iterator_->Value());
3303   if (!DecodeVarInt(&slice, &version)) {
3304     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3305     return false;
3306   }
3307
3308   // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
3309   std::string encoded_key;
3310   EncodeIDBKey(*current_key_, &encoded_key);
3311   record_identifier_.Reset(encoded_key, version);
3312
3313   return true;
3314 }
3315
3316 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor {
3317  public:
3318   ObjectStoreCursorImpl(
3319       scoped_refptr<IndexedDBBackingStore> backing_store,
3320       IndexedDBBackingStore::Transaction* transaction,
3321       int64 database_id,
3322       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3323       : IndexedDBBackingStore::Cursor(backing_store,
3324                                       transaction,
3325                                       database_id,
3326                                       cursor_options) {}
3327
3328   virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); }
3329
3330   // IndexedDBBackingStore::Cursor
3331   virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
3332   virtual bool LoadCurrentRow() OVERRIDE;
3333
3334  protected:
3335   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3336     return ObjectStoreDataKey::Encode(
3337         cursor_options_.database_id, cursor_options_.object_store_id, key);
3338   }
3339   virtual std::string EncodeKey(const IndexedDBKey& key,
3340                                 const IndexedDBKey& primary_key) OVERRIDE {
3341     NOTREACHED();
3342     return std::string();
3343   }
3344
3345  private:
3346   explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other)
3347       : IndexedDBBackingStore::Cursor(other),
3348         current_value_(other->current_value_) {}
3349
3350   IndexedDBValue current_value_;
3351
3352   DISALLOW_COPY_AND_ASSIGN(ObjectStoreCursorImpl);
3353 };
3354
3355 bool ObjectStoreCursorImpl::LoadCurrentRow() {
3356   StringPiece key_slice(iterator_->Key());
3357   ObjectStoreDataKey object_store_data_key;
3358   if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) {
3359     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3360     return false;
3361   }
3362
3363   current_key_ = object_store_data_key.user_key();
3364
3365   int64 version;
3366   StringPiece value_slice = StringPiece(iterator_->Value());
3367   if (!DecodeVarInt(&value_slice, &version)) {
3368     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3369     return false;
3370   }
3371
3372   // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
3373   std::string encoded_key;
3374   EncodeIDBKey(*current_key_, &encoded_key);
3375   record_identifier_.Reset(encoded_key, version);
3376
3377   if (!transaction_->GetBlobInfoForRecord(database_id_,
3378                                           iterator_->Key().as_string(),
3379                                           &current_value_).ok()) {
3380     return false;
3381   }
3382   current_value_.bits = value_slice.as_string();
3383   return true;
3384 }
3385
3386 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor {
3387  public:
3388   IndexKeyCursorImpl(
3389       scoped_refptr<IndexedDBBackingStore> backing_store,
3390       IndexedDBBackingStore::Transaction* transaction,
3391       int64 database_id,
3392       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3393       : IndexedDBBackingStore::Cursor(backing_store,
3394                                       transaction,
3395                                       database_id,
3396                                       cursor_options) {}
3397
3398   virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); }
3399
3400   // IndexedDBBackingStore::Cursor
3401   virtual IndexedDBValue* value() OVERRIDE {
3402     NOTREACHED();
3403     return NULL;
3404   }
3405   virtual const IndexedDBKey& primary_key() const OVERRIDE {
3406     return *primary_key_;
3407   }
3408   virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
3409       const OVERRIDE {
3410     NOTREACHED();
3411     return record_identifier_;
3412   }
3413   virtual bool LoadCurrentRow() OVERRIDE;
3414
3415  protected:
3416   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3417     return IndexDataKey::Encode(cursor_options_.database_id,
3418                                 cursor_options_.object_store_id,
3419                                 cursor_options_.index_id,
3420                                 key);
3421   }
3422   virtual std::string EncodeKey(const IndexedDBKey& key,
3423                                 const IndexedDBKey& primary_key) OVERRIDE {
3424     return IndexDataKey::Encode(cursor_options_.database_id,
3425                                 cursor_options_.object_store_id,
3426                                 cursor_options_.index_id,
3427                                 key,
3428                                 primary_key);
3429   }
3430
3431  private:
3432   explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other)
3433       : IndexedDBBackingStore::Cursor(other),
3434         primary_key_(new IndexedDBKey(*other->primary_key_)) {}
3435
3436   scoped_ptr<IndexedDBKey> primary_key_;
3437
3438   DISALLOW_COPY_AND_ASSIGN(IndexKeyCursorImpl);
3439 };
3440
3441 bool IndexKeyCursorImpl::LoadCurrentRow() {
3442   StringPiece slice(iterator_->Key());
3443   IndexDataKey index_data_key;
3444   if (!IndexDataKey::Decode(&slice, &index_data_key)) {
3445     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3446     return false;
3447   }
3448
3449   current_key_ = index_data_key.user_key();
3450   DCHECK(current_key_);
3451
3452   slice = StringPiece(iterator_->Value());
3453   int64 index_data_version;
3454   if (!DecodeVarInt(&slice, &index_data_version)) {
3455     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3456     return false;
3457   }
3458
3459   if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) {
3460     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3461     return false;
3462   }
3463
3464   std::string primary_leveldb_key =
3465       ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
3466                                  index_data_key.ObjectStoreId(),
3467                                  *primary_key_);
3468
3469   std::string result;
3470   bool found = false;
3471   leveldb::Status s =
3472       transaction_->transaction()->Get(primary_leveldb_key, &result, &found);
3473   if (!s.ok()) {
3474     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3475     return false;
3476   }
3477   if (!found) {
3478     transaction_->transaction()->Remove(iterator_->Key());
3479     return false;
3480   }
3481   if (!result.size()) {
3482     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3483     return false;
3484   }
3485
3486   int64 object_store_data_version;
3487   slice = StringPiece(result);
3488   if (!DecodeVarInt(&slice, &object_store_data_version)) {
3489     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3490     return false;
3491   }
3492
3493   if (object_store_data_version != index_data_version) {
3494     transaction_->transaction()->Remove(iterator_->Key());
3495     return false;
3496   }
3497
3498   return true;
3499 }
3500
3501 class IndexCursorImpl : public IndexedDBBackingStore::Cursor {
3502  public:
3503   IndexCursorImpl(
3504       scoped_refptr<IndexedDBBackingStore> backing_store,
3505       IndexedDBBackingStore::Transaction* transaction,
3506       int64 database_id,
3507       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
3508       : IndexedDBBackingStore::Cursor(backing_store,
3509                                       transaction,
3510                                       database_id,
3511                                       cursor_options) {}
3512
3513   virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); }
3514
3515   // IndexedDBBackingStore::Cursor
3516   virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
3517   virtual const IndexedDBKey& primary_key() const OVERRIDE {
3518     return *primary_key_;
3519   }
3520   virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
3521       const OVERRIDE {
3522     NOTREACHED();
3523     return record_identifier_;
3524   }
3525   virtual bool LoadCurrentRow() OVERRIDE;
3526
3527  protected:
3528   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
3529     return IndexDataKey::Encode(cursor_options_.database_id,
3530                                 cursor_options_.object_store_id,
3531                                 cursor_options_.index_id,
3532                                 key);
3533   }
3534   virtual std::string EncodeKey(const IndexedDBKey& key,
3535                                 const IndexedDBKey& primary_key) OVERRIDE {
3536     return IndexDataKey::Encode(cursor_options_.database_id,
3537                                 cursor_options_.object_store_id,
3538                                 cursor_options_.index_id,
3539                                 key,
3540                                 primary_key);
3541   }
3542
3543  private:
3544   explicit IndexCursorImpl(const IndexCursorImpl* other)
3545       : IndexedDBBackingStore::Cursor(other),
3546         primary_key_(new IndexedDBKey(*other->primary_key_)),
3547         current_value_(other->current_value_),
3548         primary_leveldb_key_(other->primary_leveldb_key_) {}
3549
3550   scoped_ptr<IndexedDBKey> primary_key_;
3551   IndexedDBValue current_value_;
3552   std::string primary_leveldb_key_;
3553
3554   DISALLOW_COPY_AND_ASSIGN(IndexCursorImpl);
3555 };
3556
3557 bool IndexCursorImpl::LoadCurrentRow() {
3558   StringPiece slice(iterator_->Key());
3559   IndexDataKey index_data_key;
3560   if (!IndexDataKey::Decode(&slice, &index_data_key)) {
3561     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3562     return false;
3563   }
3564
3565   current_key_ = index_data_key.user_key();
3566   DCHECK(current_key_);
3567
3568   slice = StringPiece(iterator_->Value());
3569   int64 index_data_version;
3570   if (!DecodeVarInt(&slice, &index_data_version)) {
3571     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3572     return false;
3573   }
3574   if (!DecodeIDBKey(&slice, &primary_key_)) {
3575     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3576     return false;
3577   }
3578
3579   DCHECK_EQ(index_data_key.DatabaseId(), database_id_);
3580   primary_leveldb_key_ =
3581       ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
3582                                  index_data_key.ObjectStoreId(),
3583                                  *primary_key_);
3584
3585   std::string result;
3586   bool found = false;
3587   leveldb::Status s =
3588       transaction_->transaction()->Get(primary_leveldb_key_, &result, &found);
3589   if (!s.ok()) {
3590     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3591     return false;
3592   }
3593   if (!found) {
3594     transaction_->transaction()->Remove(iterator_->Key());
3595     return false;
3596   }
3597   if (!result.size()) {
3598     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3599     return false;
3600   }
3601
3602   int64 object_store_data_version;
3603   slice = StringPiece(result);
3604   if (!DecodeVarInt(&slice, &object_store_data_version)) {
3605     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
3606     return false;
3607   }
3608
3609   if (object_store_data_version != index_data_version) {
3610     transaction_->transaction()->Remove(iterator_->Key());
3611     return false;
3612   }
3613
3614   current_value_.bits = slice.as_string();
3615   return transaction_->GetBlobInfoForRecord(database_id_,
3616                                             primary_leveldb_key_,
3617                                             &current_value_).ok();
3618 }
3619
3620 bool ObjectStoreCursorOptions(
3621     LevelDBTransaction* transaction,
3622     int64 database_id,
3623     int64 object_store_id,
3624     const IndexedDBKeyRange& range,
3625     blink::WebIDBCursorDirection direction,
3626     IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
3627   cursor_options->database_id = database_id;
3628   cursor_options->object_store_id = object_store_id;
3629
3630   bool lower_bound = range.lower().IsValid();
3631   bool upper_bound = range.upper().IsValid();
3632   cursor_options->forward =
3633       (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3634        direction == blink::WebIDBCursorDirectionNext);
3635   cursor_options->unique =
3636       (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3637        direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
3638
3639   if (!lower_bound) {
3640     cursor_options->low_key =
3641         ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
3642     cursor_options->low_open = true;  // Not included.
3643   } else {
3644     cursor_options->low_key =
3645         ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower());
3646     cursor_options->low_open = range.lowerOpen();
3647   }
3648
3649   leveldb::Status s;
3650
3651   if (!upper_bound) {
3652     cursor_options->high_key =
3653         ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
3654
3655     if (cursor_options->forward) {
3656       cursor_options->high_open = true;  // Not included.
3657     } else {
3658       // We need a key that exists.
3659       // TODO(cmumford): Handle this error (crbug.com/363397)
3660       if (!FindGreatestKeyLessThanOrEqual(transaction,
3661                                           cursor_options->high_key,
3662                                           &cursor_options->high_key,
3663                                           &s))
3664         return false;
3665       cursor_options->high_open = false;
3666     }
3667   } else {
3668     cursor_options->high_key =
3669         ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper());
3670     cursor_options->high_open = range.upperOpen();
3671
3672     if (!cursor_options->forward) {
3673       // For reverse cursors, we need a key that exists.
3674       std::string found_high_key;
3675       // TODO(cmumford): Handle this error (crbug.com/363397)
3676       if (!FindGreatestKeyLessThanOrEqual(
3677               transaction, cursor_options->high_key, &found_high_key, &s))
3678         return false;
3679
3680       // If the target key should not be included, but we end up with a smaller
3681       // key, we should include that.
3682       if (cursor_options->high_open &&
3683           CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
3684         cursor_options->high_open = false;
3685
3686       cursor_options->high_key = found_high_key;
3687     }
3688   }
3689
3690   return true;
3691 }
3692
3693 bool IndexCursorOptions(
3694     LevelDBTransaction* transaction,
3695     int64 database_id,
3696     int64 object_store_id,
3697     int64 index_id,
3698     const IndexedDBKeyRange& range,
3699     blink::WebIDBCursorDirection direction,
3700     IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
3701   DCHECK(transaction);
3702   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
3703     return false;
3704
3705   cursor_options->database_id = database_id;
3706   cursor_options->object_store_id = object_store_id;
3707   cursor_options->index_id = index_id;
3708
3709   bool lower_bound = range.lower().IsValid();
3710   bool upper_bound = range.upper().IsValid();
3711   cursor_options->forward =
3712       (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3713        direction == blink::WebIDBCursorDirectionNext);
3714   cursor_options->unique =
3715       (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
3716        direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
3717
3718   if (!lower_bound) {
3719     cursor_options->low_key =
3720         IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
3721     cursor_options->low_open = false;  // Included.
3722   } else {
3723     cursor_options->low_key = IndexDataKey::Encode(
3724         database_id, object_store_id, index_id, range.lower());
3725     cursor_options->low_open = range.lowerOpen();
3726   }
3727
3728   leveldb::Status s;
3729
3730   if (!upper_bound) {
3731     cursor_options->high_key =
3732         IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
3733     cursor_options->high_open = false;  // Included.
3734
3735     if (!cursor_options->forward) {  // We need a key that exists.
3736       if (!FindGreatestKeyLessThanOrEqual(transaction,
3737                                           cursor_options->high_key,
3738                                           &cursor_options->high_key,
3739                                           &s))
3740         return false;
3741       cursor_options->high_open = false;
3742     }
3743   } else {
3744     cursor_options->high_key = IndexDataKey::Encode(
3745         database_id, object_store_id, index_id, range.upper());
3746     cursor_options->high_open = range.upperOpen();
3747
3748     std::string found_high_key;
3749     // Seek to the *last* key in the set of non-unique keys
3750     // TODO(cmumford): Handle this error (crbug.com/363397)
3751     if (!FindGreatestKeyLessThanOrEqual(
3752             transaction, cursor_options->high_key, &found_high_key, &s))
3753       return false;
3754
3755     // If the target key should not be included, but we end up with a smaller
3756     // key, we should include that.
3757     if (cursor_options->high_open &&
3758         CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
3759       cursor_options->high_open = false;
3760
3761     cursor_options->high_key = found_high_key;
3762   }
3763
3764   return true;
3765 }
3766
3767 scoped_ptr<IndexedDBBackingStore::Cursor>
3768 IndexedDBBackingStore::OpenObjectStoreCursor(
3769     IndexedDBBackingStore::Transaction* transaction,
3770     int64 database_id,
3771     int64 object_store_id,
3772     const IndexedDBKeyRange& range,
3773     blink::WebIDBCursorDirection direction,
3774     leveldb::Status* s) {
3775   IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor");
3776   *s = leveldb::Status::OK();
3777   LevelDBTransaction* leveldb_transaction = transaction->transaction();
3778   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3779   if (!ObjectStoreCursorOptions(leveldb_transaction,
3780                                 database_id,
3781                                 object_store_id,
3782                                 range,
3783                                 direction,
3784                                 &cursor_options))
3785     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3786   scoped_ptr<ObjectStoreCursorImpl> cursor(new ObjectStoreCursorImpl(
3787       this, transaction, database_id, cursor_options));
3788   if (!cursor->FirstSeek(s))
3789     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3790
3791   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3792 }
3793
3794 scoped_ptr<IndexedDBBackingStore::Cursor>
3795 IndexedDBBackingStore::OpenObjectStoreKeyCursor(
3796     IndexedDBBackingStore::Transaction* transaction,
3797     int64 database_id,
3798     int64 object_store_id,
3799     const IndexedDBKeyRange& range,
3800     blink::WebIDBCursorDirection direction,
3801     leveldb::Status* s) {
3802   IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor");
3803   *s = leveldb::Status::OK();
3804   LevelDBTransaction* leveldb_transaction = transaction->transaction();
3805   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3806   if (!ObjectStoreCursorOptions(leveldb_transaction,
3807                                 database_id,
3808                                 object_store_id,
3809                                 range,
3810                                 direction,
3811                                 &cursor_options))
3812     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3813   scoped_ptr<ObjectStoreKeyCursorImpl> cursor(new ObjectStoreKeyCursorImpl(
3814       this, transaction, database_id, cursor_options));
3815   if (!cursor->FirstSeek(s))
3816     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3817
3818   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3819 }
3820
3821 scoped_ptr<IndexedDBBackingStore::Cursor>
3822 IndexedDBBackingStore::OpenIndexKeyCursor(
3823     IndexedDBBackingStore::Transaction* transaction,
3824     int64 database_id,
3825     int64 object_store_id,
3826     int64 index_id,
3827     const IndexedDBKeyRange& range,
3828     blink::WebIDBCursorDirection direction,
3829     leveldb::Status* s) {
3830   IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor");
3831   *s = leveldb::Status::OK();
3832   LevelDBTransaction* leveldb_transaction = transaction->transaction();
3833   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3834   if (!IndexCursorOptions(leveldb_transaction,
3835                           database_id,
3836                           object_store_id,
3837                           index_id,
3838                           range,
3839                           direction,
3840                           &cursor_options))
3841     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3842   scoped_ptr<IndexKeyCursorImpl> cursor(
3843       new IndexKeyCursorImpl(this, transaction, database_id, cursor_options));
3844   if (!cursor->FirstSeek(s))
3845     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3846
3847   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3848 }
3849
3850 scoped_ptr<IndexedDBBackingStore::Cursor>
3851 IndexedDBBackingStore::OpenIndexCursor(
3852     IndexedDBBackingStore::Transaction* transaction,
3853     int64 database_id,
3854     int64 object_store_id,
3855     int64 index_id,
3856     const IndexedDBKeyRange& range,
3857     blink::WebIDBCursorDirection direction,
3858     leveldb::Status* s) {
3859   IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor");
3860   LevelDBTransaction* leveldb_transaction = transaction->transaction();
3861   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
3862   if (!IndexCursorOptions(leveldb_transaction,
3863                           database_id,
3864                           object_store_id,
3865                           index_id,
3866                           range,
3867                           direction,
3868                           &cursor_options))
3869     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3870   scoped_ptr<IndexCursorImpl> cursor(
3871       new IndexCursorImpl(this, transaction, database_id, cursor_options));
3872   if (!cursor->FirstSeek(s))
3873     return scoped_ptr<IndexedDBBackingStore::Cursor>();
3874
3875   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
3876 }
3877
3878 IndexedDBBackingStore::Transaction::Transaction(
3879     IndexedDBBackingStore* backing_store)
3880     : backing_store_(backing_store), database_id_(-1) {
3881 }
3882
3883 IndexedDBBackingStore::Transaction::~Transaction() {
3884   STLDeleteContainerPairSecondPointers(
3885       blob_change_map_.begin(), blob_change_map_.end());
3886   STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
3887                                        incognito_blob_map_.end());
3888 }
3889
3890 void IndexedDBBackingStore::Transaction::Begin() {
3891   IDB_TRACE("IndexedDBBackingStore::Transaction::Begin");
3892   DCHECK(!transaction_.get());
3893   transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
3894       backing_store_->db_.get());
3895
3896   // If incognito, this snapshots blobs just as the above transaction_
3897   // constructor snapshots the leveldb.
3898   BlobChangeMap::const_iterator iter;
3899   for (iter = backing_store_->incognito_blob_map_.begin();
3900        iter != backing_store_->incognito_blob_map_.end();
3901        ++iter)
3902     incognito_blob_map_[iter->first] = iter->second->Clone().release();
3903 }
3904
3905 static GURL getURLFromUUID(const string& uuid) {
3906   return GURL("blob:uuid/" + uuid);
3907 }
3908
3909 leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
3910     BlobEntryKeyValuePairVec* new_blob_entries,
3911     WriteDescriptorVec* new_files_to_write) {
3912   if (backing_store_->is_incognito())
3913     return leveldb::Status::OK();
3914
3915   BlobChangeMap::iterator iter = blob_change_map_.begin();
3916   new_blob_entries->clear();
3917   new_files_to_write->clear();
3918   if (iter != blob_change_map_.end()) {
3919     // Create LevelDBTransaction for the name generator seed and add-journal.
3920     scoped_refptr<LevelDBTransaction> pre_transaction =
3921         IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
3922             backing_store_->db_.get());
3923     BlobJournalType journal;
3924     for (; iter != blob_change_map_.end(); ++iter) {
3925       std::vector<IndexedDBBlobInfo>::iterator info_iter;
3926       std::vector<IndexedDBBlobInfo*> new_blob_keys;
3927       for (info_iter = iter->second->mutable_blob_info().begin();
3928            info_iter != iter->second->mutable_blob_info().end();
3929            ++info_iter) {
3930         int64 next_blob_key = -1;
3931         bool result = GetBlobKeyGeneratorCurrentNumber(
3932             pre_transaction.get(), database_id_, &next_blob_key);
3933         if (!result || next_blob_key < 0)
3934           return InternalInconsistencyStatus();
3935         BlobJournalEntryType journal_entry =
3936             std::make_pair(database_id_, next_blob_key);
3937         journal.push_back(journal_entry);
3938         if (info_iter->is_file()) {
3939           new_files_to_write->push_back(
3940               WriteDescriptor(info_iter->file_path(),
3941                               next_blob_key,
3942                               info_iter->size(),
3943                               info_iter->last_modified()));
3944         } else {
3945           new_files_to_write->push_back(
3946               WriteDescriptor(getURLFromUUID(info_iter->uuid()),
3947                               next_blob_key,
3948                               info_iter->size()));
3949         }
3950         info_iter->set_key(next_blob_key);
3951         new_blob_keys.push_back(&*info_iter);
3952         result = UpdateBlobKeyGeneratorCurrentNumber(
3953             pre_transaction.get(), database_id_, next_blob_key + 1);
3954         if (!result)
3955           return InternalInconsistencyStatus();
3956       }
3957       BlobEntryKey blob_entry_key;
3958       StringPiece key_piece(iter->second->key());
3959       if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
3960         NOTREACHED();
3961         return InternalInconsistencyStatus();
3962       }
3963       new_blob_entries->push_back(
3964           std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys)));
3965     }
3966     UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal);
3967     leveldb::Status s = pre_transaction->Commit();
3968     if (!s.ok())
3969       return InternalInconsistencyStatus();
3970   }
3971   return leveldb::Status::OK();
3972 }
3973
3974 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
3975   if (backing_store_->is_incognito())
3976     return true;
3977
3978   BlobChangeMap::const_iterator iter = blob_change_map_.begin();
3979   // Look up all old files to remove as part of the transaction, store their
3980   // names in blobs_to_remove_, and remove their old blob data entries.
3981   if (iter != blob_change_map_.end()) {
3982     scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator();
3983     for (; iter != blob_change_map_.end(); ++iter) {
3984       BlobEntryKey blob_entry_key;
3985       StringPiece key_piece(iter->second->key());
3986       if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
3987         NOTREACHED();
3988         INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
3989         transaction_ = NULL;
3990         return false;
3991       }
3992       if (database_id_ < 0)
3993         database_id_ = blob_entry_key.database_id();
3994       else
3995         DCHECK_EQ(database_id_, blob_entry_key.database_id());
3996       std::string blob_entry_key_bytes = blob_entry_key.Encode();
3997       db_iter->Seek(blob_entry_key_bytes);
3998       if (db_iter->IsValid() &&
3999           !CompareKeys(db_iter->Key(), blob_entry_key_bytes)) {
4000         std::vector<IndexedDBBlobInfo> blob_info;
4001         if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) {
4002           INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4003           transaction_ = NULL;
4004           return false;
4005         }
4006         std::vector<IndexedDBBlobInfo>::iterator blob_info_iter;
4007         for (blob_info_iter = blob_info.begin();
4008              blob_info_iter != blob_info.end();
4009              ++blob_info_iter)
4010           blobs_to_remove_.push_back(
4011               std::make_pair(database_id_, blob_info_iter->key()));
4012         transaction_->Remove(blob_entry_key_bytes);
4013       }
4014     }
4015   }
4016   return true;
4017 }
4018
4019 leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
4020   IndexedDBActiveBlobRegistry* registry =
4021       backing_store_->active_blob_registry();
4022   BlobJournalType::iterator iter;
4023   BlobJournalType primary_journal, live_blob_journal;
4024   for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end();
4025        ++iter) {
4026     if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second))
4027       live_blob_journal.push_back(*iter);
4028     else
4029       primary_journal.push_back(*iter);
4030   }
4031   UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal);
4032   leveldb::Status s =
4033       MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal);
4034   if (!s.ok())
4035     return s;
4036   // To signal how many blobs need attention right now.
4037   blobs_to_remove_.swap(primary_journal);
4038   return leveldb::Status::OK();
4039 }
4040
4041 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
4042     scoped_refptr<BlobWriteCallback> callback) {
4043   IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne");
4044   DCHECK(transaction_);
4045   DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
4046
4047   leveldb::Status s;
4048
4049   s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
4050   if (!s.ok()) {
4051     INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
4052     transaction_ = NULL;
4053     return s;
4054   }
4055
4056   BlobEntryKeyValuePairVec new_blob_entries;
4057   WriteDescriptorVec new_files_to_write;
4058   s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write);
4059   if (!s.ok()) {
4060     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4061     transaction_ = NULL;
4062     return s;
4063   }
4064
4065   DCHECK(!new_files_to_write.size() ||
4066          KeyPrefix::IsValidDatabaseId(database_id_));
4067   if (!CollectBlobFilesToRemove()) {
4068     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4069     transaction_ = NULL;
4070     return InternalInconsistencyStatus();
4071   }
4072
4073   if (new_files_to_write.size()) {
4074     // This kicks off the writes of the new blobs, if any.
4075     // This call will zero out new_blob_entries and new_files_to_write.
4076     WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback);
4077     // Remove the add journal, if any; once the blobs are written, and we
4078     // commit, this will do the cleanup.
4079     ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode());
4080   } else {
4081     callback->Run(true);
4082   }
4083
4084   return leveldb::Status::OK();
4085 }
4086
4087 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
4088   IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo");
4089   leveldb::Status s;
4090   if (blobs_to_remove_.size()) {
4091     s = SortBlobsToRemove();
4092     if (!s.ok()) {
4093       INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
4094       transaction_ = NULL;
4095       return s;
4096     }
4097   }
4098
4099   s = transaction_->Commit();
4100   transaction_ = NULL;
4101
4102   if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) {
4103     BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
4104     BlobChangeMap::iterator iter;
4105     for (iter = blob_change_map_.begin(); iter != blob_change_map_.end();
4106          ++iter) {
4107       BlobChangeMap::iterator target_record = target_map.find(iter->first);
4108       if (target_record != target_map.end()) {
4109         delete target_record->second;
4110         target_map.erase(target_record);
4111       }
4112       if (iter->second) {
4113         target_map[iter->first] = iter->second;
4114         iter->second = NULL;
4115       }
4116     }
4117   }
4118   if (!s.ok())
4119     INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
4120   else if (blobs_to_remove_.size())
4121     s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
4122
4123   return s;
4124 }
4125
4126
4127 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
4128     : public IndexedDBBackingStore::BlobWriteCallback {
4129  public:
4130   BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction,
4131                            scoped_refptr<BlobWriteCallback> callback)
4132       : transaction_(transaction), callback_(callback) {}
4133   virtual void Run(bool succeeded) OVERRIDE {
4134     callback_->Run(succeeded);
4135     if (succeeded)  // Else it's already been deleted during rollback.
4136       transaction_->chained_blob_writer_ = NULL;
4137   }
4138
4139  private:
4140   virtual ~BlobWriteCallbackWrapper() {}
4141   friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>;
4142
4143   IndexedDBBackingStore::Transaction* transaction_;
4144   scoped_refptr<BlobWriteCallback> callback_;
4145
4146   DISALLOW_COPY_AND_ASSIGN(BlobWriteCallbackWrapper);
4147 };
4148
4149 void IndexedDBBackingStore::Transaction::WriteNewBlobs(
4150     BlobEntryKeyValuePairVec* new_blob_entries,
4151     WriteDescriptorVec* new_files_to_write,
4152     scoped_refptr<BlobWriteCallback> callback) {
4153   DCHECK_GT(new_files_to_write->size(), 0UL);
4154   DCHECK_GT(database_id_, 0);
4155   BlobEntryKeyValuePairVec::iterator blob_entry_iter;
4156   for (blob_entry_iter = new_blob_entries->begin();
4157        blob_entry_iter != new_blob_entries->end();
4158        ++blob_entry_iter) {
4159     // Add the new blob-table entry for each blob to the main transaction, or
4160     // remove any entry that may exist if there's no new one.
4161     if (!blob_entry_iter->second.size())
4162       transaction_->Remove(blob_entry_iter->first.Encode());
4163     else
4164       transaction_->Put(blob_entry_iter->first.Encode(),
4165                         &blob_entry_iter->second);
4166   }
4167   // Creating the writer will start it going asynchronously.
4168   chained_blob_writer_ =
4169       new ChainedBlobWriterImpl(database_id_,
4170                                 backing_store_,
4171                                 new_files_to_write,
4172                                 new BlobWriteCallbackWrapper(this, callback));
4173 }
4174
4175 void IndexedDBBackingStore::Transaction::Rollback() {
4176   IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
4177   if (chained_blob_writer_) {
4178     chained_blob_writer_->Abort();
4179     chained_blob_writer_ = NULL;
4180   }
4181   if (transaction_.get() == NULL)
4182     return;
4183   transaction_->Rollback();
4184   transaction_ = NULL;
4185 }
4186
4187 IndexedDBBackingStore::BlobChangeRecord::BlobChangeRecord(
4188     const std::string& key,
4189     int64 object_store_id)
4190     : key_(key), object_store_id_(object_store_id) {
4191 }
4192
4193 IndexedDBBackingStore::BlobChangeRecord::~BlobChangeRecord() {
4194 }
4195
4196 void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo(
4197     std::vector<IndexedDBBlobInfo>* blob_info) {
4198   blob_info_.clear();
4199   if (blob_info)
4200     blob_info_.swap(*blob_info);
4201 }
4202
4203 void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
4204     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
4205   handles_.clear();
4206   if (handles)
4207     handles_.swap(*handles);
4208 }
4209
4210 scoped_ptr<IndexedDBBackingStore::BlobChangeRecord>
4211 IndexedDBBackingStore::BlobChangeRecord::Clone() const {
4212   scoped_ptr<IndexedDBBackingStore::BlobChangeRecord> record(
4213       new BlobChangeRecord(key_, object_store_id_));
4214   record->blob_info_ = blob_info_;
4215
4216   ScopedVector<webkit_blob::BlobDataHandle>::const_iterator iter;
4217   for (iter = handles_.begin(); iter != handles_.end(); ++iter)
4218     record->handles_.push_back(new webkit_blob::BlobDataHandle(**iter));
4219   return record.Pass();
4220 }
4221
4222 leveldb::Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
4223     int64 database_id,
4224     int64 object_store_id,
4225     const std::string& object_store_data_key,
4226     std::vector<IndexedDBBlobInfo>* blob_info,
4227     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
4228   if (!blob_info || blob_info->empty()) {
4229     blob_change_map_.erase(object_store_data_key);
4230     incognito_blob_map_.erase(object_store_data_key);
4231
4232     BlobEntryKey blob_entry_key;
4233     StringPiece leveldb_key_piece(object_store_data_key);
4234     if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
4235                                               &blob_entry_key)) {
4236       NOTREACHED();
4237       return InternalInconsistencyStatus();
4238     }
4239     std::string value;
4240     bool found = false;
4241     leveldb::Status s =
4242         transaction()->Get(blob_entry_key.Encode(), &value, &found);
4243     if (!s.ok())
4244       return s;
4245     if (!found)
4246       return leveldb::Status::OK();
4247   }
4248   PutBlobInfo(
4249       database_id, object_store_id, object_store_data_key, blob_info, handles);
4250   return leveldb::Status::OK();
4251 }
4252
4253 // This is storing an info, even if empty, even if the previous key had no blob
4254 // info that we know of.  It duplicates a bunch of information stored in the
4255 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the
4256 // changes to exists or index keys here.
4257 void IndexedDBBackingStore::Transaction::PutBlobInfo(
4258     int64 database_id,
4259     int64 object_store_id,
4260     const std::string& object_store_data_key,
4261     std::vector<IndexedDBBlobInfo>* blob_info,
4262     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
4263   DCHECK_GT(object_store_data_key.size(), 0UL);
4264   if (database_id_ < 0)
4265     database_id_ = database_id;
4266   DCHECK_EQ(database_id_, database_id);
4267
4268   BlobChangeMap::iterator it = blob_change_map_.find(object_store_data_key);
4269   BlobChangeRecord* record = NULL;
4270   if (it == blob_change_map_.end()) {
4271     record = new BlobChangeRecord(object_store_data_key, object_store_id);
4272     blob_change_map_[object_store_data_key] = record;
4273   } else {
4274     record = it->second;
4275   }
4276   DCHECK_EQ(record->object_store_id(), object_store_id);
4277   record->SetBlobInfo(blob_info);
4278   record->SetHandles(handles);
4279   DCHECK(!handles || !handles->size());
4280 }
4281
4282 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
4283     const GURL& url,
4284     int64_t key,
4285     int64_t size)
4286     : is_file_(false), url_(url), key_(key), size_(size) {
4287 }
4288
4289 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
4290     const FilePath& file_path,
4291     int64_t key,
4292     int64_t size,
4293     base::Time last_modified)
4294     : is_file_(true),
4295       file_path_(file_path),
4296       key_(key),
4297       size_(size),
4298       last_modified_(last_modified) {
4299 }
4300
4301 }  // namespace content