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