1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
#include <map>
#include <set>
#include <vector>
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
namespace leveldb {
class DB;
class Env;
class Status;
class WriteBatch;
}
namespace content {
// Class to persist serviceworker registration data in a database.
// Should NOT be used on the IO thread since this does blocking
// file io. The ServiceWorkerStorage class owns this class and
// is responsible for only calling it serially on background
// non-IO threads (ala SequencedWorkerPool).
class CONTENT_EXPORT ServiceWorkerDatabase {
public:
// We do leveldb stuff in |path| or in memory if |path| is empty.
explicit ServiceWorkerDatabase(const base::FilePath& path);
~ServiceWorkerDatabase();
struct CONTENT_EXPORT RegistrationData {
// These values are immutable for the life of a registration.
int64 registration_id;
GURL scope;
GURL script;
// Versions are first stored once they successfully install and become
// the waiting version. Then transition to the active version. The stored
// version may be in the ACTIVE state or in the INSTALLED state.
int64 version_id;
bool is_active;
bool has_fetch_handler;
base::Time last_update_check;
RegistrationData();
~RegistrationData();
};
struct ResourceRecord {
int64 resource_id;
GURL url;
};
// For use during initialization.
ServiceWorkerStatusCode GetNextAvailableIds(
int64* next_avail_registration_id,
int64* next_avail_version_id,
int64* next_avail_resource_id);
ServiceWorkerStatusCode GetOriginsWithRegistrations(
std::set<GURL>* origins);
// For use when first handling a request in an origin with registrations.
bool GetRegistrationsForOrigin(const GURL& origin,
std::vector<RegistrationData>* registrations);
bool GetAllRegistrations(std::vector<RegistrationData>* registrations);
// Saving, retrieving, and updating registration data.
// (will bump next_avail_xxxx_ids as needed)
// (resource ids will be added/removed from the uncommitted/purgeable
// lists as needed)
bool ReadRegistration(int64 registration_id,
const GURL& origin,
RegistrationData* registration,
std::vector<ResourceRecord>* resources);
bool WriteRegistration(const RegistrationData& registration,
const std::vector<ResourceRecord>& resources);
bool UpdateVersionToActive(int64 registration_id,
const GURL& origin);
bool UpdateLastCheckTime(int64 registration_id,
const GURL& origin,
const base::Time& time);
bool DeleteRegistration(int64 registration_id,
const GURL& origin);
// As new resources are put into the diskcache, they go into an uncommitted
// list. When a registration is saved that refers to those ids, they're
// removed from that list. When a resource no longer has any registrations or
// caches referring to it, it's added to the purgeable list. Periodically,
// the purgeable list can be purged from the diskcache. At system startup, all
// uncommitted ids are moved to the purgeable list.
// Reads uncommitted resource ids from the database. Returns true on success.
// Otherwise clears |ids| and returns false.
bool GetUncommittedResourceIds(std::set<int64>* ids);
// Writes |ids| into the database as uncommitted resources. Returns true on
// success. Otherwise writes nothing and returns false.
bool WriteUncommittedResourceIds(const std::set<int64>& ids);
// Deletes uncommitted resource ids specified by |ids| from the database.
// Returns true on success. Otherwise deletes nothing and returns false.
bool ClearUncommittedResourceIds(const std::set<int64>& ids);
// Reads purgeable resource ids from the database. Returns true on success.
// Otherwise clears |ids| and returns false.
bool GetPurgeableResourceIds(std::set<int64>* ids);
// Writes |ids| into the database as purgeable resources. Returns true on
// success. Otherwise writes nothing and returns false.
bool WritePurgeableResourceIds(const std::set<int64>& ids);
// Deletes purgeable resource ids specified by |ids| from the database.
// Returns true on success. Otherwise deletes nothing and returns false.
bool ClearPurgeableResourceIds(const std::set<int64>& ids);
// Delete all data for |origin|, namely, unique origin, registrations and
// resource records. Resources are moved to the purgeable list.
bool DeleteAllDataForOrigin(const GURL& origin);
bool is_disabled() const { return is_disabled_; }
bool was_corruption_detected() const { return was_corruption_detected_; }
private:
// Opens the database at the |path_|. This is lazily called when the first
// database API is called. Returns true if the database was opened. Returns
// false if the opening failed or was not neccessary, that is, the database
// does not exist and |create_if_needed| is false.
bool LazyOpen(bool create_if_needed);
ServiceWorkerStatusCode ReadNextAvailableId(
const char* id_key,
int64* next_avail_id);
bool ReadRegistrationData(int64 registration_id,
const GURL& origin,
RegistrationData* registration);
bool ReadResourceRecords(int64 version_id,
std::vector<ResourceRecord>* resources);
bool DeleteResourceRecords(int64 version_id,
leveldb::WriteBatch* batch);
bool ReadResourceIds(const char* id_key_prefix,
std::set<int64>* ids);
bool WriteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids);
bool DeleteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids);
// Reads the current schema version from the database. If the database hasn't
// been written anything yet, sets |db_version| to 0 and returns true.
bool ReadDatabaseVersion(int64* db_version);
// Write a batch into the database.
// NOTE: You must call this when you want to put something into the database
// because this initializes the database if needed.
bool WriteBatch(leveldb::WriteBatch* batch);
// Bumps the next available id if |used_id| is greater than or equal to the
// cached one.
void BumpNextRegistrationIdIfNeeded(int64 used_id,
leveldb::WriteBatch* batch);
void BumpNextVersionIdIfNeeded(int64 used_id,
leveldb::WriteBatch* batch);
bool IsOpen();
void HandleError(const tracked_objects::Location& from_here,
const leveldb::Status& status);
base::FilePath path_;
scoped_ptr<leveldb::Env> env_;
scoped_ptr<leveldb::DB> db_;
int64 next_avail_registration_id_;
int64 next_avail_resource_id_;
int64 next_avail_version_id_;
// True if a database error has occurred (e.g. cannot read data).
// If true, all database accesses will fail.
bool is_disabled_;
// True if a database corruption was detected.
bool was_corruption_detected_;
// True if a database was initialized, that is, the schema version was written
// in the database.
bool is_initialized_;
base::SequenceChecker sequence_checker_;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase_InMemory);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DatabaseVersion);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, GetNextAvailableIds);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, Registration_Basic);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, Registration_Overwrite);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, Registration_Multiple);
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_
|