• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
6 #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
7 
8 #include <map>
9 #include <set>
10 #include <vector>
11 
12 #include "base/files/file_path.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/macros.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/sequence_checker.h"
17 #include "base/time/time.h"
18 #include "content/common/content_export.h"
19 #include "content/common/service_worker/service_worker_status_code.h"
20 #include "url/gurl.h"
21 
22 namespace leveldb {
23 class DB;
24 class Env;
25 class Status;
26 class WriteBatch;
27 }
28 
29 namespace content {
30 
31 // Class to persist serviceworker registration data in a database.
32 // Should NOT be used on the IO thread since this does blocking
33 // file io. The ServiceWorkerStorage class owns this class and
34 // is responsible for only calling it serially on background
35 // non-IO threads (ala SequencedWorkerPool).
36 class CONTENT_EXPORT ServiceWorkerDatabase {
37  public:
38   // We do leveldb stuff in |path| or in memory if |path| is empty.
39   explicit ServiceWorkerDatabase(const base::FilePath& path);
40   ~ServiceWorkerDatabase();
41 
42   // Used in UMA. A new value must be appended only.
43   enum Status {
44     STATUS_OK,
45     STATUS_ERROR_NOT_FOUND,
46     STATUS_ERROR_IO_ERROR,
47     STATUS_ERROR_CORRUPTED,
48     STATUS_ERROR_FAILED,
49     STATUS_ERROR_MAX,
50   };
51 
52   struct CONTENT_EXPORT RegistrationData {
53     // These values are immutable for the life of a registration.
54     int64 registration_id;
55     GURL scope;
56     GURL script;
57 
58     // Versions are first stored once they successfully install and become
59     // the waiting version. Then transition to the active version. The stored
60     // version may be in the ACTIVE state or in the INSTALLED state.
61     int64 version_id;
62     bool is_active;
63     bool has_fetch_handler;
64     base::Time last_update_check;
65 
66     RegistrationData();
67     ~RegistrationData();
68   };
69 
70   struct ResourceRecord {
71     int64 resource_id;
72     GURL url;
73 
ResourceRecordResourceRecord74     ResourceRecord() {}
ResourceRecordResourceRecord75     ResourceRecord(int64 id, GURL url) : resource_id(id), url(url) {}
76   };
77 
78   // Reads next available ids from the database. Returns OK if they are
79   // successfully read. Fills the arguments with an initial value and returns
80   // OK if they are not found in the database. Otherwise, returns an error.
81   Status GetNextAvailableIds(
82       int64* next_avail_registration_id,
83       int64* next_avail_version_id,
84       int64* next_avail_resource_id);
85 
86   // Reads origins that have one or more than one registration from the
87   // database. Returns OK if they are successfully read or not found.
88   // Otherwise, returns an error.
89   Status GetOriginsWithRegistrations(std::set<GURL>* origins);
90 
91   // Reads registrations for |origin| from the database. Returns OK if they are
92   // successfully read or not found. Otherwise, returns an error.
93   Status GetRegistrationsForOrigin(
94       const GURL& origin,
95       std::vector<RegistrationData>* registrations);
96 
97   // Reads all registrations from the database. Returns OK if successfully read
98   // or not found. Otherwise, returns an error.
99   Status GetAllRegistrations(std::vector<RegistrationData>* registrations);
100 
101   // Saving, retrieving, and updating registration data.
102   // (will bump next_avail_xxxx_ids as needed)
103   // (resource ids will be added/removed from the uncommitted/purgeable
104   // lists as needed)
105 
106   // Reads a registration for |registration_id| and resource records associated
107   // with it from the database. Returns OK if they are successfully read.
108   // Otherwise, returns an error.
109   Status ReadRegistration(
110       int64 registration_id,
111       const GURL& origin,
112       RegistrationData* registration,
113       std::vector<ResourceRecord>* resources);
114 
115   // Writes |registration| and |resources| into the database and does following
116   // things:
117   //   - Deletes an old version of the registration if exists.
118   //   - Bumps the next registration id and the next version id if needed.
119   //   - Removes |resources| from the uncommitted list if exist.
120   // Returns OK they are successfully written. Otherwise, returns an error.
121   Status WriteRegistration(
122       const RegistrationData& registration,
123       const std::vector<ResourceRecord>& resources,
124       std::vector<int64>* newly_purgeable_resources);
125 
126   // Updates a registration for |registration_id| to an active state. Returns OK
127   // if it's successfully updated. Otherwise, returns an error.
128   Status UpdateVersionToActive(
129       int64 registration_id,
130       const GURL& origin);
131 
132   // Updates last check time of a registration for |registration_id| by |time|.
133   // Returns OK if it's successfully updated. Otherwise, returns an error.
134   Status UpdateLastCheckTime(
135       int64 registration_id,
136       const GURL& origin,
137       const base::Time& time);
138 
139   // Deletes a registration for |registration_id| and moves resource records
140   // associated with it into the purgeable list. Returns OK if it's successfully
141   // deleted or not found in the database. Otherwise, returns an error.
142   Status DeleteRegistration(
143       int64 registration_id,
144       const GURL& origin,
145       std::vector<int64>* newly_purgeable_resources);
146 
147   // As new resources are put into the diskcache, they go into an uncommitted
148   // list. When a registration is saved that refers to those ids, they're
149   // removed from that list. When a resource no longer has any registrations or
150   // caches referring to it, it's added to the purgeable list. Periodically,
151   // the purgeable list can be purged from the diskcache. At system startup, all
152   // uncommitted ids are moved to the purgeable list.
153 
154   // Reads uncommitted resource ids from the database. Returns OK on success.
155   // Otherwise clears |ids| and returns an error.
156   Status GetUncommittedResourceIds(std::set<int64>* ids);
157 
158   // Writes |ids| into the database as uncommitted resources. Returns OK on
159   // success. Otherwise writes nothing and returns an error.
160   Status WriteUncommittedResourceIds(const std::set<int64>& ids);
161 
162   // Deletes uncommitted resource ids specified by |ids| from the database.
163   // Returns OK on success. Otherwise deletes nothing and returns an error.
164   Status ClearUncommittedResourceIds(const std::set<int64>& ids);
165 
166   // Reads purgeable resource ids from the database. Returns OK on success.
167   // Otherwise clears |ids| and returns an error.
168   Status GetPurgeableResourceIds(std::set<int64>* ids);
169 
170   // Writes |ids| into the database as purgeable resources. Returns OK on
171   // success. Otherwise writes nothing and returns an error.
172   Status WritePurgeableResourceIds(const std::set<int64>& ids);
173 
174   // Deletes purgeable resource ids specified by |ids| from the database.
175   // Returns OK on success. Otherwise deletes nothing and returns an error.
176   Status ClearPurgeableResourceIds(const std::set<int64>& ids);
177 
178   // Moves |ids| from the uncommitted list to the purgeable list.
179   // Returns OK on success. Otherwise deletes nothing and returns an error.
180   Status PurgeUncommittedResourceIds(const std::set<int64>& ids);
181 
182   // Deletes all data for |origin|, namely, unique origin, registrations and
183   // resource records. Resources are moved to the purgeable list. Returns OK if
184   // they are successfully deleted or not found in the database. Otherwise,
185   // returns an error.
186   Status DeleteAllDataForOrigin(
187       const GURL& origin,
188       std::vector<int64>* newly_purgeable_resources);
189 
190   // Completely deletes the contents of the database.
191   // Be careful using this function.
192   Status DestroyDatabase();
193 
194  private:
195   // Opens the database at the |path_|. This is lazily called when the first
196   // database API is called. Returns OK if the database is successfully opened.
197   // Returns NOT_FOUND if the database does not exist and |create_if_missing| is
198   // false. Otherwise, returns an error.
199   Status LazyOpen(bool create_if_missing);
200 
201   // Helper for LazyOpen(). |status| must be the return value from LazyOpen()
202   // and this must be called just after LazyOpen() is called. Returns true if
203   // the database is new or nonexistent, that is, it has never been used.
204   bool IsNewOrNonexistentDatabase(Status status);
205 
206   // Reads the next available id for |id_key|. Returns OK if it's successfully
207   // read. Fills |next_avail_id| with an initial value and returns OK if it's
208   // not found in the database. Otherwise, returns an error.
209   Status ReadNextAvailableId(
210       const char* id_key,
211       int64* next_avail_id);
212 
213   // Reads registration data for |registration_id| from the database. Returns OK
214   // if successfully reads. Otherwise, returns an error.
215   Status ReadRegistrationData(
216       int64 registration_id,
217       const GURL& origin,
218       RegistrationData* registration);
219 
220   // Reads resource records for |version_id| from the database. Returns OK if
221   // it's successfully read or not found in the database. Otherwise, returns an
222   // error.
223   Status ReadResourceRecords(
224       int64 version_id,
225       std::vector<ResourceRecord>* resources);
226 
227   // Deletes resource records for |version_id| from the database. Returns OK if
228   // they are successfully deleted or not found in the database. Otherwise,
229   // returns an error.
230   Status DeleteResourceRecords(
231       int64 version_id,
232       std::vector<int64>* newly_purgeable_resources,
233       leveldb::WriteBatch* batch);
234 
235   // Reads resource ids for |id_key_prefix| from the database. Returns OK if
236   // it's successfully read or not found in the database. Otherwise, returns an
237   // error.
238   Status ReadResourceIds(
239       const char* id_key_prefix,
240       std::set<int64>* ids);
241 
242   // Write resource ids for |id_key_prefix| into the database. Returns OK on
243   // success. Otherwise, returns writes nothing and returns an error.
244   Status WriteResourceIds(
245       const char* id_key_prefix,
246       const std::set<int64>& ids);
247   Status WriteResourceIdsInBatch(
248       const char* id_key_prefix,
249       const std::set<int64>& ids,
250       leveldb::WriteBatch* batch);
251 
252   // Deletes resource ids for |id_key_prefix| from the database. Returns OK if
253   // it's successfully deleted or not found in the database. Otherwise, returns
254   // an error.
255   Status DeleteResourceIds(
256       const char* id_key_prefix,
257       const std::set<int64>& ids);
258   Status DeleteResourceIdsInBatch(
259       const char* id_key_prefix,
260       const std::set<int64>& ids,
261       leveldb::WriteBatch* batch);
262 
263   // Reads the current schema version from the database. If the database hasn't
264   // been written anything yet, sets |db_version| to 0 and returns OK.
265   Status ReadDatabaseVersion(int64* db_version);
266 
267   // Writes a batch into the database.
268   // NOTE: You must call this when you want to put something into the database
269   // because this initializes the database if needed.
270   Status WriteBatch(leveldb::WriteBatch* batch);
271 
272   // Bumps the next available id if |used_id| is greater than or equal to the
273   // cached one.
274   void BumpNextRegistrationIdIfNeeded(
275       int64 used_id,
276       leveldb::WriteBatch* batch);
277   void BumpNextVersionIdIfNeeded(
278       int64 used_id,
279       leveldb::WriteBatch* batch);
280 
281   bool IsOpen();
282 
283   void Disable(
284       const tracked_objects::Location& from_here,
285       Status status);
286   void HandleOpenResult(
287       const tracked_objects::Location& from_here,
288       Status status);
289   void HandleReadResult(
290       const tracked_objects::Location& from_here,
291       Status status);
292   void HandleWriteResult(
293       const tracked_objects::Location& from_here,
294       Status status);
295 
296   base::FilePath path_;
297   scoped_ptr<leveldb::Env> env_;
298   scoped_ptr<leveldb::DB> db_;
299 
300   int64 next_avail_registration_id_;
301   int64 next_avail_resource_id_;
302   int64 next_avail_version_id_;
303 
304   enum State {
305     UNINITIALIZED,
306     INITIALIZED,
307     DISABLED,
308   };
309   State state_;
310 
311   base::SequenceChecker sequence_checker_;
312 
313   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase);
314   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase_InMemory);
315   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DatabaseVersion);
316   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, GetNextAvailableIds);
317   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DestroyDatabase);
318 
319   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase);
320 };
321 
322 }  // namespace content
323 
324 #endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
325