[patches] [fio 1/1] fio: Fix race condition in fio.read
Ilya Markov
imarkov at tarantool.org
Fri Mar 2 17:46:23 MSK 2018
From: imarkov <imarkov at tarantool.org>
When fio.read from multiple fibers is performed, as fio.read yields before
performing actual read operation and ibuf shared among several fibers
may be corrupted and read data is mixed.
The fix is to create new ibuf for each fio.read call in case
buffer is not specified.
Closes #3187
branch gh-3187-fio-read-race
---
src/lua/fio.lua | 3 +--
test/app/fio.result | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++
test/app/fio.test.lua | 29 +++++++++++++++++++++
3 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/src/lua/fio.lua b/src/lua/fio.lua
index d48c709..73719df 100644
--- a/src/lua/fio.lua
+++ b/src/lua/fio.lua
@@ -40,8 +40,7 @@ fio_methods.read = function(self, buf, size)
end
if not ffi.istype(const_char_ptr_t, buf) then
size = buf or size
- tmpbuf = buffer.IBUF_SHARED
- tmpbuf:reset()
+ tmpbuf = buffer.ibuf()
buf = tmpbuf:reserve(size)
end
local res, err = internal.read(self.fh, buf, size)
diff --git a/test/app/fio.result b/test/app/fio.result
index 0fc8582..6c46098 100644
--- a/test/app/fio.result
+++ b/test/app/fio.result
@@ -1067,6 +1067,76 @@ fio.unlink(tmpfile)
---
- true
...
+tmp1 = fio.pathjoin(tmpdir, "tmp1")
+---
+...
+tmp2= fio.pathjoin(tmpdir, "tmp2")
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function write_file(name, odd)
+ local fh = fio.open(name, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777)
+ if odd then
+ fh:write(string.rep('1', 100))
+ else
+ fh:write(string.rep('2', 100))
+ end
+ fh:write(name)
+ fh:seek(0)
+ return fh
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+fh1 = write_file(tmp1)
+---
+...
+fh2 = write_file(tmp2)
+---
+...
+fiber = require('fiber')
+---
+...
+digest = require('digest')
+---
+...
+str = fh1:read()
+---
+...
+fh1:seek(0)
+---
+- 0
+...
+hash = digest.crc32(str)
+---
+...
+ch = fiber.channel(1)
+---
+...
+f1 = fiber.create(function() str = fh1:read() ch:put(digest.crc32(str)) end)
+---
+...
+f2 = fiber.create(function() str = fh2:read() end)
+---
+...
+ch:get() == hash
+---
+- true
+...
+fio.unlink(tmp1)
+---
+- true
+...
+fio.unlink(tmp2)
+---
+- true
+...
fio.rmdir(tmpdir)
---
- true
diff --git a/test/app/fio.test.lua b/test/app/fio.test.lua
index cd0bc16..0850413 100644
--- a/test/app/fio.test.lua
+++ b/test/app/fio.test.lua
@@ -342,4 +342,33 @@ fio.path.lexists(link)
fio.unlink(link)
fio.unlink(tmpfile)
+tmp1 = fio.pathjoin(tmpdir, "tmp1")
+tmp2= fio.pathjoin(tmpdir, "tmp2")
+test_run:cmd("setopt delimiter ';'")
+function write_file(name, odd)
+ local fh = fio.open(name, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777)
+ if odd then
+ fh:write(string.rep('1', 100))
+ else
+ fh:write(string.rep('2', 100))
+ end
+ fh:write(name)
+ fh:seek(0)
+ return fh
+end;
+test_run:cmd("setopt delimiter ''");
+fh1 = write_file(tmp1)
+fh2 = write_file(tmp2)
+fiber = require('fiber')
+digest = require('digest')
+str = fh1:read()
+fh1:seek(0)
+hash = digest.crc32(str)
+ch = fiber.channel(1)
+f1 = fiber.create(function() str = fh1:read() ch:put(digest.crc32(str)) end)
+f2 = fiber.create(function() str = fh2:read() end)
+ch:get() == hash
+
+fio.unlink(tmp1)
+fio.unlink(tmp2)
fio.rmdir(tmpdir)
--
2.7.4
More information about the Tarantool-patches
mailing list