connectionpool: add configurable reuse lifetime for connections

Summary:
Re-using long-running connections can cause problems, as the `hg serve` process
on the server may be using large amounts of resources.  Add a new configuration
option `connectionpool.lifetime`.  Connections that are older than that time
will be closed and not re-used.

Reviewed By: DurhamG

Differential Revision: D8204415

fbshipit-source-id: ac937778e3dc79e77e367017db2141066bd17263
This commit is contained in:
Mark Thomas 2018-06-05 04:23:55 -07:00 committed by Facebook Github Bot
parent c7b0012cfe
commit abdd30febd
4 changed files with 43 additions and 5 deletions

View File

@ -157,6 +157,7 @@ coreconfigitem(
)
coreconfigitem("commands", "update.requiredest", default=False)
coreconfigitem("committemplate", ".*", default=None, generic=True)
coreconfigitem("connectionpool", "lifetime", default=None)
coreconfigitem("convert", "cvsps.cache", default=True)
coreconfigitem("convert", "cvsps.fuzz", default=60)
coreconfigitem("convert", "cvsps.logencoding", default=None)

View File

@ -7,6 +7,8 @@
from __future__ import absolute_import
import time
from . import extensions, sshpeer, util
@ -46,6 +48,13 @@ class connectionpool(object):
proc = peer._subprocess
if proc.poll() is not None:
conn = None
# If the connection has expired, close it
if conn is not None and conn.expired():
self.repo._ui.debug(
"not reusing expired connection to %s\n" % conn.path
)
conn.close()
conn = None
except IndexError:
pass
@ -63,7 +72,7 @@ class connectionpool(object):
if util.safehasattr(peer, "cleanup"):
extensions.wrapfunction(peer, "cleanup", _cleanup)
conn = connection(pathpool, peer)
conn = connection(self._repo.ui, pathpool, peer, path)
return conn
@ -90,9 +99,15 @@ class standaloneconnection(object):
class connection(object):
def __init__(self, pool, peer):
def __init__(self, ui, pool, peer, path):
self._ui = ui
self._pool = pool
self.peer = peer
self.path = path
self.expiry = None
lifetime = ui.configint("connectionpool", "lifetime")
if lifetime is not None:
self.expiry = time.time() + lifetime
def __enter__(self):
return self
@ -101,10 +116,16 @@ class connection(object):
# Only add the connection back to the pool if there was no exception,
# since an exception could mean the connection is not in a reusable
# state.
if type is None:
self._pool.append(self)
else:
if type is not None:
self.close()
elif self.expired():
self._ui.debug("closing expired connection to %s\n" % self.path)
self.close()
else:
self._pool.append(self)
def expired(self):
return self.expiry is not None and time.time() > self.expiry
def close(self):
if util.safehasattr(self.peer, "cleanup"):

View File

@ -593,6 +593,13 @@ below can be referred as ``{listupfiles}``::
"HG: removed {file}\n" }{if(files, "",
"HG: no files changed\n")}
``connectionpool``
------------------
``lifetime``
Number of seconds for which connections in the connection pool can be kept
and reused. Connections that are older than this won't be reused.
``decode/encode``
-----------------

View File

@ -262,3 +262,12 @@
3 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over * (glob)
abort: z2@109c3a557a73: not found in manifest! (?)
# Test connection pool lifetime
$ clearcache
$ hg prefetch -r 0::1 --debug --config connectionpool.lifetime=0 | grep 'closing expired connection'
4 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over * (glob)
closing expired connection to ssh://user@dummy/master
$ clearcache
$ hg prefetch -r 0::1 --debug --config connectionpool.lifetime=300 | grep 'closing expired connection'
4 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over * (glob)
[1]