comparison mercurial/commandserver.py @ 33503:27d23fe32887

commandserver: use selectors2 Previously, commandserver was using select.select. That could have issue if _sock.fileno() >= FD_SETSIZE (usually 1024), which raises: ValueError: filedescriptor out of range in select() We got that in production today, although it's the code opening that many files to blame, it seems better for commandserver to work in this case. There are multiple way to "solve" it, like preserving a fd with a small number and swap it with sock using dup2(). But upgrading to a modern selector supported by the system seems to be the most correct way.
author Jun Wu <quark@fb.com>
date Fri, 14 Jul 2017 20:26:21 -0700
parents 0407a51b9d8c
children 8a1a7935c047
comparison
equal deleted inserted replaced
33502:5d0c0c8d2929 33503:27d23fe32887
20 from .i18n import _ 20 from .i18n import _
21 from . import ( 21 from . import (
22 encoding, 22 encoding,
23 error, 23 error,
24 pycompat, 24 pycompat,
25 selectors2,
25 util, 26 util,
26 ) 27 )
27 28
28 logfile = None 29 logfile = None
29 30
474 self._cleanup() 475 self._cleanup()
475 476
476 def _mainloop(self): 477 def _mainloop(self):
477 exiting = False 478 exiting = False
478 h = self._servicehandler 479 h = self._servicehandler
480 selector = selectors2.DefaultSelector()
481 selector.register(self._sock, selectors2.EVENT_READ)
479 while True: 482 while True:
480 if not exiting and h.shouldexit(): 483 if not exiting and h.shouldexit():
481 # clients can no longer connect() to the domain socket, so 484 # clients can no longer connect() to the domain socket, so
482 # we stop queuing new requests. 485 # we stop queuing new requests.
483 # for requests that are queued (connect()-ed, but haven't been 486 # for requests that are queued (connect()-ed, but haven't been
484 # accept()-ed), handle them before exit. otherwise, clients 487 # accept()-ed), handle them before exit. otherwise, clients
485 # waiting for recv() will receive ECONNRESET. 488 # waiting for recv() will receive ECONNRESET.
486 self._unlinksocket() 489 self._unlinksocket()
487 exiting = True 490 exiting = True
488 try: 491 try:
489 ready = select.select([self._sock], [], [], h.pollinterval)[0] 492 ready = selector.select(timeout=h.pollinterval)
490 if not ready: 493 if not ready:
491 # only exit if we completed all queued requests 494 # only exit if we completed all queued requests
492 if exiting: 495 if exiting:
493 break 496 break
494 continue 497 continue