diff --git a/pymemcache/client.py b/pymemcache/client.py index b1f5b1b..9262234 100644 --- a/pymemcache/client.py +++ b/pymemcache/client.py @@ -69,7 +69,7 @@ Best Practices: __author__ = "Charles Gordon" - +import errno import socket import six @@ -1056,7 +1056,7 @@ def _readline(sock, buf): chunks.append(buf) last_char = buf[-1:] - buf = sock.recv(RECV_SIZE) + buf = _recv(sock, RECV_SIZE) if not buf: raise MemcacheUnexpectedCloseError() @@ -1087,7 +1087,7 @@ def _readvalue(sock, buf, size): if buf: rlen -= len(buf) chunks.append(buf) - buf = sock.recv(RECV_SIZE) + buf = _recv(sock, RECV_SIZE) if not buf: raise MemcacheUnexpectedCloseError() @@ -1104,3 +1104,13 @@ def _readvalue(sock, buf, size): chunks.append(buf[:rlen - 2]) return buf[rlen:], b''.join(chunks) + + +def _recv(sock, size): + """sock.recv() with retry on EINTR""" + while True: + try: + return sock.recv(size) + except IOError as e: + if e.errno != errno.EINTR: + raise diff --git a/pymemcache/test/test_client.py b/pymemcache/test/test_client.py index c2837a8..689d9e1 100644 --- a/pymemcache/test/test_client.py +++ b/pymemcache/test/test_client.py @@ -13,6 +13,7 @@ # limitations under the License. import collections +import errno import json import socket import unittest @@ -627,3 +628,20 @@ class TestPrefixedPooledClient(TestPrefixedClient): client = PooledClient(None, serializer=serializer, key_prefix=b'xyz:') client.client_pool = pool.ObjectPool(lambda: mock_client) return client + + +class TestRetryOnEINTR(unittest.TestCase): + def make_client(self, values): + client = Client(None) + client.sock = MockSocket(list(values)) + return client + + def test_recv(self): + client = self.make_client([ + b'VALUE ', + socket.error(errno.EINTR, "Interrupted system call"), + b'key1 0 6\r\nval', + socket.error(errno.EINTR, "Interrupted system call"), + b'ue1\r\nEND\r\n', + ]) + tools.assert_equal(client[b'key1'], b'value1')