| 537 | } |
| 538 | |
| 539 | ACTOR static Future<Void> openFiles(RawDiskQueue_TwoFiles* self) { |
| 540 | state std::vector<Future<Reference<IAsyncFile>>> fs; |
| 541 | fs.reserve(2); |
| 542 | for (int i = 0; i < 2; i++) |
| 543 | fs.push_back(IAsyncFileSystem::filesystem()->open(self->filename(i), |
| 544 | IAsyncFile::OPEN_READWRITE | IAsyncFile::OPEN_UNCACHED | |
| 545 | IAsyncFile::OPEN_UNBUFFERED | IAsyncFile::OPEN_LOCK, |
| 546 | 0)); |
| 547 | wait(waitForAllReady(fs)); |
| 548 | |
| 549 | // Treatment of errors here is important. If only one of the two files is present |
| 550 | // (due to a power failure during creation or deletion, or administrative error) we don't want to |
| 551 | // open the queue! |
| 552 | |
| 553 | if (!fs[0].isError() && !fs[1].isError()) { |
| 554 | // Both files were opened OK: success |
| 555 | } else if (fs[0].isError() && fs[0].getError().code() == error_code_file_not_found && fs[1].isError() && |
| 556 | fs[1].getError().code() == error_code_file_not_found) { |
| 557 | // Neither file was found: we can create a new queue |
| 558 | // OPEN_ATOMIC_WRITE_AND_CREATE defers creation (using a .part file) until the calls to sync() below |
| 559 | TraceEvent("DiskQueueCreate").detail("File0", self->filename(0)); |
| 560 | for (int i = 0; i < 2; i++) |
| 561 | fs[i] = IAsyncFileSystem::filesystem()->open( |
| 562 | self->filename(i), |
| 563 | IAsyncFile::OPEN_ATOMIC_WRITE_AND_CREATE | IAsyncFile::OPEN_CREATE | IAsyncFile::OPEN_READWRITE | |
| 564 | IAsyncFile::OPEN_UNCACHED | IAsyncFile::OPEN_UNBUFFERED | IAsyncFile::OPEN_LOCK, |
| 565 | 0600); |
| 566 | |
| 567 | // Any error here is fatal |
| 568 | wait(waitForAll(fs)); |
| 569 | |
| 570 | // sync on each file to actually create it will be done below |
| 571 | } else { |
| 572 | // One file had a more serious error or one file is present and the other is not. Die. |
| 573 | if (!fs[0].isError() || (fs[1].isError() && fs[1].getError().code() != error_code_file_not_found)) |
| 574 | throw fs[1].getError(); |
| 575 | else |
| 576 | throw fs[0].getError(); |
| 577 | } |
| 578 | |
| 579 | // fsync both files. This is necessary to trigger atomic file creation in the creation case above. |
| 580 | // It also permits the recovery code to assume that whatever it reads is durable. Otherwise a prior |
| 581 | // process could have written (but not synchronized) data to the file which we will read but which |
| 582 | // might not survive a reboot. The recovery code assumes otherwise and could corrupt the disk. |
| 583 | std::vector<Future<Void>> syncs; |
| 584 | syncs.reserve(fs.size()); |
| 585 | for (int i = 0; i < fs.size(); i++) |
| 586 | syncs.push_back(fs[i].get()->sync()); |
| 587 | wait(waitForAll(syncs)); |
| 588 | |
| 589 | // Successfully opened or created; fill in self->files[] |
| 590 | for (int i = 0; i < 2; i++) |
| 591 | self->files[i].setFile(fs[i].get()); |
| 592 | |
| 593 | return Void(); |
| 594 | } |
| 595 | |
| 596 | ACTOR static void shutdown(RawDiskQueue_TwoFiles* self, bool deleteFiles) { |
nothing calls this directly
no test coverage detected