Home | History | Annotate | Download | only in service_worker
      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