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
36namespace base {
37class SequencedTaskRunner;
38}
39
40namespace storage {
41class FileWriterDelegate;
42}
43
44namespace net {
45class URLRequestContext;
46}
47
48namespace content {
49
50class IndexedDBFactory;
51class LevelDBComparator;
52class LevelDBDatabase;
53class LevelDBFactory;
54struct IndexedDBValue;
55
56class 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