1 // Copyright 2018 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 COMPONENTS_FEED_CORE_FEED_JOURNAL_DATABASE_H_
6 #define COMPONENTS_FEED_CORE_FEED_JOURNAL_DATABASE_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/containers/flat_map.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/sequenced_task_runner.h"
17 #include "components/leveldb_proto/public/proto_database.h"
18 
19 namespace leveldb_proto {
20 class ProtoDatabaseProvider;
21 }  // namespace leveldb_proto
22 
23 namespace feed {
24 
25 class JournalMutation;
26 class JournalOperation;
27 class JournalStorageProto;
28 
29 using InitStatus = leveldb_proto::Enums::InitStatus;
30 
31 // FeedJournalDatabase is leveldb backend store for Feed's journal storage data.
32 // Feed's journal data are key-value pairs.  In order to support callers from
33 // different threads, this class posts all database operations to an owned
34 // sequenced task runner.
35 class FeedJournalDatabase {
36  public:
37   // Returns the journal data as a vector of strings when calling loading data
38   // or keys.
39   using JournalLoadCallback =
40       base::OnceCallback<void(bool, std::vector<std::string>)>;
41 
42   // Return whether the entry exists when calling for checking
43   // the entry's existence.
44   using CheckExistingCallback = base::OnceCallback<void(bool, bool)>;
45 
46   // Returns whether the commit operation succeeded when calling for database
47   // operations.
48   using ConfirmationCallback = base::OnceCallback<void(bool)>;
49 
50   using JournalMap = base::flat_map<std::string, JournalStorageProto>;
51 
52   using StorageEntryVector =
53       leveldb_proto::ProtoDatabase<JournalStorageProto>::KeyEntryVector;
54 
55   // Initializes the database with |proto_database_provider| and
56   // |database_folder|.
57   FeedJournalDatabase(
58       leveldb_proto::ProtoDatabaseProvider* proto_database_provider,
59       const base::FilePath& database_folder);
60 
61   // Creates storage using the given |storage_database| for local storage.
62   // Useful for testing.
63   explicit FeedJournalDatabase(
64       std::unique_ptr<leveldb_proto::ProtoDatabase<JournalStorageProto>>
65           storage_database,
66       scoped_refptr<base::SequencedTaskRunner> task_runner);
67 
68   ~FeedJournalDatabase();
69 
70   // Returns true if initialization has finished successfully, else false.
71   // While this is false, initialization may already started, or initialization
72   // failed.
73   bool IsInitialized() const;
74 
75   // Loads the journal data for the |key| and passes it to |callback|.
76   void LoadJournal(const std::string& key, JournalLoadCallback callback);
77 
78   // Checks if the journal for the |key| exists, and return the result to
79   // |callback|.
80   void DoesJournalExist(const std::string& key, CheckExistingCallback callback);
81 
82   // Commits the operations in the |journal_mutation|. |callback| will be called
83   // when all the operations are committed. Or if any operation failed, database
84   // will stop process any operations and passed error to |callback|.
85   void CommitJournalMutation(std::unique_ptr<JournalMutation> journal_mutation,
86                              ConfirmationCallback callback);
87 
88   // Loads all journal keys in the storage, and passes them to |callback|.
89   void LoadAllJournalKeys(JournalLoadCallback callback);
90 
91   // Delete all journals, |callback| will be called when all journals are
92   // deleted or if there is an error.
93   void DeleteAllJournals(ConfirmationCallback callback);
94 
95  private:
96   // This method performs JournalOperation in the |journal_mutation|.
97   // If the first operation in |journal_mutation| is JOURNAL_DELETE, journal
98   // can be empty, otherwise we need to load |journal| from database and
99   // then pass to this method.
100   void PerformOperations(std::unique_ptr<JournalStorageProto> journal,
101                          std::unique_ptr<JournalMutation> journal_mutation,
102                          ConfirmationCallback callback);
103   void CommitOperations(base::TimeTicks start_time,
104                         std::unique_ptr<JournalStorageProto> journal,
105                         JournalMap copy_to_journal,
106                         ConfirmationCallback callback);
107 
108   // The following *Internal methods must be executed from |task_runner_|.
109   void InitInternal();
110   void GetEntryInternal(
111       const std::string& key,
112       leveldb_proto::Callbacks::Internal<JournalStorageProto>::GetCallback
113           callback);
114   void LoadKeysInternal(JournalLoadCallback callback);
115   void DeleteAllEntriesInternal(ConfirmationCallback callback);
116   void UpdateEntriesInternal(
117       std::unique_ptr<StorageEntryVector> entries_to_save,
118       std::unique_ptr<std::vector<std::string>> keys_to_remove,
119       base::TimeTicks start_time,
120       ConfirmationCallback callback);
121 
122   // Callback methods given to |storage_database_| for async responses.
123   void OnDatabaseInitialized(InitStatus status);
124   void OnGetEntryForLoadJournal(base::TimeTicks start_time,
125                                 JournalLoadCallback callback,
126                                 bool success,
127                                 std::unique_ptr<JournalStorageProto> journal);
128   void OnGetEntryForDoesJournalExist(
129       base::TimeTicks start_time,
130       CheckExistingCallback callback,
131       bool success,
132       std::unique_ptr<JournalStorageProto> journal);
133   void OnGetEntryForCommitJournalMutation(
134       std::unique_ptr<JournalMutation> journal_mutation,
135       ConfirmationCallback callback,
136       bool success,
137       std::unique_ptr<JournalStorageProto> journal);
138   void OnLoadKeysForLoadAllJournalKeys(
139       base::TimeTicks start_time,
140       JournalLoadCallback callback,
141       bool success,
142       std::unique_ptr<std::vector<std::string>> keys);
143   void OnOperationCommitted(base::TimeTicks start_time,
144                             ConfirmationCallback callback,
145                             bool success);
146 
147   JournalStorageProto CopyJournal(const std::string& new_journal_name,
148                                   const JournalStorageProto& source_journal);
149 
150   // Status of the database initialization.
151   InitStatus database_status_;
152 
153   // Task runner on which to execute database calls.
154   scoped_refptr<base::SequencedTaskRunner> task_runner_;
155 
156   // The database for storing journal storage information.
157   std::unique_ptr<leveldb_proto::ProtoDatabase<JournalStorageProto>>
158       storage_database_;
159 
160   base::WeakPtrFactory<FeedJournalDatabase> weak_ptr_factory_{this};
161 
162   DISALLOW_COPY_AND_ASSIGN(FeedJournalDatabase);
163 };
164 
165 }  // namespace feed
166 
167 #endif  // COMPONENTS_FEED_CORE_FEED_JOURNAL_DATABASE_H_
168