From: Cyrill Gorcunov <gorcunov@gmail.com> To: tml <tarantool-patches@dev.tarantool.org> Subject: [Tarantool-patches] [PATCH] fio/coio: handle partial writes Date: Wed, 22 Apr 2020 00:39:30 +0300 [thread overview] Message-ID: <20200421213930.28713-1-gorcunov@gmail.com> (raw) Writting less bytes than requested is perfectly fine. In turn our fio.write/pwrite api simply returns 'true' even if only some part of a buffer has been written. Thus make coio_write and coio_pwrite to write the whole data in a cycle. Note in most situations there will be only one pass, partial writes are really the rare cases. Fixes #4651 Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- issue https://github.com/tarantool/tarantool/issues/4651 branch gorcunov/gh-4651-partial-write src/lib/core/coio_file.c | 62 ++++++++++++++++++++++++++++------ src/lib/core/errinj.h | 1 + test/app/fio.result | 73 ++++++++++++++++++++++++++++++++++++++++ test/app/fio.test.lua | 21 ++++++++++++ test/box/errinj.result | 1 + 5 files changed, 147 insertions(+), 11 deletions(-) diff --git a/src/lib/core/coio_file.c b/src/lib/core/coio_file.c index e2345567c..e290214bc 100644 --- a/src/lib/core/coio_file.c +++ b/src/lib/core/coio_file.c @@ -164,10 +164,30 @@ coio_file_close(int fd) ssize_t coio_pwrite(int fd, const void *buf, size_t count, off_t offset) { - INIT_COEIO_FILE(eio); - eio_req *req = eio_write(fd, (void *) buf, count, offset, - 0, coio_complete, &eio); - return coio_wait_done(req, &eio); + ssize_t left = count, pos = 0, res, chunk; + eio_req *req; + + while (left > 0) { + INIT_COEIO_FILE(eio); + chunk = left; + + ERROR_INJECT(ERRINJ_COIO_WRITE_CHUNK, { + chunk = 1; + }); + + req = eio_write(fd, (void *)buf + pos, chunk, + offset + pos, EIO_PRI_DEFAULT, + coio_complete, &eio); + res = coio_wait_done(req, &eio); + if (res < 0) { + pos = -1; + break; + } else { + left -= res; + pos += res; + } + } + return pos; } ssize_t @@ -201,6 +221,11 @@ static void coio_do_write(eio_req *req) { struct coio_file_task *eio = (struct coio_file_task *)req->data; + + ERROR_INJECT(ERRINJ_COIO_WRITE_CHUNK, { + eio->write.count = 1; + }); + req->result = write(eio->write.fd, eio->write.buf, eio->write.count); eio->errorno = errno; } @@ -208,13 +233,28 @@ coio_do_write(eio_req *req) ssize_t coio_write(int fd, const void *buf, size_t count) { - INIT_COEIO_FILE(eio); - eio.write.buf = buf; - eio.write.count = count; - eio.write.fd = fd; - eio_req *req = eio_custom(coio_do_write, 0, - coio_complete, &eio); - return coio_wait_done(req, &eio); + ssize_t left = count, pos = 0, res; + eio_req *req; + + while (left > 0) { + INIT_COEIO_FILE(eio); + + eio.write.buf = buf + pos; + eio.write.count = left; + eio.write.fd = fd; + + req = eio_custom(coio_do_write, EIO_PRI_DEFAULT, + coio_complete, &eio); + res = coio_wait_done(req, &eio); + if (res < 0) { + pos = -1; + break; + } else { + left -= res; + pos += res; + } + } + return pos; } static void diff --git a/src/lib/core/errinj.h b/src/lib/core/errinj.h index 7577ed11a..e95611c1e 100644 --- a/src/lib/core/errinj.h +++ b/src/lib/core/errinj.h @@ -140,6 +140,7 @@ struct errinj { _(ERRINJ_RELAY_FASTER_THAN_TX, ERRINJ_BOOL, {.bparam = false}) \ _(ERRINJ_INDEX_RESERVE, ERRINJ_BOOL, {.bparam = false})\ _(ERRINJ_TXN_COMMIT_ASYNC, ERRINJ_BOOL, {.bparam = false})\ + _(ERRINJ_COIO_WRITE_CHUNK, ERRINJ_BOOL, {.bparam = false}) \ ENUM0(errinj_id, ERRINJ_LIST); extern struct errinj errinjs[]; diff --git a/test/app/fio.result b/test/app/fio.result index 783fa4fab..73fbd29e5 100644 --- a/test/app/fio.result +++ b/test/app/fio.result @@ -776,6 +776,12 @@ file5 = fio.pathjoin(tree, 'file.5') file6 = fio.pathjoin(tree, 'file.6') --- ... +file7 = fio.pathjoin(tree, 'file.7') +--- +... +file8 = fio.pathjoin(tree, 'file.8') +--- +... fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0777', 8)) --- ... @@ -865,6 +871,73 @@ fh6:close() --- - true ... +-- test partial write/pwrite via one byte transfer +fh7 = fio.open(file7, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0644', 8)) +--- +... +errinj.set('ERRINJ_COIO_WRITE_CHUNK', true) +--- +- ok +... +fh7:write("one byte transfer, write") +--- +- true +... +errinj.set('ERRINJ_COIO_WRITE_CHUNK', false) +--- +- ok +... +fh7:seek(0) +--- +- 0 +... +fh7:read() +--- +- one byte transfer, write +... +fh7:close() +--- +- true +... +fh8 = fio.open(file8, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0644', 8)) +--- +... +errinj.set('ERRINJ_COIO_WRITE_CHUNK', true) +--- +- ok +... +fh8:pwrite("one byte transfer, ", 0) +--- +- true +... +fh8:seek(0) +--- +- 0 +... +fh8:read() +--- +- 'one byte transfer, ' +... +fh8:pwrite("pwrite", 19) +--- +- true +... +errinj.set('ERRINJ_COIO_WRITE_CHUNK', false) +--- +- ok +... +fh8:seek(0) +--- +- 0 +... +fh8:read() +--- +- one byte transfer, pwrite +... +fh8:close() +--- +- true +... 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 6825b882f..733e0f25f 100644 --- a/test/app/fio.test.lua +++ b/test/app/fio.test.lua @@ -251,6 +251,8 @@ file3 = fio.pathjoin(tree, 'file.3') file4 = fio.pathjoin(tree, 'file.4') file5 = fio.pathjoin(tree, 'file.5') file6 = fio.pathjoin(tree, 'file.6') +file7 = fio.pathjoin(tree, 'file.7') +file8 = fio.pathjoin(tree, 'file.8') fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0777', 8)) fh1:write("gogo") @@ -280,6 +282,25 @@ fh6:seek(0) fh6:read() fh6:close() +-- test partial write/pwrite via one byte transfer +fh7 = fio.open(file7, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0644', 8)) +errinj.set('ERRINJ_COIO_WRITE_CHUNK', true) +fh7:write("one byte transfer, write") +errinj.set('ERRINJ_COIO_WRITE_CHUNK', false) +fh7:seek(0) +fh7:read() +fh7:close() +fh8 = fio.open(file8, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, tonumber('0644', 8)) +errinj.set('ERRINJ_COIO_WRITE_CHUNK', true) +fh8:pwrite("one byte transfer, ", 0) +fh8:seek(0) +fh8:read() +fh8:pwrite("pwrite", 19) +errinj.set('ERRINJ_COIO_WRITE_CHUNK', false) +fh8:seek(0) +fh8:read() +fh8:close() + 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 de877b708..6b4892500 100644 --- a/test/box/errinj.result +++ b/test/box/errinj.result @@ -47,6 +47,7 @@ evals - ERRINJ_BUILD_INDEX_DELAY: false - ERRINJ_CHECK_FORMAT_DELAY: false - ERRINJ_COIO_SENDFILE_CHUNK: -1 + - ERRINJ_COIO_WRITE_CHUNK: false - ERRINJ_DYN_MODULE_COUNT: 0 - ERRINJ_FIBER_MADVISE: false - ERRINJ_FIBER_MPROTECT: -1 -- 2.20.1
next reply other threads:[~2020-04-21 21:39 UTC|newest] Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-04-21 21:39 Cyrill Gorcunov [this message] 2020-05-06 17:08 ` Alexander Turenko 2020-05-15 9:00 ` Cyrill Gorcunov 2020-06-09 16:55 ` Alexander Turenko 2020-06-09 22:55 ` Vladislav Shpilevoy 2020-06-09 22:55 ` Vladislav Shpilevoy 2020-06-10 7:52 ` Cyrill Gorcunov 2020-06-11 19:36 ` Vladislav Shpilevoy 2020-06-11 19:43 ` Cyrill Gorcunov 2020-06-11 19:56 ` Vladislav Shpilevoy 2020-06-11 20:12 ` Cyrill Gorcunov 2020-06-11 19:56 ` Vladislav Shpilevoy -- strict thread matches above, loose matches on Subject: below -- 2019-11-26 18:05 [Tarantool-patches] [PATCH] fio/coio: Handle " Cyrill Gorcunov 2019-12-04 9:44 ` Cyrill Gorcunov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20200421213930.28713-1-gorcunov@gmail.com \ --to=gorcunov@gmail.com \ --cc=tarantool-patches@dev.tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH] fio/coio: handle partial writes' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox