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.
5 #ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_
6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_
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/memory/scoped_vector.h"
19 #include "base/strings/string_piece.h"
20 #include "base/time/time.h"
21 #include "base/timer/timer.h"
22 #include "content/browser/indexed_db/indexed_db.h"
23 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
24 #include "content/browser/indexed_db/indexed_db_blob_info.h"
25 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
26 #include "content/browser/indexed_db/indexed_db_metadata.h"
27 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
28 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
29 #include "content/common/content_export.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 "storage/browser/blob/blob_data_handle.h"
34 #include "third_party/leveldatabase/src/include/leveldb/status.h"
38 class SequencedTaskRunner
;
42 class FileWriterDelegate
;
46 class URLRequestContext
;
51 class IndexedDBFactory
;
52 class LevelDBComparator
;
53 class LevelDBDatabase
;
55 struct IndexedDBValue
;
57 class CONTENT_EXPORT IndexedDBBackingStore
58 : public base::RefCounted
<IndexedDBBackingStore
> {
60 class CONTENT_EXPORT Comparator
: public LevelDBComparator
{
62 int Compare(const base::StringPiece
& a
,
63 const base::StringPiece
& b
) const override
;
64 const char* Name() const override
;
67 class CONTENT_EXPORT RecordIdentifier
{
69 RecordIdentifier(const std::string
& primary_key
, int64 version
);
73 const std::string
& primary_key() const { return primary_key_
; }
74 int64
version() const { return version_
; }
75 void Reset(const std::string
& primary_key
, int64 version
) {
76 primary_key_
= primary_key
;
81 // TODO(jsbell): Make it more clear that this is the *encoded* version of
83 std::string primary_key_
;
85 DISALLOW_COPY_AND_ASSIGN(RecordIdentifier
);
88 class BlobWriteCallback
: public base::RefCounted
<BlobWriteCallback
> {
90 virtual void Run(bool succeeded
) = 0;
93 friend class base::RefCounted
<BlobWriteCallback
>;
94 virtual ~BlobWriteCallback() {}
97 class BlobChangeRecord
{
99 BlobChangeRecord(const std::string
& key
, int64 object_store_id
);
102 const std::string
& key() const { return key_
; }
103 int64
object_store_id() const { return object_store_id_
; }
104 void SetBlobInfo(std::vector
<IndexedDBBlobInfo
>* blob_info
);
105 std::vector
<IndexedDBBlobInfo
>& mutable_blob_info() { return blob_info_
; }
106 const std::vector
<IndexedDBBlobInfo
>& blob_info() const {
109 void SetHandles(ScopedVector
<storage::BlobDataHandle
>* handles
);
110 scoped_ptr
<BlobChangeRecord
> Clone() const;
114 int64 object_store_id_
;
115 std::vector
<IndexedDBBlobInfo
> blob_info_
;
116 ScopedVector
<storage::BlobDataHandle
> handles_
;
117 DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord
);
119 typedef std::map
<std::string
, BlobChangeRecord
*> BlobChangeMap
;
121 class CONTENT_EXPORT Transaction
{
123 explicit Transaction(IndexedDBBackingStore
* backing_store
);
124 virtual ~Transaction();
126 virtual void Begin();
128 // CommitPhaseOne determines what blobs (if any) need to be written to disk
129 // and updates the primary blob journal, and kicks off the async writing
130 // of the blob files. In case of crash/rollback, the journal indicates what
131 // files should be cleaned up.
132 // The callback will be called eventually on success or failure, or
133 // immediately if phase one is complete due to lack of any blobs to write.
134 virtual leveldb::Status
CommitPhaseOne(scoped_refptr
<BlobWriteCallback
>);
136 // CommitPhaseTwo is called once the blob files (if any) have been written
137 // to disk, and commits the actual transaction to the backing store,
138 // including blob journal updates, then deletes any blob files deleted
139 // by the transaction and not referenced by running scripts.
140 virtual leveldb::Status
CommitPhaseTwo();
142 virtual void Rollback();
144 backing_store_
= NULL
;
147 leveldb::Status
PutBlobInfoIfNeeded(
149 int64 object_store_id
,
150 const std::string
& object_store_data_key
,
151 std::vector
<IndexedDBBlobInfo
>*,
152 ScopedVector
<storage::BlobDataHandle
>* handles
);
153 void PutBlobInfo(int64 database_id
,
154 int64 object_store_id
,
155 const std::string
& object_store_data_key
,
156 std::vector
<IndexedDBBlobInfo
>*,
157 ScopedVector
<storage::BlobDataHandle
>* handles
);
159 LevelDBTransaction
* transaction() { return transaction_
.get(); }
161 leveldb::Status
GetBlobInfoForRecord(
163 const std::string
& object_store_data_key
,
164 IndexedDBValue
* value
);
166 // This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored
168 typedef std::vector
<std::pair
<BlobEntryKey
, std::string
> >
169 BlobEntryKeyValuePairVec
;
171 class CONTENT_EXPORT WriteDescriptor
{
173 WriteDescriptor(const GURL
& url
,
176 base::Time last_modified
);
177 WriteDescriptor(const base::FilePath
& path
,
180 base::Time last_modified
);
181 WriteDescriptor(const WriteDescriptor
& other
);
183 WriteDescriptor
& operator=(const WriteDescriptor
& other
);
185 bool is_file() const { return is_file_
; }
186 const GURL
& url() const {
190 const base::FilePath
& file_path() const {
194 int64_t key() const { return key_
; }
195 int64_t size() const { return size_
; }
196 base::Time
last_modified() const { return last_modified_
; }
201 base::FilePath file_path_
;
204 base::Time last_modified_
;
207 class ChainedBlobWriter
208 : public base::RefCountedThreadSafe
<ChainedBlobWriter
> {
210 virtual void set_delegate(
211 scoped_ptr
<storage::FileWriterDelegate
> delegate
) = 0;
213 // TODO(ericu): Add a reason in the event of failure.
214 virtual void ReportWriteCompletion(bool succeeded
,
215 int64 bytes_written
) = 0;
217 virtual void Abort() = 0;
220 friend class base::RefCountedThreadSafe
<ChainedBlobWriter
>;
221 virtual ~ChainedBlobWriter() {}
224 class ChainedBlobWriterImpl
;
226 typedef std::vector
<WriteDescriptor
> WriteDescriptorVec
;
229 class BlobWriteCallbackWrapper
;
231 // Called by CommitPhaseOne: Identifies the blob entries to write and adds
232 // them to the primary blob journal directly (i.e. not as part of the
233 // transaction). Populates blobs_to_write_.
234 leveldb::Status
HandleBlobPreTransaction(
235 BlobEntryKeyValuePairVec
* new_blob_entries
,
236 WriteDescriptorVec
* new_files_to_write
);
238 // Called by CommitPhaseOne: Populates blob_files_to_remove_ by
239 // determining which blobs are deleted as part of the transaction, and
240 // adds blob entry cleanup operations to the transaction. Returns true on
241 // success, false on failure.
242 bool CollectBlobFilesToRemove();
244 // Called by CommitPhaseOne: Kicks off the asynchronous writes of blobs
245 // identified in HandleBlobPreTransaction. The callback will be called
246 // eventually on success or failure.
247 void WriteNewBlobs(BlobEntryKeyValuePairVec
* new_blob_entries
,
248 WriteDescriptorVec
* new_files_to_write
,
249 scoped_refptr
<BlobWriteCallback
> callback
);
251 // Called by CommitPhaseTwo: Partition blob references in blobs_to_remove_
252 // into live (active references) and dead (no references).
253 void PartitionBlobsToRemove(BlobJournalType
* dead_blobs
,
254 BlobJournalType
* live_blobs
) const;
256 IndexedDBBackingStore
* backing_store_
;
257 scoped_refptr
<LevelDBTransaction
> transaction_
;
258 BlobChangeMap blob_change_map_
;
259 BlobChangeMap incognito_blob_map_
;
262 // List of blob files being newly written as part of this transaction.
263 // These will be added to the primary blob journal prior to commit, then
264 // removed after a sucessful commit.
265 BlobJournalType blobs_to_write_
;
267 // List of blob files being deleted as part of this transaction. These will
268 // be added to either the primary or live blob journal as appropriate
269 // following a successful commit.
270 BlobJournalType blobs_to_remove_
;
271 scoped_refptr
<ChainedBlobWriter
> chained_blob_writer_
;
273 // Set to true between CommitPhaseOne and CommitPhaseTwo/Rollback, to
274 // indicate that the committing_transaction_count_ on the backing store
275 // has been bumped, and journal cleaning should be deferred.
281 enum IteratorState
{ READY
= 0, SEEK
};
285 struct CursorOptions
{
289 int64 object_store_id
;
293 std::string high_key
;
299 const IndexedDBKey
& key() const { return *current_key_
; }
300 bool Continue(leveldb::Status
* s
) { return Continue(NULL
, NULL
, SEEK
, s
); }
301 bool Continue(const IndexedDBKey
* key
,
303 leveldb::Status
* s
) {
304 return Continue(key
, NULL
, state
, s
);
306 bool Continue(const IndexedDBKey
* key
,
307 const IndexedDBKey
* primary_key
,
310 bool Advance(uint32 count
, leveldb::Status
*);
311 bool FirstSeek(leveldb::Status
*);
313 virtual Cursor
* Clone() = 0;
314 virtual const IndexedDBKey
& primary_key() const;
315 virtual IndexedDBValue
* value() = 0;
316 virtual const RecordIdentifier
& record_identifier() const;
317 virtual bool LoadCurrentRow(leveldb::Status
* s
) = 0;
320 Cursor(scoped_refptr
<IndexedDBBackingStore
> backing_store
,
321 Transaction
* transaction
,
323 const CursorOptions
& cursor_options
);
324 explicit Cursor(const IndexedDBBackingStore::Cursor
* other
);
326 virtual std::string
EncodeKey(const IndexedDBKey
& key
) = 0;
327 virtual std::string
EncodeKey(const IndexedDBKey
& key
,
328 const IndexedDBKey
& primary_key
) = 0;
330 bool IsPastBounds() const;
331 bool HaveEnteredRange() const;
333 IndexedDBBackingStore
* backing_store_
;
334 Transaction
* transaction_
;
336 const CursorOptions cursor_options_
;
337 scoped_ptr
<LevelDBIterator
> iterator_
;
338 scoped_ptr
<IndexedDBKey
> current_key_
;
339 IndexedDBBackingStore::RecordIdentifier record_identifier_
;
342 // For cursors with direction Next or NextNoDuplicate.
343 bool ContinueNext(const IndexedDBKey
* key
,
344 const IndexedDBKey
* primary_key
,
347 // For cursors with direction Prev or PrevNoDuplicate. The PrevNoDuplicate
348 // case has additional complexity of not being symmetric with
350 bool ContinuePrevious(const IndexedDBKey
* key
,
351 const IndexedDBKey
* primary_key
,
355 DISALLOW_COPY_AND_ASSIGN(Cursor
);
358 const GURL
& origin_url() const { return origin_url_
; }
359 IndexedDBFactory
* factory() const { return indexed_db_factory_
; }
360 base::SequencedTaskRunner
* task_runner() const { return task_runner_
.get(); }
361 base::OneShotTimer
<IndexedDBBackingStore
>* close_timer() {
362 return &close_timer_
;
364 IndexedDBActiveBlobRegistry
* active_blob_registry() {
365 return &active_blob_registry_
;
368 static scoped_refptr
<IndexedDBBackingStore
> Open(
369 IndexedDBFactory
* indexed_db_factory
,
370 const GURL
& origin_url
,
371 const base::FilePath
& path_base
,
372 net::URLRequestContext
* request_context
,
373 blink::WebIDBDataLoss
* data_loss
,
374 std::string
* data_loss_message
,
376 base::SequencedTaskRunner
* task_runner
,
378 leveldb::Status
* status
);
379 static scoped_refptr
<IndexedDBBackingStore
> Open(
380 IndexedDBFactory
* indexed_db_factory
,
381 const GURL
& origin_url
,
382 const base::FilePath
& path_base
,
383 net::URLRequestContext
* request_context
,
384 blink::WebIDBDataLoss
* data_loss
,
385 std::string
* data_loss_message
,
387 LevelDBFactory
* leveldb_factory
,
388 base::SequencedTaskRunner
* task_runner
,
390 leveldb::Status
* status
);
391 static scoped_refptr
<IndexedDBBackingStore
> OpenInMemory(
392 const GURL
& origin_url
,
393 base::SequencedTaskRunner
* task_runner
,
394 leveldb::Status
* status
);
395 static scoped_refptr
<IndexedDBBackingStore
> OpenInMemory(
396 const GURL
& origin_url
,
397 LevelDBFactory
* leveldb_factory
,
398 base::SequencedTaskRunner
* task_runner
,
399 leveldb::Status
* status
);
401 void GrantChildProcessPermissions(int child_process_id
);
403 // Compact is public for testing.
404 virtual void Compact();
405 virtual std::vector
<base::string16
> GetDatabaseNames(leveldb::Status
*);
406 virtual leveldb::Status
GetIDBDatabaseMetaData(
407 const base::string16
& name
,
408 IndexedDBDatabaseMetadata
* metadata
,
409 bool* success
) WARN_UNUSED_RESULT
;
410 virtual leveldb::Status
CreateIDBDatabaseMetaData(
411 const base::string16
& name
,
412 const base::string16
& version
,
415 virtual bool UpdateIDBDatabaseIntVersion(
416 IndexedDBBackingStore::Transaction
* transaction
,
419 virtual leveldb::Status
DeleteDatabase(const base::string16
& name
);
421 // Assumes caller has already closed the backing store.
422 static leveldb::Status
DestroyBackingStore(const base::FilePath
& path_base
,
423 const GURL
& origin_url
);
424 static bool RecordCorruptionInfo(const base::FilePath
& path_base
,
425 const GURL
& origin_url
,
426 const std::string
& message
);
427 leveldb::Status
GetObjectStores(
429 IndexedDBDatabaseMetadata::ObjectStoreMap
* map
) WARN_UNUSED_RESULT
;
430 virtual leveldb::Status
CreateObjectStore(
431 IndexedDBBackingStore::Transaction
* transaction
,
433 int64 object_store_id
,
434 const base::string16
& name
,
435 const IndexedDBKeyPath
& key_path
,
436 bool auto_increment
);
437 virtual leveldb::Status
DeleteObjectStore(
438 IndexedDBBackingStore::Transaction
* transaction
,
440 int64 object_store_id
) WARN_UNUSED_RESULT
;
442 virtual leveldb::Status
GetRecord(
443 IndexedDBBackingStore::Transaction
* transaction
,
445 int64 object_store_id
,
446 const IndexedDBKey
& key
,
447 IndexedDBValue
* record
) WARN_UNUSED_RESULT
;
448 virtual leveldb::Status
PutRecord(
449 IndexedDBBackingStore::Transaction
* transaction
,
451 int64 object_store_id
,
452 const IndexedDBKey
& key
,
453 IndexedDBValue
* value
,
454 ScopedVector
<storage::BlobDataHandle
>* handles
,
455 RecordIdentifier
* record
) WARN_UNUSED_RESULT
;
456 virtual leveldb::Status
ClearObjectStore(
457 IndexedDBBackingStore::Transaction
* transaction
,
459 int64 object_store_id
) WARN_UNUSED_RESULT
;
460 virtual leveldb::Status
DeleteRecord(
461 IndexedDBBackingStore::Transaction
* transaction
,
463 int64 object_store_id
,
464 const RecordIdentifier
& record
) WARN_UNUSED_RESULT
;
465 virtual leveldb::Status
DeleteRange(
466 IndexedDBBackingStore::Transaction
* transaction
,
468 int64 object_store_id
,
469 const IndexedDBKeyRange
&) WARN_UNUSED_RESULT
;
470 virtual leveldb::Status
GetKeyGeneratorCurrentNumber(
471 IndexedDBBackingStore::Transaction
* transaction
,
473 int64 object_store_id
,
474 int64
* current_number
) WARN_UNUSED_RESULT
;
475 virtual leveldb::Status
MaybeUpdateKeyGeneratorCurrentNumber(
476 IndexedDBBackingStore::Transaction
* transaction
,
478 int64 object_store_id
,
480 bool check_current
) WARN_UNUSED_RESULT
;
481 virtual leveldb::Status
KeyExistsInObjectStore(
482 IndexedDBBackingStore::Transaction
* transaction
,
484 int64 object_store_id
,
485 const IndexedDBKey
& key
,
486 RecordIdentifier
* found_record_identifier
,
487 bool* found
) WARN_UNUSED_RESULT
;
489 virtual leveldb::Status
CreateIndex(
490 IndexedDBBackingStore::Transaction
* transaction
,
492 int64 object_store_id
,
494 const base::string16
& name
,
495 const IndexedDBKeyPath
& key_path
,
497 bool is_multi_entry
) WARN_UNUSED_RESULT
;
498 virtual leveldb::Status
DeleteIndex(
499 IndexedDBBackingStore::Transaction
* transaction
,
501 int64 object_store_id
,
502 int64 index_id
) WARN_UNUSED_RESULT
;
503 virtual leveldb::Status
PutIndexDataForRecord(
504 IndexedDBBackingStore::Transaction
* transaction
,
506 int64 object_store_id
,
508 const IndexedDBKey
& key
,
509 const RecordIdentifier
& record
) WARN_UNUSED_RESULT
;
510 virtual leveldb::Status
GetPrimaryKeyViaIndex(
511 IndexedDBBackingStore::Transaction
* transaction
,
513 int64 object_store_id
,
515 const IndexedDBKey
& key
,
516 scoped_ptr
<IndexedDBKey
>* primary_key
) WARN_UNUSED_RESULT
;
517 virtual leveldb::Status
KeyExistsInIndex(
518 IndexedDBBackingStore::Transaction
* transaction
,
520 int64 object_store_id
,
522 const IndexedDBKey
& key
,
523 scoped_ptr
<IndexedDBKey
>* found_primary_key
,
524 bool* exists
) WARN_UNUSED_RESULT
;
526 // Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
527 virtual void ReportBlobUnused(int64 database_id
, int64 blob_key
);
529 base::FilePath
GetBlobFileName(int64 database_id
, int64 key
) const;
531 virtual scoped_ptr
<Cursor
> OpenObjectStoreKeyCursor(
532 IndexedDBBackingStore::Transaction
* transaction
,
534 int64 object_store_id
,
535 const IndexedDBKeyRange
& key_range
,
536 blink::WebIDBCursorDirection
,
538 virtual scoped_ptr
<Cursor
> OpenObjectStoreCursor(
539 IndexedDBBackingStore::Transaction
* transaction
,
541 int64 object_store_id
,
542 const IndexedDBKeyRange
& key_range
,
543 blink::WebIDBCursorDirection
,
545 virtual scoped_ptr
<Cursor
> OpenIndexKeyCursor(
546 IndexedDBBackingStore::Transaction
* transaction
,
548 int64 object_store_id
,
550 const IndexedDBKeyRange
& key_range
,
551 blink::WebIDBCursorDirection
,
553 virtual scoped_ptr
<Cursor
> OpenIndexCursor(
554 IndexedDBBackingStore::Transaction
* transaction
,
556 int64 object_store_id
,
558 const IndexedDBKeyRange
& key_range
,
559 blink::WebIDBCursorDirection
,
563 friend class base::RefCounted
<IndexedDBBackingStore
>;
565 IndexedDBBackingStore(IndexedDBFactory
* indexed_db_factory
,
566 const GURL
& origin_url
,
567 const base::FilePath
& blob_path
,
568 net::URLRequestContext
* request_context
,
569 scoped_ptr
<LevelDBDatabase
> db
,
570 scoped_ptr
<LevelDBComparator
> comparator
,
571 base::SequencedTaskRunner
* task_runner
);
572 virtual ~IndexedDBBackingStore();
574 bool is_incognito() const { return !indexed_db_factory_
; }
576 leveldb::Status
SetUpMetadata();
578 virtual bool WriteBlobFile(
580 const Transaction::WriteDescriptor
& descriptor
,
581 Transaction::ChainedBlobWriter
* chained_blob_writer
);
583 // Remove the referenced file on disk.
584 virtual bool RemoveBlobFile(int64 database_id
, int64 key
) const;
586 // Schedule a call to CleanPrimaryJournalIgnoreReturn() via
587 // an owned timer. If this object is destroyed, the timer
588 // will automatically be cancelled.
589 virtual void StartJournalCleaningTimer();
591 // Attempt to clean the primary journal. This will remove
592 // any referenced files and delete the journal entry. If any
593 // transaction is currently committing this will be deferred
594 // via StartJournalCleaningTimer().
595 void CleanPrimaryJournalIgnoreReturn();
598 static scoped_refptr
<IndexedDBBackingStore
> Create(
599 IndexedDBFactory
* indexed_db_factory
,
600 const GURL
& origin_url
,
601 const base::FilePath
& blob_path
,
602 net::URLRequestContext
* request_context
,
603 scoped_ptr
<LevelDBDatabase
> db
,
604 scoped_ptr
<LevelDBComparator
> comparator
,
605 base::SequencedTaskRunner
* task_runner
,
606 leveldb::Status
* status
);
608 static bool ReadCorruptionInfo(const base::FilePath
& path_base
,
609 const GURL
& origin_url
,
610 std::string
* message
);
612 leveldb::Status
FindKeyInIndex(
613 IndexedDBBackingStore::Transaction
* transaction
,
615 int64 object_store_id
,
617 const IndexedDBKey
& key
,
618 std::string
* found_encoded_primary_key
,
620 leveldb::Status
GetIndexes(int64 database_id
,
621 int64 object_store_id
,
622 IndexedDBObjectStoreMetadata::IndexMap
* map
)
625 // Remove the blob directory for the specified database and all contained
627 bool RemoveBlobDirectory(int64 database_id
) const;
629 // Synchronously read the key-specified blob journal entry from the backing
630 // store, delete all referenced blob files, and erase the journal entry.
631 // This must not be used while temporary entries are present e.g. during
632 // a two-stage transaction commit with blobs.
633 leveldb::Status
CleanUpBlobJournal(const std::string
& level_db_key
) const;
635 // Synchronously delete the files and/or directories on disk referenced by
637 leveldb::Status
CleanUpBlobJournalEntries(
638 const BlobJournalType
& journal
) const;
640 IndexedDBFactory
* indexed_db_factory_
;
641 const GURL origin_url_
;
642 base::FilePath blob_path_
;
644 // The origin identifier is a key prefix unique to the origin used in the
645 // leveldb backing store to partition data by origin. It is a normalized
646 // version of the origin URL with a versioning suffix appended, e.g.
647 // "http_localhost_81@1" Since only one origin is stored per backing store
648 // this is redundant but necessary for backwards compatibility; the suffix
649 // provides for future flexibility.
650 const std::string origin_identifier_
;
652 net::URLRequestContext
* request_context_
;
653 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
654 std::set
<int> child_process_ids_granted_
;
655 BlobChangeMap incognito_blob_map_
;
656 base::OneShotTimer
<IndexedDBBackingStore
> journal_cleaning_timer_
;
658 scoped_ptr
<LevelDBDatabase
> db_
;
659 scoped_ptr
<LevelDBComparator
> comparator_
;
660 // Whenever blobs are registered in active_blob_registry_, indexed_db_factory_
661 // will hold a reference to this backing store.
662 IndexedDBActiveBlobRegistry active_blob_registry_
;
663 base::OneShotTimer
<IndexedDBBackingStore
> close_timer_
;
665 // Incremented whenever a transaction starts committing, decremented when
666 // complete. While > 0, temporary journal entries may exist so out-of-band
667 // journal cleaning must be deferred.
668 size_t committing_transaction_count_
;
670 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStore
);
673 } // namespace content
675 #endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_BACKING_STORE_H_