OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 #include "components/leveldb/leveldb_file_thread.h" | |
6 | |
7 #include <set> | |
8 | |
9 #include "base/bind.h" | |
10 #include "mojo/message_pump/message_pump_mojo.h" | |
11 #include "mojo/platform_handle/platform_handle_functions.h" | |
12 | |
13 namespace leveldb { | |
14 | |
15 namespace { | |
16 const char kLevelDBFileThreadName[] = "LevelDB_File_Thread"; | |
17 } // namespace | |
18 | |
19 struct LevelDBFileThread::OpaqueLock { | |
20 filesystem::FilePtr lock_file; | |
21 }; | |
22 | |
23 struct LevelDBFileThread::OpaqueDir { | |
24 explicit OpaqueDir( | |
25 mojo::InterfacePtrInfo<filesystem::Directory> directory_info) { | |
26 directory.Bind(std::move(directory_info)); | |
27 } | |
28 | |
29 filesystem::DirectoryPtr directory; | |
30 }; | |
31 | |
32 struct LevelDBFileThread::WaitableEventDependencies { | |
33 WaitableEventDependencies() {} | |
34 ~WaitableEventDependencies() {} | |
35 std::set<filesystem::DirectoryPtr*> directories; | |
36 std::set<filesystem::FilePtr*> files; | |
37 }; | |
38 | |
39 LevelDBFileThread::LevelDBFileThread() | |
40 : base::Thread(kLevelDBFileThreadName), | |
41 outstanding_opaque_dirs_(0) { | |
42 base::Thread::Options options; | |
43 options.message_pump_factory = | |
44 base::Bind(&mojo::common::MessagePumpMojo::Create); | |
45 StartWithOptions(options); | |
46 } | |
47 | |
48 LevelDBFileThread::OpaqueDir* LevelDBFileThread::RegisterDirectory( | |
49 filesystem::DirectoryPtr directory) { | |
50 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
51 | |
52 OpaqueDir* out_dir = nullptr; | |
53 | |
54 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
55 // from mojo do we return from this. | |
56 base::WaitableEvent done_event(false, false); | |
57 task_runner()->PostTask( | |
58 FROM_HERE, base::Bind(&LevelDBFileThread::RegisterDirectoryImpl, | |
59 this, | |
60 &done_event, | |
61 base::Passed(directory.PassInterface()), | |
62 &out_dir)); | |
63 done_event.Wait(); | |
64 | |
65 return out_dir; | |
66 } | |
67 | |
68 void LevelDBFileThread::UnregisterDirectory(OpaqueDir* dir) { | |
69 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
70 | |
71 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
72 // from mojo do we return from this. | |
73 base::WaitableEvent done_event(false, false); | |
74 task_runner()->PostTask( | |
75 FROM_HERE, base::Bind(&LevelDBFileThread::UnregisterDirectoryImpl, | |
76 this, | |
77 &done_event, | |
78 dir)); | |
79 done_event.Wait(); | |
80 } | |
81 | |
82 base::File LevelDBFileThread::OpenFileHandle(OpaqueDir* dir, | |
83 const std::string& name, | |
84 uint32_t open_flags) { | |
85 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
86 | |
87 base::File file; | |
88 | |
89 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
90 // from mojo do we return from this. | |
91 base::WaitableEvent done_event(false, false); | |
92 task_runner()->PostTask( | |
93 FROM_HERE, base::Bind(&LevelDBFileThread::OpenFileHandleImpl, this, | |
94 dir, name, &done_event, open_flags, &file)); | |
95 done_event.Wait(); | |
96 | |
97 return file; | |
98 } | |
99 | |
100 filesystem::FileError LevelDBFileThread::SyncDirectory( | |
101 OpaqueDir* dir, | |
102 const std::string& name) { | |
103 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
104 | |
105 filesystem::FileError error; | |
106 | |
107 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
108 // from mojo do we return from this. | |
109 base::WaitableEvent done_event(false, false); | |
110 task_runner()->PostTask( | |
111 FROM_HERE, base::Bind(&LevelDBFileThread::SyncDirectoryImpl, this, | |
112 dir, name, &done_event, &error)); | |
113 done_event.Wait(); | |
114 | |
115 return error; | |
116 } | |
117 | |
118 bool LevelDBFileThread::FileExists(OpaqueDir* dir, | |
119 const std::string& name) { | |
120 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
121 | |
122 bool exists; | |
123 | |
124 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
125 // from mojo do we return from this. | |
126 base::WaitableEvent done_event(false, false); | |
127 task_runner()->PostTask( | |
128 FROM_HERE, base::Bind(&LevelDBFileThread::FileExistsImpl, this, | |
129 dir, name, &done_event, &exists)); | |
130 done_event.Wait(); | |
131 | |
132 return exists; | |
133 } | |
134 | |
135 filesystem::FileError LevelDBFileThread::GetChildren( | |
136 OpaqueDir* dir, | |
137 const std::string& path, | |
138 std::vector<std::string>* result) { | |
139 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
140 | |
141 filesystem::FileError error; | |
142 | |
143 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
144 // from mojo do we return from this. | |
145 base::WaitableEvent done_event(false, false); | |
146 task_runner()->PostTask( | |
147 FROM_HERE, base::Bind(&LevelDBFileThread::GetChildrenImpl, this, | |
148 dir, path, result, &done_event, &error)); | |
149 done_event.Wait(); | |
150 | |
151 return error; | |
152 } | |
153 | |
154 filesystem::FileError LevelDBFileThread::Delete(OpaqueDir* dir, | |
155 const std::string& path, | |
156 uint32_t delete_flags) { | |
157 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
158 | |
159 filesystem::FileError error; | |
160 | |
161 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
162 // from mojo do we return from this. | |
163 base::WaitableEvent done_event(false, false); | |
164 task_runner()->PostTask(FROM_HERE, | |
165 base::Bind(&LevelDBFileThread::DeleteImpl, this, | |
166 dir, path, delete_flags, &done_event, | |
167 &error)); | |
168 done_event.Wait(); | |
169 | |
170 return error; | |
171 } | |
172 | |
173 filesystem::FileError LevelDBFileThread::CreateDir(OpaqueDir* dir, | |
174 const std::string& path) { | |
175 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
176 | |
177 filesystem::FileError error; | |
178 | |
179 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
180 // from mojo do we return from this. | |
181 base::WaitableEvent done_event(false, false); | |
182 task_runner()->PostTask( | |
183 FROM_HERE, base::Bind(&LevelDBFileThread::CreateDirImpl, this, | |
184 dir, path, &done_event, &error)); | |
185 done_event.Wait(); | |
186 | |
187 return error; | |
188 } | |
189 | |
190 filesystem::FileError LevelDBFileThread::GetFileSize(OpaqueDir* dir, | |
191 const std::string& path, | |
192 uint64_t* file_size) { | |
193 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
194 | |
195 filesystem::FileError error; | |
196 | |
197 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
198 // from mojo do we return from this. | |
199 base::WaitableEvent done_event(false, false); | |
200 task_runner()->PostTask( | |
201 FROM_HERE, base::Bind(&LevelDBFileThread::GetFileSizeImpl, this, | |
202 dir, path, file_size, &done_event, &error)); | |
203 done_event.Wait(); | |
204 | |
205 return error; | |
206 } | |
207 | |
208 filesystem::FileError LevelDBFileThread::RenameFile( | |
209 OpaqueDir* dir, | |
210 const std::string& old_path, | |
211 const std::string& new_path) { | |
212 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
213 | |
214 filesystem::FileError error; | |
215 | |
216 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
217 // from mojo do we return from this. | |
218 base::WaitableEvent done_event(false, false); | |
219 task_runner()->PostTask( | |
220 FROM_HERE, base::Bind(&LevelDBFileThread::RenameFileImpl, this, | |
221 dir, old_path, new_path, &done_event, &error)); | |
222 done_event.Wait(); | |
223 | |
224 return error; | |
225 } | |
226 | |
227 std::pair<filesystem::FileError, LevelDBFileThread::OpaqueLock*> | |
228 LevelDBFileThread::LockFile(OpaqueDir* dir, | |
229 const std::string& path) { | |
230 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
231 | |
232 filesystem::FileError error; | |
233 OpaqueLock* out_lock = nullptr; | |
234 | |
235 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
236 // from mojo do we return from this. | |
237 base::WaitableEvent done_event(false, false); | |
238 task_runner()->PostTask( | |
239 FROM_HERE, base::Bind(&LevelDBFileThread::LockFileImpl, this, | |
240 dir, path, &done_event, &error, &out_lock)); | |
241 done_event.Wait(); | |
242 | |
243 return std::make_pair(error, out_lock); | |
244 } | |
245 | |
246 filesystem::FileError LevelDBFileThread::UnlockFile(OpaqueLock* lock) { | |
247 DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId()); | |
248 | |
249 // Take ownership of the incoming lock so it gets destroyed whatever happens. | |
250 scoped_ptr<OpaqueLock> scoped_lock(lock); | |
251 | |
252 filesystem::FileError error; | |
253 | |
254 // This proxies to the other thread, which proxies to mojo. Only on the reply | |
255 // from mojo do we return from this. | |
256 base::WaitableEvent done_event(false, false); | |
257 task_runner()->PostTask( | |
258 FROM_HERE, base::Bind(&LevelDBFileThread::UnlockFileImpl, this, | |
259 base::Passed(&scoped_lock), &done_event, &error)); | |
260 done_event.Wait(); | |
261 | |
262 return error; | |
263 } | |
264 | |
265 LevelDBFileThread::~LevelDBFileThread() { | |
266 Stop(); | |
267 DCHECK_EQ(0, outstanding_opaque_dirs_); | |
268 } | |
269 | |
270 bool LevelDBFileThread::RegisterDirAndWaitableEvent( | |
271 OpaqueDir* dir, | |
272 base::WaitableEvent* done_event) { | |
273 if (!dir->directory.is_bound()) { | |
274 // The directory went out of scope between the PostTask on the other thread | |
275 // and now. | |
276 done_event->Signal(); | |
277 return true; | |
278 } | |
279 | |
280 waitable_event_dependencies_[done_event].directories.insert(&dir->directory); | |
281 return false; | |
282 } | |
283 | |
284 void LevelDBFileThread::CompleteWaitableEvent(base::WaitableEvent* done_event) { | |
285 // Clean up the dependencies that we no longer care about. | |
286 waitable_event_dependencies_.erase(done_event); | |
287 done_event->Signal(); | |
288 } | |
289 | |
290 void LevelDBFileThread::OnConnectionError() { | |
291 // One of our interface ptrs has become unbound. Signal the event which has | |
292 // it as a dependency. | |
293 auto it = waitable_event_dependencies_.begin(); | |
294 while (it != waitable_event_dependencies_.end()) { | |
295 bool unbound_ptr_found = false; | |
296 for (const auto* dir : it->second.directories) { | |
297 if (!dir->is_bound()) { | |
298 unbound_ptr_found = true; | |
299 break; | |
300 } | |
301 } | |
302 | |
303 if (!unbound_ptr_found) { | |
304 for (const auto* file : it->second.files) { | |
305 if (!file->is_bound()) { | |
306 unbound_ptr_found = true; | |
307 break; | |
308 } | |
309 } | |
310 } | |
311 | |
312 if (unbound_ptr_found) { | |
313 base::WaitableEvent* e = it->first; | |
314 it = waitable_event_dependencies_.erase(it); | |
315 e->Signal(); | |
316 } else { | |
317 ++it; | |
318 } | |
319 } | |
320 } | |
321 | |
322 void LevelDBFileThread::OnSimpleComplete(base::WaitableEvent* done_event, | |
323 filesystem::FileError* out_error, | |
324 filesystem::FileError in_error) { | |
325 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
326 *out_error = in_error; | |
327 CompleteWaitableEvent(done_event); | |
328 } | |
329 | |
330 void LevelDBFileThread::RegisterDirectoryImpl( | |
331 base::WaitableEvent* done_event, | |
332 mojo::InterfacePtrInfo<filesystem::Directory> directory_info, | |
333 OpaqueDir** out_dir) { | |
334 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
335 | |
336 // Take the Directory pipe and bind it on this thread. | |
337 *out_dir = new OpaqueDir(std::move(directory_info)); | |
338 outstanding_opaque_dirs_++; | |
339 | |
340 // Register the connection error handler for the resulting DirectoryPtr | |
341 (*out_dir)->directory.set_connection_error_handler( | |
342 base::Bind(&LevelDBFileThread::OnConnectionError, this)); | |
343 | |
344 done_event->Signal(); | |
345 } | |
346 | |
347 void LevelDBFileThread::UnregisterDirectoryImpl( | |
348 base::WaitableEvent* done_event, | |
349 OpaqueDir* dir) { | |
350 // Only delete the directories on the thread that owns them. | |
351 delete dir; | |
352 outstanding_opaque_dirs_--; | |
353 CompleteWaitableEvent(done_event); | |
354 } | |
355 | |
356 void LevelDBFileThread::OpenFileHandleImpl(OpaqueDir* dir, | |
357 std::string name, | |
358 base::WaitableEvent* done_event, | |
359 uint32_t open_flags, | |
360 base::File* out_file) { | |
361 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
362 | |
363 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
364 return; | |
365 | |
366 dir->directory->OpenFileHandle( | |
367 mojo::String::From(name), open_flags, | |
368 base::Bind(&LevelDBFileThread::OnOpenFileHandleComplete, this, done_event, | |
369 out_file)); | |
370 } | |
371 | |
372 void LevelDBFileThread::OnOpenFileHandleComplete( | |
373 base::WaitableEvent* done_event, | |
374 base::File* output_file, | |
375 filesystem::FileError err, | |
376 mojo::ScopedHandle handle) { | |
377 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
378 | |
379 if (err != filesystem::FileError::OK) { | |
380 *output_file = base::File(static_cast<base::File::Error>(err)); | |
381 } else { | |
382 MojoPlatformHandle platform_handle; | |
383 MojoResult extract_result = | |
384 MojoExtractPlatformHandle(handle.release().value(), &platform_handle); | |
385 | |
386 if (extract_result == MOJO_RESULT_OK) { | |
387 *output_file = base::File(platform_handle); | |
388 } else { | |
389 NOTREACHED(); | |
390 *output_file = base::File(base::File::Error::FILE_ERROR_FAILED); | |
391 } | |
392 } | |
393 | |
394 CompleteWaitableEvent(done_event); | |
395 } | |
396 | |
397 void LevelDBFileThread::SyncDirectoryImpl(OpaqueDir* dir, | |
398 std::string name, | |
399 base::WaitableEvent* done_event, | |
400 filesystem::FileError* out_error) { | |
401 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
402 | |
403 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
404 return; | |
405 | |
406 // Step one: open the directory |name| from the toplevel directory. | |
407 scoped_ptr<filesystem::DirectoryPtr> target(new filesystem::DirectoryPtr); | |
408 | |
409 dir->directory->OpenDirectory( | |
410 name, GetProxy(target.get()), | |
411 filesystem::kFlagRead | filesystem::kFlagWrite, | |
412 base::Bind(&LevelDBFileThread::OnSyncDirctoryOpened, this, | |
413 base::Passed(&target), done_event, out_error)); | |
414 } | |
415 | |
416 void LevelDBFileThread::OnSyncDirctoryOpened( | |
417 scoped_ptr<filesystem::DirectoryPtr> dir, | |
418 base::WaitableEvent* done_event, | |
419 filesystem::FileError* out_error, | |
420 filesystem::FileError in_error) { | |
421 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
422 | |
423 if (in_error != filesystem::FileError::OK) { | |
424 *out_error = in_error; | |
425 CompleteWaitableEvent(done_event); | |
426 return; | |
427 } | |
428 | |
429 // Add a dependency between the new directory we opened and the current | |
430 // waitable event. | |
431 dir->set_connection_error_handler( | |
432 base::Bind(&LevelDBFileThread::OnConnectionError, this)); | |
433 waitable_event_dependencies_[done_event].directories.insert(dir.get()); | |
434 | |
435 // We move the object into the bind before we call. Copy to the stack. | |
436 filesystem::DirectoryPtr* local = dir.get(); | |
437 (*local)->Flush(base::Bind(&LevelDBFileThread::OnSyncDirectoryComplete, this, | |
438 base::Passed(&dir), done_event, out_error)); | |
439 } | |
440 | |
441 void LevelDBFileThread::OnSyncDirectoryComplete( | |
442 scoped_ptr<filesystem::DirectoryPtr> dir, | |
443 base::WaitableEvent* done_event, | |
444 filesystem::FileError* out_error, | |
445 filesystem::FileError in_error) { | |
446 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
447 *out_error = in_error; | |
448 CompleteWaitableEvent(done_event); | |
449 } | |
450 | |
451 void LevelDBFileThread::FileExistsImpl(OpaqueDir* dir, | |
452 std::string name, | |
453 base::WaitableEvent* done_event, | |
454 bool* exists) { | |
455 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
456 | |
457 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
458 return; | |
459 | |
460 dir->directory->Exists( | |
461 mojo::String::From(name), | |
462 base::Bind(&LevelDBFileThread::OnFileExistsComplete, this, | |
463 done_event, exists)); | |
464 } | |
465 | |
466 void LevelDBFileThread::OnFileExistsComplete(base::WaitableEvent* done_event, | |
467 bool* exists, | |
468 filesystem::FileError err, | |
469 bool in_exists) { | |
470 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
471 *exists = in_exists; | |
472 CompleteWaitableEvent(done_event); | |
473 } | |
474 | |
475 void LevelDBFileThread::GetChildrenImpl(OpaqueDir* dir, | |
476 std::string name, | |
477 std::vector<std::string>* contents, | |
478 base::WaitableEvent* done_event, | |
479 filesystem::FileError* out_error) { | |
480 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
481 | |
482 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
483 return; | |
484 | |
485 // Step one: open the directory |name| from the toplevel directory. | |
486 scoped_ptr<filesystem::DirectoryPtr> target(new filesystem::DirectoryPtr); | |
487 mojo::InterfaceRequest<filesystem::Directory> proxy = GetProxy(target.get()); | |
488 dir->directory->OpenDirectory( | |
489 name, std::move(proxy), filesystem::kFlagRead | filesystem::kFlagWrite, | |
490 base::Bind(&LevelDBFileThread::OnGetChildrenOpened, this, | |
491 base::Passed(&target), contents, done_event, out_error)); | |
492 } | |
493 | |
494 void LevelDBFileThread::OnGetChildrenOpened( | |
495 scoped_ptr<filesystem::DirectoryPtr> dir, | |
496 std::vector<std::string>* contents, | |
497 base::WaitableEvent* done_event, | |
498 filesystem::FileError* out_error, | |
499 filesystem::FileError in_error) { | |
500 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
501 | |
502 if (in_error != filesystem::FileError::OK) { | |
503 *out_error = in_error; | |
504 CompleteWaitableEvent(done_event); | |
505 return; | |
506 } | |
507 | |
508 // Add a dependency between the new directory we opened and the current | |
509 // waitable event. | |
510 dir->set_connection_error_handler( | |
511 base::Bind(&LevelDBFileThread::OnConnectionError, this)); | |
512 waitable_event_dependencies_[done_event].directories.insert(dir.get()); | |
513 | |
514 // We move the object into the bind before we call. Copy to the stack. | |
515 filesystem::DirectoryPtr* local = dir.get(); | |
516 (*local)->Read(base::Bind(&LevelDBFileThread::OnGetChildrenComplete, this, | |
517 base::Passed(&dir), contents, done_event, | |
518 out_error)); | |
519 } | |
520 | |
521 void LevelDBFileThread::OnGetChildrenComplete( | |
522 scoped_ptr<filesystem::DirectoryPtr> dir, | |
523 std::vector<std::string>* out_contents, | |
524 base::WaitableEvent* done_event, | |
525 filesystem::FileError* out_error, | |
526 filesystem::FileError in_error, | |
527 mojo::Array<filesystem::DirectoryEntryPtr> directory_contents) { | |
528 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
529 | |
530 if (!directory_contents.is_null()) { | |
531 for (size_t i = 0; i < directory_contents.size(); ++i) | |
532 out_contents->push_back(directory_contents[i]->name.To<std::string>()); | |
533 } | |
534 | |
535 *out_error = in_error; | |
536 CompleteWaitableEvent(done_event); | |
537 } | |
538 | |
539 void LevelDBFileThread::DeleteImpl(OpaqueDir* dir, | |
540 std::string name, | |
541 uint32_t delete_flags, | |
542 base::WaitableEvent* done_event, | |
543 filesystem::FileError* out_error) { | |
544 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
545 | |
546 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
547 return; | |
548 | |
549 dir->directory->Delete(mojo::String::From(name), delete_flags, | |
550 base::Bind(&LevelDBFileThread::OnSimpleComplete, this, | |
551 done_event, out_error)); | |
552 } | |
553 | |
554 void LevelDBFileThread::CreateDirImpl(OpaqueDir* dir, | |
555 std::string name, | |
556 base::WaitableEvent* done_event, | |
557 filesystem::FileError* out_error) { | |
558 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
559 | |
560 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
561 return; | |
562 | |
563 dir->directory->OpenDirectory( | |
564 name, nullptr, | |
565 filesystem::kFlagRead | filesystem::kFlagWrite | filesystem::kFlagCreate, | |
566 base::Bind(&LevelDBFileThread::OnSimpleComplete, this, done_event, | |
567 out_error)); | |
568 } | |
569 | |
570 void LevelDBFileThread::GetFileSizeImpl(OpaqueDir* dir, | |
571 const std::string& path, | |
572 uint64_t* file_size, | |
573 base::WaitableEvent* done_event, | |
574 filesystem::FileError* out_error) { | |
575 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
576 | |
577 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
578 return; | |
579 | |
580 dir->directory->StatFile( | |
581 path, base::Bind(&LevelDBFileThread::OnGetFileSizeImpl, this, file_size, | |
582 done_event, out_error)); | |
583 } | |
584 | |
585 void LevelDBFileThread::OnGetFileSizeImpl( | |
586 uint64_t* file_size, | |
587 base::WaitableEvent* done_event, | |
588 filesystem::FileError* out_error, | |
589 filesystem::FileError in_error, | |
590 filesystem::FileInformationPtr file_info) { | |
591 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
592 if (file_info) | |
593 *file_size = file_info->size; | |
594 *out_error = in_error; | |
595 CompleteWaitableEvent(done_event); | |
596 } | |
597 | |
598 void LevelDBFileThread::RenameFileImpl(OpaqueDir* dir, | |
599 const std::string& old_path, | |
600 const std::string& new_path, | |
601 base::WaitableEvent* done_event, | |
602 filesystem::FileError* out_error) { | |
603 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
604 | |
605 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
606 return; | |
607 | |
608 dir->directory->Rename(mojo::String::From(old_path), | |
609 mojo::String::From(new_path), | |
610 base::Bind(&LevelDBFileThread::OnSimpleComplete, this, | |
611 done_event, out_error)); | |
612 } | |
613 | |
614 void LevelDBFileThread::LockFileImpl(OpaqueDir* dir, | |
615 const std::string& path, | |
616 base::WaitableEvent* done_event, | |
617 filesystem::FileError* out_error, | |
618 OpaqueLock** out_lock) { | |
619 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
620 | |
621 if (RegisterDirAndWaitableEvent(dir, done_event)) | |
622 return; | |
623 | |
624 // Since a lock is associated with a file descriptor, we need to open and | |
625 // have a persistent file on the other side of the connection. | |
626 scoped_ptr<filesystem::FilePtr> target(new filesystem::FilePtr); | |
627 mojo::InterfaceRequest<filesystem::File> proxy = GetProxy(target.get()); | |
628 dir->directory->OpenFile( | |
629 mojo::String::From(path), std::move(proxy), | |
630 filesystem::kFlagOpenAlways | filesystem::kFlagRead | | |
631 filesystem::kFlagWrite, | |
632 base::Bind(&LevelDBFileThread::OnOpenLockFileComplete, this, | |
633 base::Passed(&target), done_event, out_error, out_lock)); | |
634 } | |
635 | |
636 void LevelDBFileThread::OnOpenLockFileComplete( | |
637 scoped_ptr<filesystem::FilePtr> file, | |
638 base::WaitableEvent* done_event, | |
639 filesystem::FileError* out_error, | |
640 OpaqueLock** out_lock, | |
641 filesystem::FileError in_error) { | |
642 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
643 | |
644 if (in_error != filesystem::FileError::OK) { | |
645 *out_error = in_error; | |
646 CompleteWaitableEvent(done_event); | |
647 return; | |
648 } | |
649 | |
650 // Add a dependency between the new file we opened and the current waitable | |
651 // event. (This dependency will get cleared in OnLockFileComplete if we | |
652 // complete this call safely.) | |
653 file->set_connection_error_handler( | |
654 base::Bind(&LevelDBFileThread::OnConnectionError, this)); | |
655 waitable_event_dependencies_[done_event].files.insert(file.get()); | |
656 | |
657 filesystem::FilePtr* local = file.get(); | |
658 (*local)->Lock(base::Bind(&LevelDBFileThread::OnLockFileComplete, this, | |
659 base::Passed(&file), done_event, out_error, | |
660 out_lock)); | |
661 } | |
662 | |
663 void LevelDBFileThread::OnLockFileComplete(scoped_ptr<filesystem::FilePtr> file, | |
664 base::WaitableEvent* done_event, | |
665 filesystem::FileError* out_error, | |
666 OpaqueLock** out_lock, | |
667 filesystem::FileError in_error) { | |
668 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
669 | |
670 *out_error = in_error; | |
671 | |
672 if (in_error == filesystem::FileError::OK) { | |
673 OpaqueLock* l = new OpaqueLock; | |
674 l->lock_file = std::move(*file); | |
675 *out_lock = l; | |
676 } | |
677 | |
678 CompleteWaitableEvent(done_event); | |
679 } | |
680 | |
681 void LevelDBFileThread::UnlockFileImpl(scoped_ptr<OpaqueLock> lock, | |
682 base::WaitableEvent* done_event, | |
683 filesystem::FileError* out_error) { | |
684 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
685 | |
686 OpaqueLock* local = lock.get(); | |
687 local->lock_file->Unlock(base::Bind(&LevelDBFileThread::OnUnlockFileCompleted, | |
688 this, base::Passed(&lock), done_event, | |
689 out_error)); | |
690 } | |
691 | |
692 void LevelDBFileThread::OnUnlockFileCompleted(scoped_ptr<OpaqueLock> lock, | |
693 base::WaitableEvent* done_event, | |
694 filesystem::FileError* out_error, | |
695 filesystem::FileError in_error) { | |
696 // We're passed the OpauqeLock here for ownership reasons, but it's going to | |
697 // get destructed on its own here. | |
698 DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId()); | |
699 *out_error = in_error; | |
700 CompleteWaitableEvent(done_event); | |
701 } | |
702 | |
703 void LevelDBFileThread::Init() { | |
704 } | |
705 | |
706 void LevelDBFileThread::CleanUp() { | |
707 } | |
708 | |
709 } // namespace leveldb | |
OLD | NEW |