From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Return-Path: From: Cyrill Gorcunov Subject: [PATCH v5] core/coio_file: Use eio_sendfile_sync instead of a chunk mode Date: Thu, 18 Apr 2019 23:49:58 +0300 Message-Id: <20190418204958.6824-1-gorcunov@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit To: tml Cc: Vladimir Davydov , Cyrill Gorcunov List-ID: eio library provides a portable version of sendfile syscall which works a way more efficient than explicit copying file by 4K chunks. --- v5: - Merge three patches into one - Update box/errinj test - Build as Release and rerun fio/box tests src/lib/core/coio_file.c | 33 ++++++++++++++++++--------------- src/lib/core/errinj.h | 1 + test/app/fio.result | 23 +++++++++++++++++++++++ test/app/fio.test.lua | 8 ++++++++ test/box/errinj.result | 2 ++ 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/lib/core/coio_file.c b/src/lib/core/coio_file.c index c5b2db781..3caf185a5 100644 --- a/src/lib/core/coio_file.c +++ b/src/lib/core/coio_file.c @@ -33,6 +33,7 @@ #include "fiber.h" #include "say.h" #include "fio.h" +#include "errinj.h" #include #include #include @@ -570,8 +571,9 @@ coio_readdir(const char *dir_path, char **buf) static void coio_do_copyfile(eio_req *req) { + struct errinj *inj = errinj(ERRINJ_COIO_SENDFILE_CHUNK, ERRINJ_INT); struct coio_file_task *eio = (struct coio_file_task *)req->data; - + off_t pos, ret, left, chunk; struct stat st; if (stat(eio->copyfile.source, &st) < 0) { goto error; @@ -588,22 +590,23 @@ coio_do_copyfile(eio_req *req) goto error_dest; } - enum { COPY_FILE_BUF_SIZE = 4096 }; - - char buf[COPY_FILE_BUF_SIZE]; - - while (true) { - ssize_t nread = fio_read(source_fd, buf, sizeof(buf)); - if (nread < 0) - goto error_copy; - - if (nread == 0) - break; /* eof */ - - ssize_t nwritten = fio_writen(dest_fd, buf, nread); - if (nwritten < 0) + if (inj != NULL && inj->iparam > 0) + chunk = (off_t)inj->iparam; + else + chunk = st.st_size; + + for (left = st.st_size, pos = 0; left > 0;) { + ret = eio_sendfile_sync(dest_fd, source_fd, pos, chunk); + if (ret < 0) { + say_syserror("sendfile, [%s -> %s]", + fio_filename(source_fd), + fio_filename(dest_fd)); goto error_copy; + } + pos += ret; + left -= ret; } + req->result = 0; close(source_fd); close(dest_fd); diff --git a/src/lib/core/errinj.h b/src/lib/core/errinj.h index 4bca81caf..462c98464 100644 --- a/src/lib/core/errinj.h +++ b/src/lib/core/errinj.h @@ -129,6 +129,7 @@ struct errinj { _(ERRINJ_MEMTX_DELAY_GC, ERRINJ_BOOL, {.bparam = false}) \ _(ERRINJ_SIO_READ_MAX, ERRINJ_INT, {.iparam = -1}) \ _(ERRINJ_SQL_NAME_NORMALIZATION, ERRINJ_BOOL, {.bparam = false}) \ + _(ERRINJ_COIO_SENDFILE_CHUNK, ERRINJ_INT, {.iparam = -1}) \ ENUM0(errinj_id, ERRINJ_LIST); extern struct errinj errinjs[]; diff --git a/test/app/fio.result b/test/app/fio.result index 486cb8043..879e0a767 100644 --- a/test/app/fio.result +++ b/test/app/fio.result @@ -718,6 +718,9 @@ file2 = fio.pathjoin(tmp2, 'file.2') file3 = fio.pathjoin(tree, 'file.3') --- ... +file4 = fio.pathjoin(tree, 'file.4') +--- +... fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777) --- ... @@ -752,6 +755,26 @@ fio.stat(fio.pathjoin(tmp2, "file.1")) ~= nil --- - true ... +--- test copyfile to operate with one byte transfer +errinj = box.error.injection +--- +... +errinj.set('ERRINJ_COIO_SENDFILE_CHUNK', 1) +--- +- ok +... +fio.copyfile(file1, file4) +--- +- true +... +fio.stat(file1, file4) ~= nil +--- +- true +... +errinj.set('ERRINJ_COIO_SENDFILE_CHUNK', -1) +--- +- ok +... res, err = fio.copyfile(fio.pathjoin(tmp1, 'not_exists.txt'), tmp1) --- ... diff --git a/test/app/fio.test.lua b/test/app/fio.test.lua index 9af37044d..1255b2804 100644 --- a/test/app/fio.test.lua +++ b/test/app/fio.test.lua @@ -230,6 +230,7 @@ fio.mktree(tree2, 0777) file1 = fio.pathjoin(tmp1, 'file.1') file2 = fio.pathjoin(tmp2, 'file.2') file3 = fio.pathjoin(tree, 'file.3') +file4 = fio.pathjoin(tree, 'file.4') fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777) fh1:write("gogo") @@ -241,6 +242,13 @@ fio.symlink(file1, file3) fio.copyfile(file1, tmp2) fio.stat(fio.pathjoin(tmp2, "file.1")) ~= nil +--- test copyfile to operate with one byte transfer +errinj = box.error.injection +errinj.set('ERRINJ_COIO_SENDFILE_CHUNK', 1) +fio.copyfile(file1, file4) +fio.stat(file1, file4) ~= nil +errinj.set('ERRINJ_COIO_SENDFILE_CHUNK', -1) + res, err = fio.copyfile(fio.pathjoin(tmp1, 'not_exists.txt'), tmp1) res err:match("failed to copy") ~= nil diff --git a/test/box/errinj.result b/test/box/errinj.result index 5905f8ee0..fe4ba63bd 100644 --- a/test/box/errinj.result +++ b/test/box/errinj.result @@ -38,6 +38,8 @@ errinj.info() state: false ERRINJ_VYRUN_INDEX_GARBAGE: state: false + ERRINJ_COIO_SENDFILE_CHUNK: + state: -1 ERRINJ_VY_INDEX_FILE_RENAME: state: false ERRINJ_VY_POINT_ITER_WAIT: -- 2.20.1