Skip to content

Commit 5eaaf32

Browse files
committed
Fixes Wdt#80 - Task#8474686
Summary: * Don't overwrite by default * really make sure we either create or open a file * when create we fail unless overwrite is set and truncate it otherwise * fix the timing of open and seek to count all of them not just successes * perf record directory creation too * openAndSetSize now private as it's risky (for retries) * fixed perf reporting bug of missing \n when there is only 1 data point * improved logging of option_type * made resumption imply overwrite * fixed the profiler test/script * make sure failure in shell does print what fails Reviewed By: @uddipta Differential Revision: D2470377
1 parent 1607bd3 commit 5eaaf32

16 files changed

+216
-65
lines changed

CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ cmake_minimum_required(VERSION 3.2)
2222
# There is no C per se in WDT but if you use CXX only here many checks fail
2323
# Version is Major.Minor.YYMMDDX for up to 10 releases per day
2424
# Minor currently is also the protocol version - has to match with Protocol.cpp
25-
project("WDT" LANGUAGES C CXX VERSION 1.20.1509240)
25+
project("WDT" LANGUAGES C CXX VERSION 1.20.1509241)
2626

2727
# On MacOS this requires the latest (master) CMake (and/or CMake 3.1.1/3.2)
2828
set(CMAKE_CXX_STANDARD 11)
@@ -297,4 +297,7 @@ if (BUILD_TESTING)
297297
add_test(NAME WdtFileListTest COMMAND
298298
"${CMAKE_CURRENT_SOURCE_DIR}/wdt_file_list_test.py")
299299

300+
add_test(NAME WdtOverwriteTest COMMAND
301+
"${CMAKE_CURRENT_SOURCE_DIR}/wdt_overwrite_test.py")
302+
300303
endif(BUILD_TESTING)

FileCreator.cpp

