Merge lp:~bac/python-memcached/bug-974632 into lp:python-memcached

Proposed by Brad Crittenden
Status: Needs review
Proposed branch: lp:~bac/python-memcached/bug-974632
Merge into: lp:python-memcached
Diff against target: 59 lines (+16/-5)
1 file modified
memcache.py (+16/-5)
To merge this branch: bzr merge lp:~bac/python-memcached/bug-974632
Reviewer Review Type Date Requested Status
Sean Reifschneider Disapprove
Review via email: mp+101148@code.launchpad.net

Description of the change

Restore the previous behavior of readline() so that it returns None if the socket is closed. A new internal method _readline() is introduced to provide the uncaught _ConnectionDeadError exception for the places that wish to catch it and do a retry.

To post a comment you must log in.
Revision history for this message
Sean Reifschneider (jafo) wrote :

I think this misses some cases that the current could would also raise an exception in. This is a good start, and helped me understand the problem, thanks for the patch, but I've made some other changes which include restoring the readline() back to not raising an exception in most cases, and the _unsafe_*() functions calling functions which explicitly request that readline() raise the exception.

I'm going to commit a change shortly, would you mind reviewing it and seeing if it fixes the issue?

Thanks,
Sean

review: Disapprove
Revision history for this message
Brad Crittenden (bac) wrote :

Hi Sean, thanks for looking at this code.

Your comment confuses me a little because the approach you describe as your preferred solution seems to be what I've implemented, that is the readline() method is restored to never throw an exception while the unsafe do call a special method that can raise the exception. I called this new method _readline(), which could've been named better.

Perhaps there are call sites that use _expectvalue that I missed?

Anyway, I'll be happy to review the patch you produce.

Revision history for this message
Sean Reifschneider (jafo) wrote :

On 04/11/2012 04:37 AM, Brad Crittenden wrote:
> Your comment confuses me a little because the approach you describe

I guess the simplest explanation I can give is that my patches changes the
semantics back to how they were before Tarek's patch -- exceptions aren't
raised by that code. Only in the cases where the higher-level code
explicitly requests the exceptions are they generated.

I don't recall exactly what I saw that I thought might still leak
exceptions, but it just "felt right" this way, basically reverting to the
old behavior, regarding exception generation.

Thoughts?

Thanks,
Sean

Unmerged revisions

57. By Brad Crittenden

Provide a wrapper to handled _ConnectionDeadErrors so that readline() behaves as before.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'memcache.py'
2--- memcache.py 2011-11-29 19:34:32 +0000
3+++ memcache.py 2012-04-06 19:18:22 +0000
4@@ -182,7 +182,7 @@
5 @param cache_cas: (default False) If true, cas operations will be
6 cached. WARNING: This cache is not expired internally, if you have
7 a long-running process you will need to expire it manually via
8- "client.reset_cas(), or the cache can grow unlimited.
9+ client.reset_cas(), or the cache can grow unlimited.
10 @param server_max_key_length: (default SERVER_MAX_KEY_LENGTH)
11 Data that is larger than this will not be sent to the server.
12 @param server_max_value_length: (default SERVER_MAX_VALUE_LENGTH)
13@@ -960,7 +960,7 @@
14
15 def _expectvalue(self, server, line=None):
16 if not line:
17- line = server.readline()
18+ line = server._readline()
19
20 if line and line[:5] == 'VALUE':
21 resp, rkey, flags, len = line.split()
22@@ -1064,8 +1064,8 @@
23 else:
24 self.family = socket.AF_INET
25 self.ip = hostData['host']
26- self.port = int(hostData.get('port', 11211))
27- self.address = ( self.ip, self.port )
28+ self.port = int(hostData.get('port') or 11211)
29+ self.address = (self.ip, self.port)
30
31 self.deaduntil = 0
32 self.socket = None
33@@ -1130,7 +1130,11 @@
34 """ cmds already has trailing \r\n's applied """
35 self.socket.sendall(cmds)
36
37- def readline(self):
38+ def _readline(self):
39+ """Read from the socket.
40+
41+ If the socket is closed (Raises _ConnectionDeadError).
42+ """
43 buf = self.buffer
44 recv = self.socket.recv
45 while True:
46@@ -1147,6 +1151,13 @@
47 self.buffer = buf[index+2:]
48 return buf[:index]
49
50+ def readline(self):
51+ """Read a line. If the connection is dead, return None."""
52+ try:
53+ return self._readline()
54+ except _ConnectionDeadError:
55+ return None
56+
57 def expect(self, text):
58 line = self.readline()
59 if line != text:

Subscribers

People subscribed via source and target branches