##// END OF EJS Templates
remotefilelog: rework workaround for sshpeer deadlocks...
Valentin Gatien-Baron -
r47417:0509cee3 default
parent child Browse files
Show More
@@ -1,88 +1,90
1 # connectionpool.py - class for pooling peer connections for reuse
1 # connectionpool.py - class for pooling peer connections for reuse
2 #
2 #
3 # Copyright 2017 Facebook, Inc.
3 # Copyright 2017 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from mercurial import (
10 from mercurial import (
11 extensions,
11 extensions,
12 hg,
12 hg,
13 pycompat,
13 pycompat,
14 sshpeer,
14 sshpeer,
15 util,
15 util,
16 )
16 )
17
17
18 _sshv1peer = sshpeer.sshv1peer
18 _sshv1peer = sshpeer.sshv1peer
19
19
20
20
21 class connectionpool(object):
21 class connectionpool(object):
22 def __init__(self, repo):
22 def __init__(self, repo):
23 self._repo = repo
23 self._repo = repo
24 self._pool = dict()
24 self._pool = dict()
25
25
26 def get(self, path):
26 def get(self, path):
27 pathpool = self._pool.get(path)
27 pathpool = self._pool.get(path)
28 if pathpool is None:
28 if pathpool is None:
29 pathpool = list()
29 pathpool = list()
30 self._pool[path] = pathpool
30 self._pool[path] = pathpool
31
31
32 conn = None
32 conn = None
33 if len(pathpool) > 0:
33 if len(pathpool) > 0:
34 try:
34 try:
35 conn = pathpool.pop()
35 conn = pathpool.pop()
36 peer = conn.peer
36 peer = conn.peer
37 # If the connection has died, drop it
37 # If the connection has died, drop it
38 if isinstance(peer, _sshv1peer):
38 if isinstance(peer, _sshv1peer):
39 if peer._subprocess.poll() is not None:
39 if peer._subprocess.poll() is not None:
40 conn = None
40 conn = None
41 except IndexError:
41 except IndexError:
42 pass
42 pass
43
43
44 if conn is None:
44 if conn is None:
45
45
46 def _cleanup(orig):
46 peer = hg.peer(self._repo.ui, {}, path)
47 # close pipee first so peer.cleanup reading it won't deadlock,
47 if util.safehasattr(peer, '_cleanup'):
48 # if there are other processes with pipeo open (i.e. us).
49 peer = orig.im_self
50 if util.safehasattr(peer, 'pipee'):
51 peer.pipee.close()
52 return orig()
53
48
54 peer = hg.peer(self._repo.ui, {}, path)
49 class mypeer(peer.__class__):
55 if util.safehasattr(peer, 'cleanup'):
50 def _cleanup(self):
56 extensions.wrapfunction(peer, b'cleanup', _cleanup)
51 # close pipee first so peer.cleanup reading it won't
52 # deadlock, if there are other processes with pipeo
53 # open (i.e. us).
54 if util.safehasattr(self, 'pipee'):
55 self.pipee.close()
56 return super(mypeer, self)._cleanup()
57
58 peer.__class__ = mypeer
57
59
58 conn = connection(pathpool, peer)
60 conn = connection(pathpool, peer)
59
61
60 return conn
62 return conn
61
63
62 def close(self):
64 def close(self):
63 for pathpool in pycompat.itervalues(self._pool):
65 for pathpool in pycompat.itervalues(self._pool):
64 for conn in pathpool:
66 for conn in pathpool:
65 conn.close()
67 conn.close()
66 del pathpool[:]
68 del pathpool[:]
67
69
68
70
69 class connection(object):
71 class connection(object):
70 def __init__(self, pool, peer):
72 def __init__(self, pool, peer):
71 self._pool = pool
73 self._pool = pool
72 self.peer = peer
74 self.peer = peer
73
75
74 def __enter__(self):
76 def __enter__(self):
75 return self
77 return self
76
78
77 def __exit__(self, type, value, traceback):
79 def __exit__(self, type, value, traceback):
78 # Only add the connection back to the pool if there was no exception,
80 # Only add the connection back to the pool if there was no exception,
79 # since an exception could mean the connection is not in a reusable
81 # since an exception could mean the connection is not in a reusable
80 # state.
82 # state.
81 if type is None:
83 if type is None:
82 self._pool.append(self)
84 self._pool.append(self)
83 else:
85 else:
84 self.close()
86 self.close()
85
87
86 def close(self):
88 def close(self):
87 if util.safehasattr(self.peer, 'cleanup'):
89 if util.safehasattr(self.peer, 'cleanup'):
88 self.peer.cleanup()
90 self.peer.cleanup()
General Comments 0
You need to be logged in to leave comments. Login now