+65-14
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,14 @@ bool FileCreator::setFileSize(int fd, int64_t fileSize) {
5555

5656
int FileCreator::openAndSetSize(BlockDetails const *blockDetails) {
5757
const auto &options = WdtOptions::get();
58-
int fd = createFile(blockDetails->fileName);
58+
int fd;
59+
const bool doCreate = blockDetails->allocationStatus == NOT_EXISTS;
60+
const bool isTooLarge = (blockDetails->allocationStatus == EXISTS_TOO_LARGE);
61+
if (doCreate) {
62+
fd = createFile(blockDetails->fileName);
63+
} else {
64+
fd = openExistingFile(blockDetails->fileName);
65+
}
5966
if (fd < 0) {
6067
return -1;
6168
}
@@ -67,14 +74,13 @@ int FileCreator::openAndSetSize(BlockDetails const *blockDetails) {
6774
return -1;
6875
}
6976
if (options.isLogBasedResumption()) {
70-
if (blockDetails->allocationStatus == EXISTS_TOO_LARGE) {
77+
if (isTooLarge) {
7178
LOG(WARNING) << "File size smaller in the sender side "
7279
<< blockDetails->fileName
7380
<< ", marking previous transferred chunks as invalid";
7481
transferLogManager_.addInvalidationEntry(blockDetails->prevSeqId);
7582
}
76-
if (blockDetails->allocationStatus == EXISTS_TOO_LARGE ||
77-
blockDetails->allocationStatus == NOT_EXISTS) {
83+
if (isTooLarge || doCreate) {
7884
transferLogManager_.addFileCreationEntry(
7985
blockDetails->fileName, blockDetails->seqId, blockDetails->fileSize);
8086
} else {
@@ -147,11 +153,33 @@ int FileCreator::openForBlocks(int threadIndex,
147153
return -1;
148154
}
149155
}
150-
return createFile(blockDetails->fileName);
156+
return openExistingFile(blockDetails->fileName);
151157
}
152158

153159
using std::string;
154160

161+
int FileCreator::openExistingFile(const string &relPathStr) {
162+
// This should have been validated earlier and errored out
163+
// instead of crashing here
164+
WDT_CHECK(!relPathStr.empty());
165+
WDT_CHECK(relPathStr[0] != '/');
166+
WDT_CHECK(relPathStr.back() != '/');
167+
168+
string path(rootDir_);
169+
path.append(relPathStr);
170+
171+
int openFlags = O_WRONLY;
172+
START_PERF_TIMER
173+
int res = open(path.c_str(), openFlags, 0644);
174+
RECORD_PERF_RESULT(PerfStatReport::FILE_OPEN)
175+
if (res < 0) {
176+
PLOG(ERROR) << "failed opening file " << path;
177+
return -1;
178+
}
179+
VLOG(1) << "successfully opened file " << path;
180+
return res;
181+
}
182+
155183
int FileCreator::createFile(const string &relPathStr) {
156184
CHECK(!relPathStr.empty());
157185
CHECK(relPathStr[0] != '/');
@@ -167,39 +195,62 @@ int FileCreator::createFile(const string &relPathStr) {
167195
std::string dir;
168196
if (p) {
169197
dir.assign(relPathStr.data(), p);
170-
if (!createDirRecursively(dir)) {
198+
START_PERF_TIMER
199+
const bool dirSuccess1 = createDirRecursively(dir);
200+
RECORD_PERF_RESULT(PerfStatReport::DIRECTORY_CREATE)
201+
if (!dirSuccess1) {
171202
// retry with force
172203
LOG(ERROR) << "failed to create dir " << dir << " recursively, "
173204
<< "trying to force directory creation";
174-
if (!createDirRecursively(dir, true /* force */)) {
205+
START_PERF_TIMER
206+
const bool dirSuccess2 = createDirRecursively(dir, true /* force */);
207+
RECORD_PERF_RESULT(PerfStatReport::DIRECTORY_CREATE)
208+
if (!dirSuccess2) {
175209
LOG(ERROR) << "failed to create dir " << dir << " recursively";
176210
return -1;
177211
}
178212
}
179213
}
180214
int openFlags = O_CREAT | O_WRONLY;
215+
auto &options = WdtOptions::get();
216+
// When doing download resumption we sometime open files that do already
217+
// exist and we need to overwrite them anyway (files which have been
218+
// discarded from the log for some reason)
219+
if (options.overwrite || options.enable_download_resumption) {
220+
// Make sure file size resumption will not get messed up if we
221+
// expect to create this file
222+
openFlags |= O_TRUNC;
223+
} else {
224+
// Make sure open will fail if we don't allow overwriting and
225+
// the file happens to already exist
226+
openFlags |= O_EXCL;
227+
}
181228
START_PERF_TIMER
182229
int res = open(path.c_str(), openFlags, 0644);
230+
RECORD_PERF_RESULT(PerfStatReport::FILE_OPEN)
183231
if (res < 0) {
184232
if (dir.empty()) {
185233
PLOG(ERROR) << "failed creating file " << path;
186234
return -1;
187235
}
188236
PLOG(ERROR) << "failed creating file " << path << ", trying to "
189237
<< "force directory creation";
190-
if (!createDirRecursively(dir, true /* force */)) {
191-
LOG(ERROR) << "failed to create dir " << dir << " recursively";
192-
return -1;
238+
{
239+
START_PERF_TIMER
240+
const bool dirSuccess = createDirRecursively(dir, true /* force */);
241+
RECORD_PERF_RESULT(PerfStatReport::DIRECTORY_CREATE)
242+
if (!dirSuccess) {
243+
LOG(ERROR) << "failed to create dir " << dir << " recursively";
244+
return -1;
245+
}
193246
}
194247
START_PERF_TIMER
195248
res = open(path.c_str(), openFlags, 0644);
249+
RECORD_PERF_RESULT(PerfStatReport::FILE_OPEN)
196250
if (res < 0) {
197251
PLOG(ERROR) << "failed creating file " << path;
198252
return -1;
199253
}
200-
RECORD_PERF_RESULT(PerfStatReport::FILE_OPEN)
201-
} else {
202-
RECORD_PERF_RESULT(PerfStatReport::FILE_OPEN)
203254
}
204255
VLOG(1) << "successfully created file " << path;
205256
return res;
@@ -210,7 +261,7 @@ bool FileCreator::createDirRecursively(const std::string dir, bool force) {
210261
return true;
211262
}
212263

213-
CHECK(dir.back() == '/');
264+
WDT_CHECK(dir.back() == '/');
214265

215266
int64_t lastIndex = dir.size() - 1;
216267
while (lastIndex > 0 && dir[lastIndex - 1] != '/') {

FileCreator.h

+17-12
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,6 @@ class FileCreator {
5757
delete[] threadConditionVariables_;
5858
}
5959

60-
/**
61-
* Opens the file and sets its size. If the existing file size is greater than
62-
* required size, the file is truncated using ftruncate. Space is
63-
* allocated using posix_fallocate.
64-
*
65-
* @param blockDetails block-details
66-
*
67-
* @return file descriptor in case of success, -1 otherwise
68-
*/
69-
int openAndSetSize(BlockDetails const *blockDetails);
70-
7160
/**
7261
* This is used to open the file in block mode. If the current thread is the
7362
* first one to try to open the file, then it allocates space using
@@ -94,18 +83,34 @@ class FileCreator {
9483
}
9584

9685
private:
86+
/**
87+
* Opens the file and sets its size. If the existing file size is greater than
88+
* required size, the file is truncated using ftruncate. Space is
89+
* allocated using posix_fallocate.
90+
*
91+
* @param blockDetails block-details
92+
*
93+
* @return file descriptor in case of success, -1 otherwise
94+
*/
95+
int openAndSetSize(BlockDetails const *blockDetails);
96+
9797
/**
9898
* Create a file and open for writing, recursively create subdirs.
9999
* Subdirs are only created once due to createdDirs_ cache, but
100100
* if an open fails where we assumed the directory already exists
101101
* based on cache, we try creating the dir and open again before
102-
* failing.
102+
* failing. Will not overwrite existing files unless overwrite option
103+
* is set.
103104
*
104105
* @param relPath path relative to root dir
105106
*
106107
* @return file descriptor or -1 on error
107108
*/
108109
int createFile(const std::string &relPath);
110+
/**
111+
* Open existing file
112+
*/
113+
int openExistingFile(const std::string &relPath);
109114

110115
/**
111116
* sets the size of the file. If the size is greater then the

FileWriter.cpp

+9-15
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,15 @@ ErrorCode FileWriter::open() {
2424
if (options.skip_writes) {
2525
return OK;
2626
}
27-
if (blockDetails_->fileSize == blockDetails_->dataSize) {
28-
// single block file
29-
WDT_CHECK(blockDetails_->offset == 0);
30-
fd_ = fileCreator_->openAndSetSize(blockDetails_);
31-
} else {
32-
// multi block file
33-
fd_ = fileCreator_->openForBlocks(threadIndex_, blockDetails_);
34-
if (fd_ >= 0 && blockDetails_->offset > 0) {
35-
START_PERF_TIMER
36-
if (lseek(fd_, blockDetails_->offset, SEEK_SET) < 0) {
37-
PLOG(ERROR) << "Unable to seek " << blockDetails_->fileName;
38-
close();
39-
} else {
40-
RECORD_PERF_RESULT(PerfStatReport::FILE_SEEK)
41-
}
27+
// TODO: consider a working optimization for small files
28+
fd_ = fileCreator_->openForBlocks(threadIndex_, blockDetails_);
29+
if (fd_ >= 0 && blockDetails_->offset > 0) {
30+
START_PERF_TIMER
31+
const int ret = lseek(fd_, blockDetails_->offset, SEEK_SET);
32+
RECORD_PERF_RESULT(PerfStatReport::FILE_SEEK);
33+
if (ret < 0) {
34+
PLOG(ERROR) << "Unable to seek " << blockDetails_->fileName;
35+
close();
4236
}
4337
}
4438
if (fd_ == -1) {

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ Make sure to do the following, before "arc diff":
274274
275275
fbconfig --clang --with-project-version clang:dev -r wdt
276276
277-
fbmake runtests --extended-tests
277+
fbmake runtests --run-disabled --extended-tests
278278
fbmake runtests_opt
279279
fbmake opt
280280

Reporting.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,12 @@ void ProgressReporter::logProgress(int64_t effectiveDataBytes, int progress,
246246
folly::ThreadLocalPtr<PerfStatReport> perfStatReport;
247247

248248
const std::string PerfStatReport::statTypeDescription_[] = {
249-
"Socket Read", "Socket Write", "File Open", "File Close",
250-
"File Read", "File Write", "Sync File Range", "fsync",
251-
"File Seek", "Throttler Sleep", "Receiver Wait Sleep"};
249+
"Socket Read", "Socket Write",
250+
"File Open", "File Close",
251+
"File Read", "File Write",
252+
"Sync File Range", "fsync",
253+
"File Seek", "Throttler Sleep",
254+
"Receiver Wait Sleep", "Directory creation"};
252255

253256
PerfStatReport::PerfStatReport() {
254257
static_assert(
@@ -363,7 +366,7 @@ std::ostream& operator<<(std::ostream& os, const PerfStatReport& statReport) {
363366
os << "p95 " << time << " ";
364367
}
365368
if (p99Count > runningCount && p99Count <= runningCount + count) {
366-
os << "p99 " << time << "\n";
369+
os << "p99 " << time;
367370
}
368371
runningCount += count;
369372

@@ -373,7 +376,7 @@ std::ostream& operator<<(std::ostream& os, const PerfStatReport& statReport) {
373376
}
374377
buckets[currentBucketIndex] += count;
375378
}
376-
379+
os << '\n';
377380
for (int i = 0; i < numBuckets; i++) {
378381
if (buckets[i] == 0) {
379382
continue;

Reporting.h

+1
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ class PerfStatReport {
476476
RECEIVER_WAIT_SLEEP, // receiver sleep duration between sending wait cmd to
477477
// sender. A high sum for this suggests threads
478478
// were not properly load balanced
479+
DIRECTORY_CREATE,
479480
END
480481
};
481482

WdtBase.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ string WdtTransferRequest::generateUrl(bool genFull) const {
286286
wdtUri.setQueryParam(TRANSFER_ID_PARAM, transferId);
287287
wdtUri.setQueryParam(RECEIVER_PROTOCOL_VERSION_PARAM,
288288
folly::to<string>(protocolVersion));
289-
const auto &options = WdtOptions::get();
289+
const auto& options = WdtOptions::get();
290290
if (options.url_backward_compatibility) {
291291
wdtUri.setQueryParam(LEGACY_PROTOCOL_VERSION_PARAM,
292292
folly::to<string>(LEGACY_PROTCOL_VERSION));
@@ -313,7 +313,7 @@ void WdtTransferRequest::serializePorts(WdtUri& wdtUri) const {
313313
}
314314
prevPort = ports[i];
315315
}
316-
const auto &options = WdtOptions::get();
316+
const auto& options = WdtOptions::get();
317317
if (hasHoles || options.url_backward_compatibility) {
318318
wdtUri.setQueryParam(PORTS_PARAM, getSerializedPortsList());
319319
} else {

WdtConfig.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
#define WDT_VERSION_MAJOR 1
1010
#define WDT_VERSION_MINOR 20
11-
#define WDT_VERSION_BUILD 1509240
11+
#define WDT_VERSION_BUILD 1509241
1212
// Add -fbcode to version str
13-
#define WDT_VERSION_STR "1.20.1509240-fbcode"
13+
#define WDT_VERSION_STR "1.20.1509241-fbcode"
1414
// Tie minor and proto version
1515
#define WDT_PROTOCOL_VERSION WDT_VERSION_MINOR
1616

WdtFlags.cpp.inc

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ WDT_OPT(namespace_receiver_limit, int32,
125125
"A value of zero disables limits");
126126

127127
#ifdef WDT_SUPPORTS_ODIRECT
128-
WDT_OPT(odirect_reads, bool,
128+
WDT_OPT(odirect_reads, bool,
129129
"Wdt can read files in O_DIRECT mode, set this flag to true"
130130
" to make sender read all files in O_DIRECT");
131131
#else
@@ -150,3 +150,4 @@ WDT_OPT(open_files_during_discovery, bool,
150150
"If true, files are opened when they are discovered");
151151
WDT_OPT(url_backward_compatibility, bool,
152152
"If true, we send url that works with older version(<19)");
153+
WDT_OPT(overwrite, bool, "Allow the receiver to overwrite existing files");

WdtOptions.cpp

+21-7
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,20 @@
1111
namespace facebook {
1212
namespace wdt {
1313

14-
#define CHANGE_IF_NOT_SPECIFIED(option, specifiedOptions, value) \
15-
if (specifiedOptions.find(#option) == specifiedOptions.end()) { \
16-
option = value; \
14+
/**
15+
* Macro to change the default of some flags based on some other flag
16+
* Example of usage:
17+
* if (enable_download_resumption) {
18+
* CHANGE_IF_NOT_SPECIFIED(overwrite, userSpecifiedOptions, true,
19+
* "(download resumption)")
20+
* }
21+
*/
22+
#define CHANGE_IF_NOT_SPECIFIED(option, specifiedOptions, value, msg) \
23+
if (specifiedOptions.find(#option) == specifiedOptions.end()) { \
24+
LOG(INFO) << "Setting " << #option << " to " << value << " " << msg; \
25+
option = value; \
26+
} else { \
27+
LOG(INFO) << "Not overwriting user specified " << #option << " " << msg; \
1728
}
1829

1930
const std::string WdtOptions::FLASH_OPTION_TYPE = "flash";
@@ -23,10 +34,13 @@ void WdtOptions::modifyOptions(
2334
const std::string& optionType,
2435
const std::set<std::string>& userSpecifiedOptions) {
2536
if (optionType == DISK_OPTION_TYPE) {
26-
CHANGE_IF_NOT_SPECIFIED(num_ports, userSpecifiedOptions, 1)
27-
CHANGE_IF_NOT_SPECIFIED(block_size_mbytes, userSpecifiedOptions, -1)
28-
CHANGE_IF_NOT_SPECIFIED(disable_preallocation, userSpecifiedOptions, true)
29-
CHANGE_IF_NOT_SPECIFIED(resume_using_dir_tree, userSpecifiedOptions, true)
37+
std::string msg("(disk option type)");
38+
CHANGE_IF_NOT_SPECIFIED(num_ports, userSpecifiedOptions, 1, msg)
39+
CHANGE_IF_NOT_SPECIFIED(block_size_mbytes, userSpecifiedOptions, -1, msg)
40+
CHANGE_IF_NOT_SPECIFIED(disable_preallocation, userSpecifiedOptions, true,
41+
msg)
42+
CHANGE_IF_NOT_SPECIFIED(resume_using_dir_tree, userSpecifiedOptions, true,
43+
msg)
3044
return;
3145
}
3246
if (optionType != FLASH_OPTION_TYPE) {

WdtOptions.h

+5
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ class WdtOptions {
300300
*/
301301
bool url_backward_compatibility{false};
302302

303+
/**
304+
* If true, wdt can overwrite existing files
305+
*/
306+
bool overwrite{false};
307+
303308
/**
304309
* @return whether files should be pre-allocated or not
305310
*/

0 commit comments

Comments
 (0)