Skip to content

Commit 161eebe

Browse files
committed
casync-http: reuse write_chunk to download index
This commit fixes a download issue. Now, the casync-http process writes the whole index in one shot upon the download is completed, instead of streaming it to the casync process. The transfer may end with CURLE_PARTIAL_FILE when the download of the index does not complete before casync starts seeding. That issue is reproducible when the seed operation is very long. A large device block of 9.5GB is good enough to reproduce the issue. In this situation, the cURL transfer starts in the casync-http process and the write_index() function streams the data received to the casync process through stdout. In the meanwhile, the casync process starts the long seeding operation that causes the casync-http process to hold on the transfer as the poller blocks it in the function process_remote(). Many minutes later, when the seeding operation ends, the poll in casync-http returns and the function robust_curl_easy_perform() returns CURLE_PARTIAL_FILE (which stands for "Transferred a partial file" in a human-readable format, according to curl_easy_strerror()). The commit does not call the poller anymore in the middle of the transfer of the index, as for chunks. It appends the data to the realloc buffer instead. Then, it sends the whole data upon the transfer is complete. The commit reuses the function write_chunk() to download both index and chunk. It renames that function to write_buffer() that is more generic. The buffer is then written to casync using the former function write_index() that is freed from cURL stuff. This commit fixes the issue below: $ casync extract http://localhost/rootfs-9.5GB.caibx /dev/sda6 -v Failed to acquire http://localhost/rootfs/rootfs-9.5G.caibx Failed to run synchronizer: Broken pipe
1 parent e8fd544 commit 161eebe

File tree

1 file changed

+24
-20
lines changed

1 file changed

+24
-20
lines changed

src/casync-http.c

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,22 @@ static int process_remote(CaRemote *rr, ProcessUntil until) {
167167
}
168168
}
169169

170-
static size_t write_index(const void *buffer, size_t size, size_t nmemb, void *userdata) {
171-
CaRemote *rr = userdata;
172-
size_t product;
170+
static int write_index(CaRemote *rr, ReallocBuffer *buffer) {
173171
int r;
174172

175-
product = size * nmemb;
173+
assert(rr);
176174

177175
r = process_remote(rr, PROCESS_UNTIL_CAN_PUT_INDEX);
178176
if (r < 0)
179-
return 0;
177+
return r;
180178

181-
r = ca_remote_put_index(rr, buffer, product);
179+
r = ca_remote_put_index(rr, realloc_buffer_data(buffer), realloc_buffer_size(buffer));
182180
if (r < 0) {
183181
log_error("Failed to put index: %m");
184-
return 0;
182+
return r;
185183
}
186184

187-
return product;
185+
return 0;
188186
}
189187

190188
static int write_index_eof(CaRemote *rr) {
@@ -239,24 +237,24 @@ static int write_archive_eof(CaRemote *rr) {
239237
return 0;
240238
}
241239

242-
static size_t write_chunk(const void *buffer, size_t size, size_t nmemb, void *userdata) {
243-
ReallocBuffer *chunk_buffer = userdata;
240+
static size_t write_buffer(const void *ptr, size_t size, size_t nmemb, void *userdata) {
241+
ReallocBuffer *buffer = userdata;
244242
size_t product, z;
245243

246244
product = size * nmemb;
247245

248-
z = realloc_buffer_size(chunk_buffer) + product;
249-
if (z < realloc_buffer_size(chunk_buffer)) {
246+
z = realloc_buffer_size(buffer) + product;
247+
if (z < realloc_buffer_size(buffer)) {
250248
log_error("Overflow");
251249
return 0;
252250
}
253251

254252
if (z > (CA_PROTOCOL_SIZE_MAX - offsetof(CaProtocolChunk, data))) {
255-
log_error("Chunk too large");
253+
log_error("Message too large");
256254
return 0;
257255
}
258256

259-
if (!realloc_buffer_append(chunk_buffer, buffer, product)) {
257+
if (!realloc_buffer_append(buffer, ptr, product)) {
260258
log_oom();
261259
return 0;
262260
}
@@ -375,7 +373,7 @@ static int run(int argc, char *argv[]) {
375373
size_t n_stores = 0, current_store = 0;
376374
CURL *curl = NULL;
377375
_cleanup_(ca_remote_unrefp) CaRemote *rr = NULL;
378-
_cleanup_(realloc_buffer_free) ReallocBuffer chunk_buffer = {};
376+
_cleanup_(realloc_buffer_free) ReallocBuffer buffer = {};
379377
_cleanup_free_ char *url_buffer = NULL;
380378
long protocol_status;
381379
int r;
@@ -480,15 +478,21 @@ static int run(int argc, char *argv[]) {
480478
}
481479

482480
if (index_url) {
483-
r = acquire_file(rr, curl, index_url, write_index, rr);
481+
r = acquire_file(rr, curl, index_url, write_buffer, &buffer);
484482
if (r < 0)
485483
goto finish;
486484
if (r == 0)
487485
goto flush;
488486

487+
r = write_index(rr, &buffer);
488+
if (r < 0)
489+
goto finish;
490+
489491
r = write_index_eof(rr);
490492
if (r < 0)
491493
goto finish;
494+
495+
realloc_buffer_empty(&buffer);
492496
}
493497

494498
for (;;) {
@@ -540,13 +544,13 @@ static int run(int argc, char *argv[]) {
540544
goto finish;
541545
}
542546

543-
if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_chunk) != CURLE_OK) {
547+
if (curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer) != CURLE_OK) {
544548
log_error("Failed to set CURL callback function.");
545549
r = -EIO;
546550
goto finish;
547551
}
548552

549-
if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk_buffer) != CURLE_OK) {
553+
if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer) != CURLE_OK) {
550554
log_error("Failed to set CURL private data.");
551555
r = -EIO;
552556
goto finish;
@@ -592,7 +596,7 @@ static int run(int argc, char *argv[]) {
592596
(arg_protocol == ARG_PROTOCOL_FTP && (protocol_status >= 200 && protocol_status <= 299))||
593597
(arg_protocol == ARG_PROTOCOL_SFTP && (protocol_status == 0))) {
594598

595-
r = ca_remote_put_chunk(rr, &id, CA_CHUNK_COMPRESSED, realloc_buffer_data(&chunk_buffer), realloc_buffer_size(&chunk_buffer));
599+
r = ca_remote_put_chunk(rr, &id, CA_CHUNK_COMPRESSED, realloc_buffer_data(&buffer), realloc_buffer_size(&buffer));
596600
if (r < 0) {
597601
log_error_errno(r, "Failed to write chunk: %m");
598602
goto finish;
@@ -609,7 +613,7 @@ static int run(int argc, char *argv[]) {
609613
}
610614
}
611615

612-
realloc_buffer_empty(&chunk_buffer);
616+
realloc_buffer_empty(&buffer);
613617

614618
r = process_remote(rr, PROCESS_UNTIL_WRITTEN);
615619
if (r == -EPIPE) {

0 commit comments

Comments
 (0)