Home | History | Annotate | Download | only in indexed_db
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_
      6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "base/basictypes.h"
     15 #include "base/files/file_path.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/strings/string_piece.h"
     19 #include "base/time/time.h"
     20 #include "base/timer/timer.h"
     21 #include "content/browser/indexed_db/indexed_db.h"
     22 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
     23 #include "content/browser/indexed_db/indexed_db_blob_info.h"
     24 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
     25 #include "content/browser/indexed_db/indexed_db_metadata.h"
     26 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
     27 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
     28 #include "content/common/content_export.h"
     29 #include "content/common/indexed_db/indexed_db_key.h"
     30 #include "content/common/indexed_db/indexed_db_key_path.h"
     31 #include "content/common/indexed_db/indexed_db_key_range.h"
     32 #include "storage/browser/blob/blob_data_handle.h"
     33 #include "third_party/leveldatabase/src/include/leveldb/status.h"
     34 #include "url/gurl.h"
     35 
     36 namespace base {
     37 class SequencedTaskRunner;
     38 }
     39 
     40 namespace storage {
     41 class FileWriterDelegate;
     42 }
     43 
     44 namespace net {
     45 class URLRequestContext;
     46 }
     47 
     48 namespace content {
     49 
     50 class IndexedDBFactory;
     51 class LevelDBComparator;
     52 class LevelDBDatabase;
     53 class LevelDBFactory;
     54 struct IndexedDBValue;
     55 
     56 class CONTENT_EXPORT IndexedDBBackingStore
     57     : public base::RefCounted<IndexedDBBackingStore> {
     58  public:
     59   class CONTENT_EXPORT Comparator : public LevelDBComparator {
     60    public:
     61     virtual int Compare(const base::StringPiece& a,
     62                         const base::StringPiece& b) const OVERRIDE;
     63     virtual const char* Name() const OVERRIDE;
     64   };
     65 
     66   class CONTENT_EXPORT RecordIdentifier {
     67    public:
     68     RecordIdentifier(const std::string& primary_key, int64 version);
     69     RecordIdentifier();
     70     ~RecordIdentifier();
     71 
     72     const std::string& primary_key() const { return primary_key_; }
     73     int64 version() const { return version_; }
     74     void Reset(const std::string& primary_key, int64 version) {
     75       primary_key_ = primary_key;
     76       version_ = version;
     77     }
     78 
     79    private:
     80     // TODO(jsbell): Make it more clear that this is the *encoded* version of
     81     // the key.
     82     std::string primary_key_;
     83     int64 version_;
     84     DISALLOW_COPY_AND_ASSIGN(RecordIdentifier);
     85   };
     86 
     87   class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> {
     88    public:
     89     virtual void Run(bool succeeded) = 0;
     90 
     91    protected:
     92     friend class base::RefCounted<BlobWriteCallback>;
     93     virtual ~BlobWriteCallback() {}
     94   };
     95 
     96   class BlobChangeRecord {
     97    public:
     98     BlobChangeRecord(const std::string& key, int64 object_store_id);
     99     ~BlobChangeRecord();
    100 
    101     const std::string& key() const { return key_; }
    102     int64 object_store_id() const { return object_store_id_; }
    103     void SetBlobInfo(std::vector<IndexedDBBlobInfo>* blob_info);
    104     std::vector<IndexedDBBlobInfo>& mutable_blob_info() { return blob_info_; }
    105     const std::vector<IndexedDBBlobInfo>& blob_info() const {
    106       return blob_info_;
    107     }
    108     void SetHandles(ScopedVector<storage::BlobDataHandle>* handles);
    109     scoped_ptr<BlobChangeRecord> Clone() const;
    110 
    111    private:
    112     std::string key_;
    113     int64 object_store_id_;
    114     std::vector<IndexedDBBlobInfo> blob_info_;
    115     ScopedVector<storage::BlobDataHandle> handles_;
    116     DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord);
    117   };
    118   typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap;
    119 
    120   class CONTENT_EXPORT Transaction {
    121    public:
    122     explicit Transaction(IndexedDBBackingStore* backing_store);
    123     virtual ~Transaction();
    124 
    125     virtual void Begin();
    126     // The callback will be called eventually on success or failure, or
    127     // immediately if phase one is complete due to lack of any blobs to write.
    128     virtual leveldb::Status CommitPhaseOne(scoped_refptr<BlobWriteCallback>);
    129     virtual leveldb::Status CommitPhaseTwo();
    130     virtual void Rollback();
    131     void Reset() {
    132       backing_store_ = NULL;
    133       transaction_ = NULL;
    134     }
    135     leveldb::Status PutBlobInfoIfNeeded(
    136         int64 database_id,
    137         int64 object_store_id,
    138         const std::string& object_store_data_key,
    139         std::vector<IndexedDBBlobInfo>*,
    140         ScopedVector<storage::BlobDataHandle>* handles);
    141     void PutBlobInfo(int64 database_id,
    142                      int64 object_store_id,
    143                      const std::string& object_store_data_key,
    144                      std::vector<IndexedDBBlobInfo>*,
    145                      ScopedVector<storage::BlobDataHandle>* handles);
    146 
    147     LevelDBTransaction* transaction() { return transaction_.get(); }
    148 
    149     leveldb::Status GetBlobInfoForRecord(
    150         int64 database_id,
    151         const std::string& object_store_data_key,
    152         IndexedDBValue* value);
    153 
    154     // This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored
    155     // under that key.
    156     typedef std::vector<std::pair<BlobEntryKey, std::string> >
    157         BlobEntryKeyValuePairVec;
    158 
    159     class WriteDescriptor {
    160      public:
    161       WriteDescriptor(const GURL& url, int64_t key, int64_t size);
    162       WriteDescriptor(const base::FilePath& path,
    163                       int64_t key,
    164                       int64_t size,
    165                       base::Time last_modified);
    166 
    167       bool is_file() const { return is_file_; }
    168       const GURL& url() const {
    169         DCHECK(!is_file_);
    170         return url_;
    171       }
    172       const base::FilePath& file_path() const {
    173         DCHECK(is_file_);
    174         return file_path_;
    175       }
    176       int64_t key() const { return key_; }
    177       int64_t size() const { return size_; }
    178       base::Time last_modified() const { return last_modified_; }
    179 
    180      private:
    181       bool is_file_;
    182       GURL url_;
    183       base::FilePath file_path_;
    184       int64_t key_;
    185       int64_t size_;
    186       base::Time last_modified_;
    187     };
    188 
    189     class ChainedBlobWriter
    190         : public base::RefCountedThreadSafe<ChainedBlobWriter> {
    191      public:
    192       virtual void set_delegate(
    193           scoped_ptr<storage::FileWriterDelegate> delegate) = 0;
    194 
    195       // TODO(ericu): Add a reason in the event of failure.
    196       virtual void ReportWriteCompletion(bool succeeded,
    197                                          int64 bytes_written) = 0;
    198 
    199       virtual void Abort() = 0;
    200 
    201      protected:
    202       friend class base::RefCountedThreadSafe<ChainedBlobWriter>;
    203       virtual ~ChainedBlobWriter() {}
    204     };
    205 
    206     class ChainedBlobWriterImpl;
    207 
    208     typedef std::vector<WriteDescriptor> WriteDescriptorVec;
    209 
    210    private:
    211     class BlobWriteCallbackWrapper;
    212 
    213     leveldb::Status HandleBlobPreTransaction(
    214         BlobEntryKeyValuePairVec* new_blob_entries,
    215         WriteDescriptorVec* new_files_to_write);
    216     // Returns true on success, false on failure.
    217     bool CollectBlobFilesToRemove();
    218     // The callback will be called eventually on success or failure.
    219     void WriteNewBlobs(BlobEntryKeyValuePairVec* new_blob_entries,
    220                        WriteDescriptorVec* new_files_to_write,
    221                        scoped_refptr<BlobWriteCallback> callback);
    222     leveldb::Status SortBlobsToRemove();
    223 
    224     IndexedDBBackingStore* backing_store_;
    225     scoped_refptr<LevelDBTransaction> transaction_;
    226     BlobChangeMap blob_change_map_;
    227     BlobChangeMap incognito_blob_map_;
    228     int64 database_id_;
    229     BlobJournalType blobs_to_remove_;
    230     scoped_refptr<ChainedBlobWriter> chained_blob_writer_;
    231   };
    232 
    233   class Cursor {
    234    public:
    235     enum IteratorState { READY = 0, SEEK };
    236 
    237     virtual ~Cursor();
    238 
    239     struct CursorOptions {
    240       CursorOptions();
    241       ~CursorOptions();
    242       int64 database_id;
    243       int64 object_store_id;
    244       int64 index_id;
    245       std::string low_key;
    246       bool low_open;
    247       std::string high_key;
    248       bool high_open;
    249       bool forward;
    250       bool unique;
    251     };
    252 
    253     const IndexedDBKey& key() const { return *current_key_; }
    254     bool Continue(leveldb::Status* s) { return Continue(NULL, NULL, SEEK, s); }
    255     bool Continue(const IndexedDBKey* key,
    256                   IteratorState state,
    257                   leveldb::Status* s) {
    258       return Continue(key, NULL, state, s);
    259     }
    260     bool Continue(const IndexedDBKey* key,
    261                   const IndexedDBKey* primary_key,
    262                   IteratorState state,
    263                   leveldb::Status*);
    264     bool Advance(uint32 count, leveldb::Status*);
    265     bool FirstSeek(leveldb::Status*);
    266 
    267     virtual Cursor* Clone() = 0;
    268     virtual const IndexedDBKey& primary_key() const;
    269     virtual IndexedDBValue* value() = 0;
    270     virtual const RecordIdentifier& record_identifier() const;
    271     virtual bool LoadCurrentRow() = 0;
    272 
    273    protected:
    274     Cursor(scoped_refptr<IndexedDBBackingStore> backing_store,
    275            Transaction* transaction,
    276            int64 database_id,
    277            const CursorOptions& cursor_options);
    278     explicit Cursor(const IndexedDBBackingStore::Cursor* other);
    279 
    280     virtual std::string EncodeKey(const IndexedDBKey& key) = 0;
    281     virtual std::string EncodeKey(const IndexedDBKey& key,
    282                                   const IndexedDBKey& primary_key) = 0;
    283 
    284     bool IsPastBounds() const;
    285     bool HaveEnteredRange() const;
    286 
    287     IndexedDBBackingStore* backing_store_;
    288     Transaction* transaction_;
    289     int64 database_id_;
    290     const CursorOptions cursor_options_;
    291     scoped_ptr<LevelDBIterator> iterator_;
    292     scoped_ptr<IndexedDBKey> current_key_;
    293     IndexedDBBackingStore::RecordIdentifier record_identifier_;
    294 
    295    private:
    296     DISALLOW_COPY_AND_ASSIGN(Cursor);
    297   };
    298 
    299   const GURL& origin_url() const { return origin_url_; }
    300   IndexedDBFactory* factory() const { return indexed_db_factory_; }
    301   base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
    302   base::OneShotTimer<IndexedDBBackingStore>* close_timer() {
    303     return &close_timer_;
    304   }
    305   IndexedDBActiveBlobRegistry* active_blob_registry() {
    306     return &active_blob_registry_;
    307   }
    308 
    309   static scoped_refptr<IndexedDBBackingStore> Open(
    310       IndexedDBFactory* indexed_db_factory,
    311       const GURL& origin_url,
    312       const base::FilePath& path_base,
    313       net::URLRequestContext* request_context,
    314       blink::WebIDBDataLoss* data_loss,
    315       std::string* data_loss_message,
    316       bool* disk_full,
    317       base::SequencedTaskRunner* task_runner,
    318       bool clean_journal,
    319       leveldb::Status* status);
    320   static scoped_refptr<IndexedDBBackingStore> Open(
    321       IndexedDBFactory* indexed_db_factory,
    322       const GURL& origin_url,
    323       const base::FilePath& path_base,
    324       net::URLRequestContext* request_context,
    325       blink::WebIDBDataLoss* data_loss,
    326       std::string* data_loss_message,
    327       bool* disk_full,
    328       LevelDBFactory* leveldb_factory,
    329       base::SequencedTaskRunner* task_runner,
    330       bool clean_journal,
    331       leveldb::Status* status);
    332   static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
    333       const GURL& origin_url,
    334       base::SequencedTaskRunner* task_runner,
    335       leveldb::Status* status);
    336   static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
    337       const GURL& origin_url,
    338       LevelDBFactory* leveldb_factory,
    339       base::SequencedTaskRunner* task_runner,
    340       leveldb::Status* status);
    341 
    342   void GrantChildProcessPermissions(int child_process_id);
    343 
    344   // Compact is public for testing.
    345   virtual void Compact();
    346   virtual std::vector<base::string16> GetDatabaseNames(leveldb::Status*);
    347   virtual leveldb::Status GetIDBDatabaseMetaData(
    348       const base::string16& name,
    349       IndexedDBDatabaseMetadata* metadata,
    350       bool* success) WARN_UNUSED_RESULT;
    351   virtual leveldb::Status CreateIDBDatabaseMetaData(
    352       const base::string16& name,
    353       const base::string16& version,
    354       int64 int_version,
    355       int64* row_id);
    356   virtual bool UpdateIDBDatabaseIntVersion(
    357       IndexedDBBackingStore::Transaction* transaction,
    358       int64 row_id,
    359       int64 int_version);
    360   virtual leveldb::Status DeleteDatabase(const base::string16& name);
    361 
    362   // Assumes caller has already closed the backing store.
    363   static leveldb::Status DestroyBackingStore(const base::FilePath& path_base,
    364                                              const GURL& origin_url);
    365   static bool RecordCorruptionInfo(const base::FilePath& path_base,
    366                                    const GURL& origin_url,
    367                                    const std::string& message);
    368   leveldb::Status GetObjectStores(
    369       int64 database_id,
    370       IndexedDBDatabaseMetadata::ObjectStoreMap* map) WARN_UNUSED_RESULT;
    371   virtual leveldb::Status CreateObjectStore(
    372       IndexedDBBackingStore::Transaction* transaction,
    373       int64 database_id,
    374       int64 object_store_id,
    375       const base::string16& name,
    376       const IndexedDBKeyPath& key_path,
    377       bool auto_increment);
    378   virtual leveldb::Status DeleteObjectStore(
    379       IndexedDBBackingStore::Transaction* transaction,
    380       int64 database_id,
    381       int64 object_store_id) WARN_UNUSED_RESULT;
    382 
    383   virtual leveldb::Status GetRecord(
    384       IndexedDBBackingStore::Transaction* transaction,
    385       int64 database_id,
    386       int64 object_store_id,
    387       const IndexedDBKey& key,
    388       IndexedDBValue* record) WARN_UNUSED_RESULT;
    389   virtual leveldb::Status PutRecord(
    390       IndexedDBBackingStore::Transaction* transaction,
    391       int64 database_id,
    392       int64 object_store_id,
    393       const IndexedDBKey& key,
    394       IndexedDBValue* value,
    395       ScopedVector<storage::BlobDataHandle>* handles,
    396       RecordIdentifier* record) WARN_UNUSED_RESULT;
    397   virtual leveldb::Status ClearObjectStore(
    398       IndexedDBBackingStore::Transaction* transaction,
    399       int64 database_id,
    400       int64 object_store_id) WARN_UNUSED_RESULT;
    401   virtual leveldb::Status DeleteRecord(
    402       IndexedDBBackingStore::Transaction* transaction,
    403       int64 database_id,
    404       int64 object_store_id,
    405       const RecordIdentifier& record) WARN_UNUSED_RESULT;
    406   virtual leveldb::Status DeleteRange(
    407       IndexedDBBackingStore::Transaction* transaction,
    408       int64 database_id,
    409       int64 object_store_id,
    410       const IndexedDBKeyRange&) WARN_UNUSED_RESULT;
    411   virtual leveldb::Status GetKeyGeneratorCurrentNumber(
    412       IndexedDBBackingStore::Transaction* transaction,
    413       int64 database_id,
    414       int64 object_store_id,
    415       int64* current_number) WARN_UNUSED_RESULT;
    416   virtual leveldb::Status MaybeUpdateKeyGeneratorCurrentNumber(
    417       IndexedDBBackingStore::Transaction* transaction,
    418       int64 database_id,
    419       int64 object_store_id,
    420       int64 new_state,
    421       bool check_current) WARN_UNUSED_RESULT;
    422   virtual leveldb::Status KeyExistsInObjectStore(
    423       IndexedDBBackingStore::Transaction* transaction,
    424       int64 database_id,
    425       int64 object_store_id,
    426       const IndexedDBKey& key,
    427       RecordIdentifier* found_record_identifier,
    428       bool* found) WARN_UNUSED_RESULT;
    429 
    430   virtual leveldb::Status CreateIndex(
    431       IndexedDBBackingStore::Transaction* transaction,
    432       int64 database_id,
    433       int64 object_store_id,
    434       int64 index_id,
    435       const base::string16& name,
    436       const IndexedDBKeyPath& key_path,
    437       bool is_unique,
    438       bool is_multi_entry) WARN_UNUSED_RESULT;
    439   virtual leveldb::Status DeleteIndex(
    440       IndexedDBBackingStore::Transaction* transaction,
    441       int64 database_id,
    442       int64 object_store_id,
    443       int64 index_id) WARN_UNUSED_RESULT;
    444   virtual leveldb::Status PutIndexDataForRecord(
    445       IndexedDBBackingStore::Transaction* transaction,
    446       int64 database_id,
    447       int64 object_store_id,
    448       int64 index_id,
    449       const IndexedDBKey& key,
    450       const RecordIdentifier& record) WARN_UNUSED_RESULT;
    451   virtual leveldb::Status GetPrimaryKeyViaIndex(
    452       IndexedDBBackingStore::Transaction* transaction,
    453       int64 database_id,
    454       int64 object_store_id,
    455       int64 index_id,
    456       const IndexedDBKey& key,
    457       scoped_ptr<IndexedDBKey>* primary_key) WARN_UNUSED_RESULT;
    458   virtual leveldb::Status KeyExistsInIndex(
    459       IndexedDBBackingStore::Transaction* transaction,
    460       int64 database_id,
    461       int64 object_store_id,
    462       int64 index_id,
    463       const IndexedDBKey& key,
    464       scoped_ptr<IndexedDBKey>* found_primary_key,
    465       bool* exists) WARN_UNUSED_RESULT;
    466 
    467   // Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
    468   virtual void ReportBlobUnused(int64 database_id, int64 blob_key);
    469 
    470   base::FilePath GetBlobFileName(int64 database_id, int64 key);
    471 
    472   virtual scoped_ptr<Cursor> OpenObjectStoreKeyCursor(
    473       IndexedDBBackingStore::Transaction* transaction,
    474       int64 database_id,
    475       int64 object_store_id,
    476       const IndexedDBKeyRange& key_range,
    477       blink::WebIDBCursorDirection,
    478       leveldb::Status*);
    479   virtual scoped_ptr<Cursor> OpenObjectStoreCursor(
    480       IndexedDBBackingStore::Transaction* transaction,
    481       int64 database_id,
    482       int64 object_store_id,
    483       const IndexedDBKeyRange& key_range,
    484       blink::WebIDBCursorDirection,
    485       leveldb::Status*);
    486   virtual scoped_ptr<Cursor> OpenIndexKeyCursor(
    487       IndexedDBBackingStore::Transaction* transaction,
    488       int64 database_id,
    489       int64 object_store_id,
    490       int64 index_id,
    491       const IndexedDBKeyRange& key_range,
    492       blink::WebIDBCursorDirection,
    493       leveldb::Status*);
    494   virtual scoped_ptr<Cursor> OpenIndexCursor(
    495       IndexedDBBackingStore::Transaction* transaction,
    496       int64 database_id,
    497       int64 object_store_id,
    498       int64 index_id,
    499       const IndexedDBKeyRange& key_range,
    500       blink::WebIDBCursorDirection,
    501       leveldb::Status*);
    502 
    503  protected:
    504   friend class base::RefCounted<IndexedDBBackingStore>;
    505 
    506   IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory,
    507                         const GURL& origin_url,
    508                         const base::FilePath& blob_path,
    509                         net::URLRequestContext* request_context,
    510                         scoped_ptr<LevelDBDatabase> db,
    511                         scoped_ptr<LevelDBComparator> comparator,
    512                         base::SequencedTaskRunner* task_runner);
    513   virtual ~IndexedDBBackingStore();
    514 
    515   bool is_incognito() const { return !indexed_db_factory_; }
    516 
    517   leveldb::Status SetUpMetadata();
    518 
    519   virtual bool WriteBlobFile(
    520       int64 database_id,
    521       const Transaction::WriteDescriptor& descriptor,
    522       Transaction::ChainedBlobWriter* chained_blob_writer);
    523   virtual bool RemoveBlobFile(int64 database_id, int64 key);
    524   virtual void StartJournalCleaningTimer();
    525   void CleanPrimaryJournalIgnoreReturn();
    526 
    527  private:
    528   static scoped_refptr<IndexedDBBackingStore> Create(
    529       IndexedDBFactory* indexed_db_factory,
    530       const GURL& origin_url,
    531       const base::FilePath& blob_path,
    532       net::URLRequestContext* request_context,
    533       scoped_ptr<LevelDBDatabase> db,
    534       scoped_ptr<LevelDBComparator> comparator,
    535       base::SequencedTaskRunner* task_runner,
    536       leveldb::Status* status);
    537 
    538   static bool ReadCorruptionInfo(const base::FilePath& path_base,
    539                                  const GURL& origin_url,
    540                                  std::string* message);
    541 
    542   leveldb::Status FindKeyInIndex(
    543       IndexedDBBackingStore::Transaction* transaction,
    544       int64 database_id,
    545       int64 object_store_id,
    546       int64 index_id,
    547       const IndexedDBKey& key,
    548       std::string* found_encoded_primary_key,
    549       bool* found);
    550   leveldb::Status GetIndexes(int64 database_id,
    551                              int64 object_store_id,
    552                              IndexedDBObjectStoreMetadata::IndexMap* map)
    553       WARN_UNUSED_RESULT;
    554   bool RemoveBlobDirectory(int64 database_id);
    555   leveldb::Status CleanUpBlobJournal(const std::string& level_db_key);
    556 
    557   IndexedDBFactory* indexed_db_factory_;
    558   const GURL origin_url_;
    559   base::FilePath blob_path_;
    560 
    561   // The origin identifier is a key prefix unique to the origin used in the
    562   // leveldb backing store to partition data by origin. It is a normalized
    563   // version of the origin URL with a versioning suffix appended, e.g.
    564   // "http_localhost_81@1" Since only one origin is stored per backing store
    565   // this is redundant but necessary for backwards compatibility; the suffix
    566   // provides for future flexibility.
    567   const std::string origin_identifier_;
    568 
    569   net::URLRequestContext* request_context_;
    570   scoped_refptr<base::SequencedTaskRunner> task_runner_;
    571   std::set<int> child_process_ids_granted_;
    572   BlobChangeMap incognito_blob_map_;
    573   base::OneShotTimer<IndexedDBBackingStore> journal_cleaning_timer_;
    574 
    575   scoped_ptr<LevelDBDatabase> db_;
    576   scoped_ptr<LevelDBComparator> comparator_;
    577   // Whenever blobs are registered in active_blob_registry_, indexed_db_factory_
    578   // will hold a reference to this backing store.
    579   IndexedDBActiveBlobRegistry active_blob_registry_;
    580   base::OneShotTimer<IndexedDBBackingStore> close_timer_;
    581 
    582   DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStore);
    583 };
    584 
    585 }  // namespace content
    586 
    587 #endif  // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_
    588