Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(697)

Side by Side Diff: content/browser/service_worker/service_worker_fetch_stores.cc

Issue 424863002: Fill in some of ServiceWorkerFetchStores. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cache_storage
Patch Set: Asynchronous cache init Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/service_worker/service_worker_fetch_stores.h" 5 #include "content/browser/service_worker/service_worker_fetch_stores.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/file_util.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/pickle.h"
12 #include "base/sha1.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "content/browser/service_worker/service_worker_fetch_store.h"
9 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/directory_lister.h"
10 18
11 namespace content { 19 namespace content {
12 20
21 // Handles the loading of ServiceWorkerFetchStore and any extra clean up other
22 // than deleting the ServiceWorkerFetchStore object.
23 class ServiceWorkerFetchStores::StoresLoader {
24 public:
25 virtual ~StoresLoader() {};
26 virtual ServiceWorkerFetchStore* LoadStore(const std::string& key) = 0;
27 // Creates a new store, deleting any pre-existing store of the same name.
28 virtual ServiceWorkerFetchStore* CreateStore(const std::string& key) = 0;
29 virtual bool CleanUpDeletedStore(const std::string& key) = 0;
30 virtual bool WriteIndex(StoreMap* stores) = 0;
31 virtual void LoadIndex(std::vector<std::string>* names) = 0;
32 };
33
34 class ServiceWorkerFetchStores::MemoryLoader
35 : public ServiceWorkerFetchStores::StoresLoader {
36 public:
37 virtual content::ServiceWorkerFetchStore* LoadStore(
38 const std::string& key) OVERRIDE {
39 NOTREACHED();
40 return NULL;
41 }
42
43 virtual ServiceWorkerFetchStore* CreateStore(
44 const std::string& key) OVERRIDE {
45 return ServiceWorkerFetchStore::CreateMemoryStore(key);
46 }
47
48 virtual bool CleanUpDeletedStore(const std::string& key) OVERRIDE {
49 return true;
50 }
51
52 virtual bool WriteIndex(StoreMap* stores) OVERRIDE { return false; }
53
54 virtual void LoadIndex(std::vector<std::string>* names) OVERRIDE { return; }
55 };
56
57 class ServiceWorkerFetchStores::SimpleCacheLoader
58 : public ServiceWorkerFetchStores::StoresLoader {
59 public:
60 explicit SimpleCacheLoader(const base::FilePath& origin_path)
61 : origin_path_(origin_path) {}
62
63 virtual ServiceWorkerFetchStore* LoadStore(const std::string& key) OVERRIDE {
64 base::CreateDirectory(CreatePersistentStorePath(origin_path_, key));
65 return ServiceWorkerFetchStore::CreatePersistentStore(
66 CreatePersistentStorePath(origin_path_, key), key);
67 }
68
69 virtual ServiceWorkerFetchStore* CreateStore(
70 const std::string& key) OVERRIDE {
71 base::FilePath store_path = CreatePersistentStorePath(origin_path_, key);
72 if (base::PathExists(store_path))
73 base::DeleteFile(store_path, /* recursive */ true);
74 return LoadStore(key);
75 }
76
77 virtual bool CleanUpDeletedStore(const std::string& key) OVERRIDE {
78 return base::DeleteFile(CreatePersistentStorePath(origin_path_, key), true);
79 }
80
81 virtual bool WriteIndex(StoreMap* stores) OVERRIDE {
82 scoped_ptr<Pickle> pickle(new Pickle());
michaeln 2014/08/07 00:10:13 We prefer to use formats on disk that are endian a
jkarlin 2014/08/07 16:02:35 Done. Note I renamed the protobuf target from 'ser
83
84 for (StoreMap::const_iterator iter(stores); !iter.IsAtEnd();
85 iter.Advance()) {
86 const ServiceWorkerFetchStore* store = iter.GetCurrentValue();
87 pickle->WriteString(store->name());
88 }
89
90 base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp");
91 base::FilePath index_path = origin_path_.AppendASCII("index.txt");
92
93 int bytes_written = base::WriteFile(
94 tmp_path, static_cast<const char*>(pickle->data()), pickle->size());
95 if (bytes_written != implicit_cast<int>(pickle->size())) {
96 base::DeleteFile(tmp_path, /* recursive */ false);
97 return false;
98 }
99
100 // Atomically rename the temporary index file to become the real one.
101 return base::ReplaceFile(tmp_path, index_path, NULL);
102 }
103
104 virtual void LoadIndex(std::vector<std::string>* names) OVERRIDE {
105 base::FilePath index_path = origin_path_.AppendASCII("index.txt");
106 base::MemoryMappedFile index_file_map;
michaeln 2014/08/07 00:10:13 memmapped files seems like an odd choice here, is
jkarlin 2014/08/07 16:02:35 Yes, ReadFileToString is better. Thanks. Done.
107 if (!index_file_map.Initialize(index_path)) {
108 base::DeleteFile(index_path, /* recursive */ false);
109 return;
110 }
111
112 Pickle pickle(reinterpret_cast<const char*>(index_file_map.data()),
113 index_file_map.length());
114 if (!pickle.data())
115 return;
116
117 PickleIterator pickle_it(pickle);
118 std::string name;
119 while (pickle.ReadString(&pickle_it, &name))
120 names->push_back(name);
121 return;
122
123 // TODO(jkarlin): Delete stores that are in the directory and not returned
124 // in LoadIndex.
125 }
126
127 private:
128 std::string HexedHash(const std::string& value) {
129 std::string value_hash = base::SHA1HashString(value);
130 return StringToLowerASCII(
131 base::HexEncode(value_hash.c_str(), value_hash.length()));
132 }
133
134 base::FilePath CreatePersistentStorePath(const base::FilePath& origin_path,
135 const std::string& store_name) {
136 return origin_path.AppendASCII(HexedHash(store_name));
137 }
138
139 const base::FilePath origin_path_;
140 };
141
13 ServiceWorkerFetchStores::ServiceWorkerFetchStores( 142 ServiceWorkerFetchStores::ServiceWorkerFetchStores(
14 const base::FilePath& path, 143 const base::FilePath& path,
15 BackendType backend_type, 144 bool memory_only,
16 const scoped_refptr<base::MessageLoopProxy>& callback_loop) 145 const scoped_refptr<base::MessageLoopProxy>& callback_loop)
17 : origin_path_(path), 146 : initialized_(false), origin_path_(path), callback_loop_(callback_loop) {
18 backend_type_(backend_type), 147 if (memory_only)
19 callback_loop_(callback_loop) { 148 stores_loader_.reset(new MemoryLoader());
149 else
150 stores_loader_.reset(new SimpleCacheLoader(origin_path_));
20 } 151 }
21 152
22 ServiceWorkerFetchStores::~ServiceWorkerFetchStores() { 153 ServiceWorkerFetchStores::~ServiceWorkerFetchStores() {
23 } 154 }
24 155
25 void ServiceWorkerFetchStores::CreateStore( 156 void ServiceWorkerFetchStores::CreateStore(
26 const std::string& key, 157 const std::string& key,
27 const StoreAndErrorCallback& callback) { 158 const StoreAndErrorCallback& callback) {
28 // TODO(jkarlin): Implement this. 159 LazyInit();
29 160
30 callback_loop_->PostTask(FROM_HERE, 161 if (key.empty()) {
31 base::Bind(callback, 0, FETCH_STORES_ERROR_EXISTS)); 162 callback_loop_->PostTask(
32 return; 163 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_EMPTY_KEY));
164 return;
165 }
166
167 if (GetLoadedStore(key)) {
168 callback_loop_->PostTask(
169 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_EXISTS));
170 return;
171 }
172
173 ServiceWorkerFetchStore* store = stores_loader_->CreateStore(key);
174
175 if (!store) {
176 callback_loop_->PostTask(
177 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_STORAGE));
178 return;
179 }
180
181 InitStore(store);
182
183 stores_loader_->WriteIndex(&store_map_);
184
185 store->InitializeIfNeeded(
186 base::Bind(&ServiceWorkerFetchStores::InitializeStoreCallback,
187 base::Unretained(this),
188 store,
189 callback));
190
191 callback_loop_->PostTask(
michaeln 2014/08/07 00:10:13 i think this is an extra call to 'callback' that p
jkarlin 2014/08/07 16:02:35 Done.
192 FROM_HERE,
193 base::Bind(callback, store->id(), FETCH_STORES_ERROR_NO_ERROR));
33 } 194 }
34 195
35 void ServiceWorkerFetchStores::Get(const std::string& key, 196 void ServiceWorkerFetchStores::Get(const std::string& key,
michaeln 2014/08/07 00:10:13 Another thing that could help with Store vs Stores
jkarlin 2014/08/07 16:02:35 I renamed key -> store_name in the stores* classes
36 const StoreAndErrorCallback& callback) { 197 const StoreAndErrorCallback& callback) {
37 // TODO(jkarlin): Implement this. 198 LazyInit();
38 199
39 callback_loop_->PostTask(FROM_HERE, 200 if (key.empty()) {
40 base::Bind(callback, 0, FETCH_STORES_ERROR_EXISTS)); 201 callback_loop_->PostTask(
41 return; 202 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_EMPTY_KEY));
203 return;
204 }
205
206 ServiceWorkerFetchStore* store = GetLoadedStore(key);
207 if (!store) {
208 callback_loop_->PostTask(
209 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_NOT_FOUND));
210 return;
211 }
212
213 store->InitializeIfNeeded(
214 base::Bind(&ServiceWorkerFetchStores::InitializeStoreCallback,
215 base::Unretained(this),
216 store,
217 callback));
42 } 218 }
43 219
44 void ServiceWorkerFetchStores::Has(const std::string& key, 220 void ServiceWorkerFetchStores::Has(const std::string& key,
45 const BoolAndErrorCallback& callback) const { 221 const BoolAndErrorCallback& callback) {
46 // TODO(jkarlin): Implement this. 222 LazyInit();
223
224 if (key.empty()) {
225 callback_loop_->PostTask(
226 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_EMPTY_KEY));
227 return;
228 }
47 229
48 callback_loop_->PostTask( 230 callback_loop_->PostTask(
49 FROM_HERE, base::Bind(callback, false, FETCH_STORES_ERROR_EXISTS)); 231 FROM_HERE,
50 return; 232 base::Bind(callback, GetLoadedStore(key), FETCH_STORES_ERROR_NO_ERROR));
51 } 233 }
52 234
53 void ServiceWorkerFetchStores::Delete(const std::string& key, 235 void ServiceWorkerFetchStores::Delete(const std::string& key,
54 const StoreAndErrorCallback& callback) { 236 const BoolAndErrorCallback& callback) {
55 // TODO(jkarlin): Implement this. 237 LazyInit();
56 238
57 callback_loop_->PostTask(FROM_HERE, 239 if (key.empty()) {
58 base::Bind(callback, 0, FETCH_STORES_ERROR_EXISTS)); 240 callback_loop_->PostTask(
59 return; 241 FROM_HERE, base::Bind(callback, false, FETCH_STORES_ERROR_EMPTY_KEY));
242 return;
243 }
244
245 ServiceWorkerFetchStore* store = GetLoadedStore(key);
246 if (!store) {
247 callback_loop_->PostTask(
248 FROM_HERE, base::Bind(callback, false, FETCH_STORES_ERROR_NOT_FOUND));
249 return;
250 }
251
252 name_map_.erase(key);
253 store_map_.Remove(store->id()); // deletes store
254
255 stores_loader_->WriteIndex(&store_map_); // Update the index.
256
257 stores_loader_->CleanUpDeletedStore(key);
258
259 callback_loop_->PostTask(
260 FROM_HERE, base::Bind(callback, true, FETCH_STORES_ERROR_NO_ERROR));
60 } 261 }
61 262
62 void ServiceWorkerFetchStores::Keys( 263 void ServiceWorkerFetchStores::Keys(const StringsAndErrorCallback& callback) {
63 const StringsAndErrorCallback& callback) const { 264 LazyInit();
64 // TODO(jkarlin): Implement this. 265
65 std::vector<std::string> out; 266 std::vector<std::string> names;
267 for (NameMap::const_iterator it = name_map_.begin(); it != name_map_.end();
268 ++it) {
269 names.push_back(it->first);
270 }
271
66 callback_loop_->PostTask( 272 callback_loop_->PostTask(
67 FROM_HERE, base::Bind(callback, out, FETCH_STORES_ERROR_EXISTS)); 273 FROM_HERE, base::Bind(callback, names, FETCH_STORES_ERROR_NO_ERROR));
68 return; 274 }
275
276 void ServiceWorkerFetchStores::InitializeStoreCallback(
277 const ServiceWorkerFetchStore* store,
278 const StoreAndErrorCallback& callback,
279 bool success) {
280 if (!success) {
281 // TODO(jkarlin): This should delete the directory and try again in case
282 // the cache is simply corrupt.
283 callback_loop_->PostTask(
284 FROM_HERE, base::Bind(callback, 0, FETCH_STORES_ERROR_STORAGE));
285 return;
286 }
287 callback_loop_->PostTask(
288 FROM_HERE,
289 base::Bind(callback, store->id(), FETCH_STORES_ERROR_NO_ERROR));
290 }
291
292 // Init is run lazily so that it is called on the proper MessageLoop.
293 void ServiceWorkerFetchStores::LazyInit() {
294 if (initialized_)
295 return;
296
297 std::vector<std::string> indexed_store_names;
298 stores_loader_->LoadIndex(&indexed_store_names);
299
300 for (std::vector<std::string>::const_iterator it =
301 indexed_store_names.begin();
302 it != indexed_store_names.end();
303 ++it) {
304 ServiceWorkerFetchStore* store = stores_loader_->LoadStore(*it);
305 InitStore(store);
306 }
307 initialized_ = true;
308 }
309
310 void ServiceWorkerFetchStores::InitStore(ServiceWorkerFetchStore* store) {
311 StoreID id = store_map_.Add(store);
312 name_map_.insert(std::make_pair(store->name(), id));
313 store->set_id(id);
314 }
315
316 ServiceWorkerFetchStore* ServiceWorkerFetchStores::GetLoadedStore(
317 const std::string& key) const {
318 DCHECK(initialized_);
319
320 NameMap::const_iterator it = name_map_.find(key);
321 if (it == name_map_.end())
322 return NULL;
323
324 ServiceWorkerFetchStore* store = store_map_.Lookup(it->second);
325 DCHECK(store);
326 return store;
69 } 327 }
70 328
71 } // namespace content 329 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698