From 767c47ec3007375cbd292a92833eaca3b80cc20c Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Mon, 11 May 2015 18:28:16 +0900 Subject: [PATCH 1/2] Add test for EINTR --- pymemcache/test/test_client.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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') From 15e2bce474f3ee49d0ce562be24e0814163ef99b Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Mon, 11 May 2015 18:34:24 +0900 Subject: [PATCH 2/2] Retry sock.recv() when it raises EINTR --- pymemcache/client.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) 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