summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHumble Devassy Chirammal <humble.devassy@gmail.com>2016-03-18 03:07:06 -0700
committerGerrit Code Review <review@dev.gluster.org>2016-03-18 03:07:06 -0700
commit9466403495084eb9a197c1fe30bfa40a68b8feec (patch)
tree701c26b0861f800ea6c196bb81a2e21caf369263
parent1815ad27684435a0612c987b5d6d8893417593f8 (diff)
parent14c16992b563a77330478bcc6fecdb54df4300b5 (diff)
Merge "Add readinto() API"
-rwxr-xr-xgluster/gfapi.py23
-rw-r--r--test/functional/libgfapi-python-tests.py18
-rw-r--r--test/unit/gluster/test_gfapi.py11
3 files changed, 52 insertions, 0 deletions
diff --git a/gluster/gfapi.py b/gluster/gfapi.py
index fa0e1b3..d6f847d 100755
--- a/gluster/gfapi.py
+++ b/gluster/gfapi.py
@@ -328,6 +328,29 @@ class File(object):
err = ctypes.get_errno()
raise OSError(err, os.strerror(err))
+ def readinto(self, buf):
+ """
+ Read up to len(buf) bytes into buf which must be a bytearray.
+ (buf cannot be a string as strings are immutable in python)
+
+ This method is useful when you have to read a large file over
+ multiple read calls. While read() allocates a buffer every time
+ it's invoked, readinto() copies data to an already allocated
+ buffer passed to it.
+
+ Returns the number of bytes read (0 for EOF).
+ """
+ if type(buf) is bytearray:
+ buf_ptr = (ctypes.c_ubyte * len(buf)).from_buffer(buf)
+ else:
+ # TODO: Allow reading other types such as array.array
+ raise TypeError("buffer must of type bytearray")
+ nread = api.glfs_read(self.fd, buf_ptr, len(buf_ptr), 0)
+ if nread < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return nread
+
def write(self, data, flags=0):
"""
Write data to the file.
diff --git a/test/functional/libgfapi-python-tests.py b/test/functional/libgfapi-python-tests.py
index 6840d18..3a0b89e 100644
--- a/test/functional/libgfapi-python-tests.py
+++ b/test/functional/libgfapi-python-tests.py
@@ -502,6 +502,24 @@ class FileOpsTest(unittest.TestCase):
self.vol.symlink(file_name, link_name)
self.assertEqual(self.vol.readlink(link_name), file_name)
+ def test_readinto(self):
+ file_name = uuid4().hex
+ with File(self.vol.open(file_name, os.O_WRONLY | os.O_CREAT)) as f:
+ s = ''.join([str(i) for i in xrange(10)])
+ f.write(s)
+ f.fsync()
+
+ buf = bytearray(1)
+ with File(self.vol.open(file_name, os.O_RDONLY)) as f:
+ for i in xrange(10):
+ # Read one character at a time into buf
+ f.readinto(buf)
+ self.assertEqual(len(buf), 1)
+ self.assertEqual(buf, bytearray(str(i)))
+
+ with File(self.vol.open(file_name, os.O_RDONLY)) as f:
+ self.assertRaises(TypeError, f.readinto, str("buf"))
+
class DirOpsTest(unittest.TestCase):
diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py
index 5551235..4be2346 100644
--- a/test/unit/gluster/test_gfapi.py
+++ b/test/unit/gluster/test_gfapi.py
@@ -192,6 +192,17 @@ class TestFile(unittest.TestCase):
with patch("gluster.gfapi.File.fgetsize", _mock_fgetsize):
self.fd.read(buflen)
+ def test_readinto(self):
+ mock_glfs_read = Mock()
+ mock_glfs_read.return_value = 5
+
+ with patch("gluster.gfapi.api.glfs_read", mock_glfs_read):
+ buf = bytearray(10)
+ ret = self.fd.readinto(buf)
+ self.assertEqual(ret, 5)
+
+ self.assertRaises(TypeError, self.fd.readinto, str("hello"))
+
def test_write_success(self):
mock_glfs_write = Mock()
mock_glfs_write.return_value = 5