Commit c293082e authored by Marius Gedminas's avatar Marius Gedminas

Don't triplicate connection attempts

The loop over all possible IPv4 and IPv6 addresses turns out to also
loop through all possible socket types (SOCK_STREAM/IPPROTO_TCP,
SOCK_DGRAM/IPPROTO_UDP, SOCK_RAW/IPPROTO_IP).  This meant that each
connection attempt was repeated three times, serially.

This fixes new_addr.test nondeterministic failures.  Here's a short
reminder of what that test does:

  1. Starts a ZEO server on random port X
  2. Connects and creates some data
  3. Stops the ZEO server
  4. Starts a new ZEO server on random port Y
  5. Tells the old connection about the new address
  6. Makes a modification though a new connection
  7. Waits for the old connection to reconnect using the new address,
  8. Verifies that it sees the new data

Here's why the test used to fail:

  * In step 3, when we stop the ZEO server, the client would notice a
    disconnect and immediately try to reconnect.

  * Due to this bug it would open three TCP connections to localhost:X
    and somehow succeed (I've no idea why -- ZEO server is supposed to
    close the listening socket before it drops client connections, so
    how can a new connection to the listening socket succeed?)

  * It would try handshaking each of the connection one after the other,
    timing out after 10 seconds each time (in ZEO.ServerStub.stub).

  * Only after all three connection attempts failed would it sleep for
    `max_disconnect_poll` seconds and then try to connect to localhost:Y

  * Three times 10 seconds is 30 seconds, which is by accident the same
    timeout the test uses in step 7 to wait for a successful
    reconnection.

With this fix the test still does one unnecessary 10 second timeout
before it passes.  I'd love to fix it, but I'm losing hope of
understanding what's actually happening there.
parent 4b44eed1
......@@ -7,7 +7,7 @@ We'll start by setting up a server and connecting to it:
... ('127.0.0.1', 0), {'1': ZODB.FileStorage.FileStorage('t.fs')})
>>> server.start_thread()
>>> conn = ZEO.connection(server.addr)
>>> conn = ZEO.connection(server.addr, max_disconnect_poll=0.1)
>>> client = conn.db().storage
>>> client.is_connected()
True
......
......@@ -444,6 +444,11 @@ class ConnectThread(threading.Thread):
host, port = addr
for (family, socktype, proto, cannoname, sockaddr
) in socket.getaddrinfo(host or 'localhost', port):
# we only speak TCP, so let's skip UDP and RAW sockets
# otherwise we'll try to connect to the same address
# three times in a row
if socktype != socket.SOCK_STREAM:
continue
# for IPv6, drop flowinfo, and restrict addresses
# to [host]:port
yield family, sockaddr[:2]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment