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.
5 #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
6 #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
13 #include "base/files/file_path.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/sequence_checker.h"
18 #include "base/time/time.h"
19 #include "content/common/content_export.h"
20 #include "content/common/service_worker/service_worker_status_code.h"
32 // Class to persist serviceworker registration data in a database.
33 // Should NOT be used on the IO thread since this does blocking
34 // file io. The ServiceWorkerStorage class owns this class and
35 // is responsible for only calling it serially on background
36 // non-IO threads (ala SequencedWorkerPool).
37 class CONTENT_EXPORT ServiceWorkerDatabase
{
39 // We do leveldb stuff in |path| or in memory if |path| is empty.
40 explicit ServiceWorkerDatabase(const base::FilePath
& path
);
41 ~ServiceWorkerDatabase();
43 // Used in UMA. A new value must be appended only.
46 STATUS_ERROR_NOT_FOUND
,
47 STATUS_ERROR_IO_ERROR
,
48 STATUS_ERROR_CORRUPTED
,
52 static const char* StatusToString(Status status
);
54 struct CONTENT_EXPORT RegistrationData
{
55 // These values are immutable for the life of a registration.
56 int64 registration_id
;
59 // Versions are first stored once they successfully install and become
60 // the waiting version. Then transition to the active version. The stored
61 // version may be in the ACTIVATED state or in the INSTALLED state.
65 bool has_fetch_handler
;
66 base::Time last_update_check
;
68 // Not populated until ServiceWorkerStorage::StoreRegistration is called.
69 int64_t resources_total_size_bytes
;
75 struct ResourceRecord
{
78 // Signed so we can store -1 to specify an unknown or error state. When
79 // stored to the database, this value should always be >= 0.
82 ResourceRecord() : resource_id(-1), size_bytes(0) {}
83 ResourceRecord(int64 id
, GURL url
, int64 size_bytes
)
84 : resource_id(id
), url(url
), size_bytes(size_bytes
) {}
87 // Reads next available ids from the database. Returns OK if they are
88 // successfully read. Fills the arguments with an initial value and returns
89 // OK if they are not found in the database. Otherwise, returns an error.
90 Status
GetNextAvailableIds(
91 int64
* next_avail_registration_id
,
92 int64
* next_avail_version_id
,
93 int64
* next_avail_resource_id
);
95 // Reads origins that have one or more than one registration from the
96 // database. Returns OK if they are successfully read or not found.
97 // Otherwise, returns an error.
98 Status
GetOriginsWithRegistrations(std::set
<GURL
>* origins
);
100 // Reads registrations for |origin| from the database. Returns OK if they are
101 // successfully read or not found. Otherwise, returns an error.
102 Status
GetRegistrationsForOrigin(
104 std::vector
<RegistrationData
>* registrations
,
105 std::vector
<std::vector
<ResourceRecord
>>* opt_resources_list
);
107 // Reads all registrations from the database. Returns OK if successfully read
108 // or not found. Otherwise, returns an error.
109 Status
GetAllRegistrations(std::vector
<RegistrationData
>* registrations
);
111 // Saving, retrieving, and updating registration data.
112 // (will bump next_avail_xxxx_ids as needed)
113 // (resource ids will be added/removed from the uncommitted/purgeable
116 // Reads a registration for |registration_id| and resource records associated
117 // with it from the database. Returns OK if they are successfully read.
118 // Otherwise, returns an error.
119 Status
ReadRegistration(
120 int64 registration_id
,
122 RegistrationData
* registration
,
123 std::vector
<ResourceRecord
>* resources
);
125 // Looks up the origin for the registration with |registration_id|. Returns OK
126 // if a registration was found and read successfully. Otherwise, returns an
128 Status
ReadRegistrationOrigin(int64 registration_id
, GURL
* origin
);
130 // Writes |registration| and |resources| into the database and does following
132 // - If an old version of the registration exists, deletes it and sets
133 // |deleted_version| to the old version registration data object
134 // |newly_purgeable_resources| to its resources. Otherwise, sets
135 // |deleted_version->version_id| to -1.
136 // - Bumps the next registration id and the next version id if needed.
137 // - Removes |resources| from the uncommitted list if exist.
138 // Returns OK they are successfully written. Otherwise, returns an error.
139 Status
WriteRegistration(const RegistrationData
& registration
,
140 const std::vector
<ResourceRecord
>& resources
,
141 RegistrationData
* deleted_version
,
142 std::vector
<int64
>* newly_purgeable_resources
);
144 // Updates a registration for |registration_id| to an active state. Returns OK
145 // if it's successfully updated. Otherwise, returns an error.
146 Status
UpdateVersionToActive(
147 int64 registration_id
,
150 // Updates last check time of a registration for |registration_id| by |time|.
151 // Returns OK if it's successfully updated. Otherwise, returns an error.
152 Status
UpdateLastCheckTime(
153 int64 registration_id
,
155 const base::Time
& time
);
157 // Deletes a registration for |registration_id| and moves resource records
158 // associated with it into the purgeable list. If deletion occurred, sets
159 // |version_id| to the id of the version that was deleted and
160 // |newly_purgeable_resources| to its resources; otherwise, sets |version_id|
161 // to -1. Returns OK if it's successfully deleted or not found in the
162 // database. Otherwise, returns an error.
163 Status
DeleteRegistration(int64 registration_id
,
165 RegistrationData
* deleted_version
,
166 std::vector
<int64
>* newly_purgeable_resources
);
168 // Reads user data for |registration_id| and |user_data_name| from the
170 Status
ReadUserData(int64 registration_id
,
171 const std::string
& user_data_name
,
172 std::string
* user_data
);
174 // Writes |user_data| into the database. Returns NOT_FOUND if the registration
175 // specified by |registration_id| does not exist in the database.
176 Status
WriteUserData(int64 registration_id
,
178 const std::string
& user_data_name
,
179 const std::string
& user_data
);
181 // Deletes user data for |registration_id| and |user_data_name| from the
182 // database. Returns OK if it's successfully deleted or not found in the
184 Status
DeleteUserData(int64 registration_id
,
185 const std::string
& user_data_name
);
187 // Reads user data for all registrations that have data with |user_data_name|
188 // from the database. Returns OK if they are successfully read or not found.
189 Status
ReadUserDataForAllRegistrations(
190 const std::string
& user_data_name
,
191 std::vector
<std::pair
<int64
, std::string
>>* user_data
);
193 // As new resources are put into the diskcache, they go into an uncommitted
194 // list. When a registration is saved that refers to those ids, they're
195 // removed from that list. When a resource no longer has any registrations or
196 // caches referring to it, it's added to the purgeable list. Periodically,
197 // the purgeable list can be purged from the diskcache. At system startup, all
198 // uncommitted ids are moved to the purgeable list.
200 // Reads uncommitted resource ids from the database. Returns OK on success.
201 // Otherwise clears |ids| and returns an error.
202 Status
GetUncommittedResourceIds(std::set
<int64
>* ids
);
204 // Writes |ids| into the database as uncommitted resources. Returns OK on
205 // success. Otherwise writes nothing and returns an error.
206 Status
WriteUncommittedResourceIds(const std::set
<int64
>& ids
);
208 // Deletes uncommitted resource ids specified by |ids| from the database.
209 // Returns OK on success. Otherwise deletes nothing and returns an error.
210 Status
ClearUncommittedResourceIds(const std::set
<int64
>& ids
);
212 // Reads purgeable resource ids from the database. Returns OK on success.
213 // Otherwise clears |ids| and returns an error.
214 Status
GetPurgeableResourceIds(std::set
<int64
>* ids
);
216 // Writes |ids| into the database as purgeable resources. Returns OK on
217 // success. Otherwise writes nothing and returns an error.
218 Status
WritePurgeableResourceIds(const std::set
<int64
>& ids
);
220 // Deletes purgeable resource ids specified by |ids| from the database.
221 // Returns OK on success. Otherwise deletes nothing and returns an error.
222 Status
ClearPurgeableResourceIds(const std::set
<int64
>& ids
);
224 // Moves |ids| from the uncommitted list to the purgeable list.
225 // Returns OK on success. Otherwise deletes nothing and returns an error.
226 Status
PurgeUncommittedResourceIds(const std::set
<int64
>& ids
);
228 // Deletes all data for |origins|, namely, unique origin, registrations and
229 // resource records. Resources are moved to the purgeable list. Returns OK if
230 // they are successfully deleted or not found in the database. Otherwise,
232 Status
DeleteAllDataForOrigins(const std::set
<GURL
>& origins
,
233 std::vector
<int64
>* newly_purgeable_resources
);
235 // Completely deletes the contents of the database.
236 // Be careful using this function.
237 Status
DestroyDatabase();
240 // Opens the database at the |path_|. This is lazily called when the first
241 // database API is called. Returns OK if the database is successfully opened.
242 // Returns NOT_FOUND if the database does not exist and |create_if_missing| is
243 // false. Otherwise, returns an error.
244 Status
LazyOpen(bool create_if_missing
);
246 // Helper for LazyOpen(). |status| must be the return value from LazyOpen()
247 // and this must be called just after LazyOpen() is called. Returns true if
248 // the database is new or nonexistent, that is, it has never been used.
249 bool IsNewOrNonexistentDatabase(Status status
);
251 // Upgrades the database schema from version 1 to version 2. Called by
252 // LazyOpen() when the stored schema is older than version 2.
253 Status
UpgradeDatabaseSchemaFromV1ToV2();
255 // Reads the next available id for |id_key|. Returns OK if it's successfully
256 // read. Fills |next_avail_id| with an initial value and returns OK if it's
257 // not found in the database. Otherwise, returns an error.
258 Status
ReadNextAvailableId(
260 int64
* next_avail_id
);
262 // Reads registration data for |registration_id| from the database. Returns OK
263 // if successfully reads. Otherwise, returns an error.
264 Status
ReadRegistrationData(
265 int64 registration_id
,
267 RegistrationData
* registration
);
269 // Reads resource records for |version_id| from the database. Returns OK if
270 // it's successfully read or not found in the database. Otherwise, returns an
272 Status
ReadResourceRecords(
274 std::vector
<ResourceRecord
>* resources
);
276 // Deletes resource records for |version_id| from the database. Returns OK if
277 // they are successfully deleted or not found in the database. Otherwise,
279 Status
DeleteResourceRecords(
281 std::vector
<int64
>* newly_purgeable_resources
,
282 leveldb::WriteBatch
* batch
);
284 // Reads resource ids for |id_key_prefix| from the database. Returns OK if
285 // it's successfully read or not found in the database. Otherwise, returns an
287 Status
ReadResourceIds(
288 const char* id_key_prefix
,
289 std::set
<int64
>* ids
);
291 // Write resource ids for |id_key_prefix| into the database. Returns OK on
292 // success. Otherwise, returns writes nothing and returns an error.
293 Status
WriteResourceIds(
294 const char* id_key_prefix
,
295 const std::set
<int64
>& ids
);
296 Status
WriteResourceIdsInBatch(
297 const char* id_key_prefix
,
298 const std::set
<int64
>& ids
,
299 leveldb::WriteBatch
* batch
);
301 // Deletes resource ids for |id_key_prefix| from the database. Returns OK if
302 // it's successfully deleted or not found in the database. Otherwise, returns
304 Status
DeleteResourceIds(
305 const char* id_key_prefix
,
306 const std::set
<int64
>& ids
);
307 Status
DeleteResourceIdsInBatch(
308 const char* id_key_prefix
,
309 const std::set
<int64
>& ids
,
310 leveldb::WriteBatch
* batch
);
312 // Deletes all user data for |registration_id| from the database. Returns OK
313 // if they are successfully deleted or not found in the database.
314 Status
DeleteUserDataForRegistration(
315 int64 registration_id
,
316 leveldb::WriteBatch
* batch
);
318 // Reads the current schema version from the database. If the database hasn't
319 // been written anything yet, sets |db_version| to 0 and returns OK.
320 Status
ReadDatabaseVersion(int64
* db_version
);
322 // Writes a batch into the database.
323 // NOTE: You must call this when you want to put something into the database
324 // because this initializes the database if needed.
325 Status
WriteBatch(leveldb::WriteBatch
* batch
);
327 // Bumps the next available id if |used_id| is greater than or equal to the
329 void BumpNextRegistrationIdIfNeeded(
331 leveldb::WriteBatch
* batch
);
332 void BumpNextResourceIdIfNeeded(
334 leveldb::WriteBatch
* batch
);
335 void BumpNextVersionIdIfNeeded(
337 leveldb::WriteBatch
* batch
);
342 const tracked_objects::Location
& from_here
,
344 void HandleOpenResult(
345 const tracked_objects::Location
& from_here
,
347 void HandleReadResult(
348 const tracked_objects::Location
& from_here
,
350 void HandleWriteResult(
351 const tracked_objects::Location
& from_here
,
354 base::FilePath path_
;
355 scoped_ptr
<leveldb::Env
> env_
;
356 scoped_ptr
<leveldb::DB
> db_
;
358 int64 next_avail_registration_id_
;
359 int64 next_avail_resource_id_
;
360 int64 next_avail_version_id_
;
369 base::SequenceChecker sequence_checker_
;
371 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, OpenDatabase
);
372 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, OpenDatabase_InMemory
);
373 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, DatabaseVersion
);
374 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, GetNextAvailableIds
);
375 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
,
376 Registration_UninitializedDatabase
);
377 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
,
378 UserData_UninitializedDatabase
);
379 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, DestroyDatabase
);
380 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest
, UpgradeSchemaToVersion2
);
382 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase
);
385 } // namespace content
387 #endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_