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 57 // Versions are first stored once they successfully install and become 58 // the waiting version. Then transition to the active version. The stored 59 // version may be in the ACTIVATED state or in the INSTALLED state. 60 GURL script; 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 // - If an old version of the registration exists, deletes it and sets 118 // |deleted_version_id| to the old version id and 119 // |newly_purgeable_resources| to its resources. Otherwise, sets 120 // |deleted_version_id| to -1. 121 // - Bumps the next registration id and the next version id if needed. 122 // - Removes |resources| from the uncommitted list if exist. 123 // Returns OK they are successfully written. Otherwise, returns an error. 124 Status WriteRegistration(const RegistrationData& registration, 125 const std::vector<ResourceRecord>& resources, 126 int64* deleted_version_id, 127 std::vector<int64>* newly_purgeable_resources); 128 129 // Updates a registration for |registration_id| to an active state. Returns OK 130 // if it's successfully updated. Otherwise, returns an error. 131 Status UpdateVersionToActive( 132 int64 registration_id, 133 const GURL& origin); 134 135 // Updates last check time of a registration for |registration_id| by |time|. 136 // Returns OK if it's successfully updated. Otherwise, returns an error. 137 Status UpdateLastCheckTime( 138 int64 registration_id, 139 const GURL& origin, 140 const base::Time& time); 141 142 // Deletes a registration for |registration_id| and moves resource records 143 // associated with it into the purgeable list. If deletion occurred, sets 144 // |version_id| to the id of the version that was deleted and 145 // |newly_purgeable_resources| to its resources; otherwise, sets |version_id| 146 // to -1. Returns OK if it's successfully deleted or not found in the 147 // database. Otherwise, returns an error. 148 Status DeleteRegistration(int64 registration_id, 149 const GURL& origin, 150 int64* version_id, 151 std::vector<int64>* newly_purgeable_resources); 152 153 // As new resources are put into the diskcache, they go into an uncommitted 154 // list. When a registration is saved that refers to those ids, they're 155 // removed from that list. When a resource no longer has any registrations or 156 // caches referring to it, it's added to the purgeable list. Periodically, 157 // the purgeable list can be purged from the diskcache. At system startup, all 158 // uncommitted ids are moved to the purgeable list. 159 160 // Reads uncommitted resource ids from the database. Returns OK on success. 161 // Otherwise clears |ids| and returns an error. 162 Status GetUncommittedResourceIds(std::set<int64>* ids); 163 164 // Writes |ids| into the database as uncommitted resources. Returns OK on 165 // success. Otherwise writes nothing and returns an error. 166 Status WriteUncommittedResourceIds(const std::set<int64>& ids); 167 168 // Deletes uncommitted resource ids specified by |ids| from the database. 169 // Returns OK on success. Otherwise deletes nothing and returns an error. 170 Status ClearUncommittedResourceIds(const std::set<int64>& ids); 171 172 // Reads purgeable resource ids from the database. Returns OK on success. 173 // Otherwise clears |ids| and returns an error. 174 Status GetPurgeableResourceIds(std::set<int64>* ids); 175 176 // Writes |ids| into the database as purgeable resources. Returns OK on 177 // success. Otherwise writes nothing and returns an error. 178 Status WritePurgeableResourceIds(const std::set<int64>& ids); 179 180 // Deletes purgeable resource ids specified by |ids| from the database. 181 // Returns OK on success. Otherwise deletes nothing and returns an error. 182 Status ClearPurgeableResourceIds(const std::set<int64>& ids); 183 184 // Moves |ids| from the uncommitted list to the purgeable list. 185 // Returns OK on success. Otherwise deletes nothing and returns an error. 186 Status PurgeUncommittedResourceIds(const std::set<int64>& ids); 187 188 // Deletes all data for |origin|, namely, unique origin, registrations and 189 // resource records. Resources are moved to the purgeable list. Returns OK if 190 // they are successfully deleted or not found in the database. Otherwise, 191 // returns an error. 192 Status DeleteAllDataForOrigin( 193 const GURL& origin, 194 std::vector<int64>* newly_purgeable_resources); 195 196 // Completely deletes the contents of the database. 197 // Be careful using this function. 198 Status DestroyDatabase(); 199 200 private: 201 // Opens the database at the |path_|. This is lazily called when the first 202 // database API is called. Returns OK if the database is successfully opened. 203 // Returns NOT_FOUND if the database does not exist and |create_if_missing| is 204 // false. Otherwise, returns an error. 205 Status LazyOpen(bool create_if_missing); 206 207 // Helper for LazyOpen(). |status| must be the return value from LazyOpen() 208 // and this must be called just after LazyOpen() is called. Returns true if 209 // the database is new or nonexistent, that is, it has never been used. 210 bool IsNewOrNonexistentDatabase(Status status); 211 212 // Reads the next available id for |id_key|. Returns OK if it's successfully 213 // read. Fills |next_avail_id| with an initial value and returns OK if it's 214 // not found in the database. Otherwise, returns an error. 215 Status ReadNextAvailableId( 216 const char* id_key, 217 int64* next_avail_id); 218 219 // Reads registration data for |registration_id| from the database. Returns OK 220 // if successfully reads. Otherwise, returns an error. 221 Status ReadRegistrationData( 222 int64 registration_id, 223 const GURL& origin, 224 RegistrationData* registration); 225 226 // Reads resource records for |version_id| from the database. Returns OK if 227 // it's successfully read or not found in the database. Otherwise, returns an 228 // error. 229 Status ReadResourceRecords( 230 int64 version_id, 231 std::vector<ResourceRecord>* resources); 232 233 // Deletes resource records for |version_id| from the database. Returns OK if 234 // they are successfully deleted or not found in the database. Otherwise, 235 // returns an error. 236 Status DeleteResourceRecords( 237 int64 version_id, 238 std::vector<int64>* newly_purgeable_resources, 239 leveldb::WriteBatch* batch); 240 241 // Reads resource ids for |id_key_prefix| from the database. Returns OK if 242 // it's successfully read or not found in the database. Otherwise, returns an 243 // error. 244 Status ReadResourceIds( 245 const char* id_key_prefix, 246 std::set<int64>* ids); 247 248 // Write resource ids for |id_key_prefix| into the database. Returns OK on 249 // success. Otherwise, returns writes nothing and returns an error. 250 Status WriteResourceIds( 251 const char* id_key_prefix, 252 const std::set<int64>& ids); 253 Status WriteResourceIdsInBatch( 254 const char* id_key_prefix, 255 const std::set<int64>& ids, 256 leveldb::WriteBatch* batch); 257 258 // Deletes resource ids for |id_key_prefix| from the database. Returns OK if 259 // it's successfully deleted or not found in the database. Otherwise, returns 260 // an error. 261 Status DeleteResourceIds( 262 const char* id_key_prefix, 263 const std::set<int64>& ids); 264 Status DeleteResourceIdsInBatch( 265 const char* id_key_prefix, 266 const std::set<int64>& ids, 267 leveldb::WriteBatch* batch); 268 269 // Reads the current schema version from the database. If the database hasn't 270 // been written anything yet, sets |db_version| to 0 and returns OK. 271 Status ReadDatabaseVersion(int64* db_version); 272 273 // Writes a batch into the database. 274 // NOTE: You must call this when you want to put something into the database 275 // because this initializes the database if needed. 276 Status WriteBatch(leveldb::WriteBatch* batch); 277 278 // Bumps the next available id if |used_id| is greater than or equal to the 279 // cached one. 280 void BumpNextRegistrationIdIfNeeded( 281 int64 used_id, 282 leveldb::WriteBatch* batch); 283 void BumpNextResourceIdIfNeeded( 284 int64 used_id, 285 leveldb::WriteBatch* batch); 286 void BumpNextVersionIdIfNeeded( 287 int64 used_id, 288 leveldb::WriteBatch* batch); 289 290 bool IsOpen(); 291 292 void Disable( 293 const tracked_objects::Location& from_here, 294 Status status); 295 void HandleOpenResult( 296 const tracked_objects::Location& from_here, 297 Status status); 298 void HandleReadResult( 299 const tracked_objects::Location& from_here, 300 Status status); 301 void HandleWriteResult( 302 const tracked_objects::Location& from_here, 303 Status status); 304 305 base::FilePath path_; 306 scoped_ptr<leveldb::Env> env_; 307 scoped_ptr<leveldb::DB> db_; 308 309 int64 next_avail_registration_id_; 310 int64 next_avail_resource_id_; 311 int64 next_avail_version_id_; 312 313 enum State { 314 UNINITIALIZED, 315 INITIALIZED, 316 DISABLED, 317 }; 318 State state_; 319 320 base::SequenceChecker sequence_checker_; 321 322 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase); 323 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase_InMemory); 324 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DatabaseVersion); 325 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, GetNextAvailableIds); 326 FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DestroyDatabase); 327 328 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase); 329 }; 330 331 } // namespace content 332 333 #endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_H_ 334