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 74 ResourceRecord() {} 75 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