hgext/chgserver.py
changeset 29598 a67398726747
parent 29597 581c0c7cb258
child 29841 d5883fd055c6
equal deleted inserted replaced
29597:581c0c7cb258 29598:a67398726747
   540 
   540 
   541     pollinterval = 1  # [sec]
   541     pollinterval = 1  # [sec]
   542 
   542 
   543     def __init__(self, ui):
   543     def __init__(self, ui):
   544         self.ui = ui
   544         self.ui = ui
   545         self.idletimeout = ui.configint('chgserver', 'idletimeout', 3600)
   545         self._idletimeout = ui.configint('chgserver', 'idletimeout', 3600)
   546         self.lastactive = time.time()
   546         self._lastactive = time.time()
   547 
   547 
   548     def bindsocket(self, sock, address):
   548     def bindsocket(self, sock, address):
   549         self._inithashstate(address)
   549         self._inithashstate(address)
   550         self._checkextensions()
   550         self._checkextensions()
   551         self._bind(sock)
   551         self._bind(sock)
   552         self._createsymlink()
   552         self._createsymlink()
   553 
   553 
   554     def _inithashstate(self, address):
   554     def _inithashstate(self, address):
   555         self.baseaddress = address
   555         self._baseaddress = address
   556         if self.ui.configbool('chgserver', 'skiphash', False):
   556         if self.ui.configbool('chgserver', 'skiphash', False):
   557             self.hashstate = None
   557             self._hashstate = None
   558             self.address = address
   558             self._realaddress = address
   559             return
   559             return
   560         self.hashstate = hashstate.fromui(self.ui)
   560         self._hashstate = hashstate.fromui(self.ui)
   561         self.address = _hashaddress(address, self.hashstate.confighash)
   561         self._realaddress = _hashaddress(address, self._hashstate.confighash)
   562 
   562 
   563     def _checkextensions(self):
   563     def _checkextensions(self):
   564         if not self.hashstate:
   564         if not self._hashstate:
   565             return
   565             return
   566         if extensions.notloaded():
   566         if extensions.notloaded():
   567             # one or more extensions failed to load. mtimehash becomes
   567             # one or more extensions failed to load. mtimehash becomes
   568             # meaningless because we do not know the paths of those extensions.
   568             # meaningless because we do not know the paths of those extensions.
   569             # set mtimehash to an illegal hash value to invalidate the server.
   569             # set mtimehash to an illegal hash value to invalidate the server.
   570             self.hashstate.mtimehash = ''
   570             self._hashstate.mtimehash = ''
   571 
   571 
   572     def _bind(self, sock):
   572     def _bind(self, sock):
   573         # use a unique temp address so we can stat the file and do ownership
   573         # use a unique temp address so we can stat the file and do ownership
   574         # check later
   574         # check later
   575         tempaddress = _tempaddress(self.address)
   575         tempaddress = _tempaddress(self._realaddress)
   576         util.bindunixsocket(sock, tempaddress)
   576         util.bindunixsocket(sock, tempaddress)
   577         self._socketstat = os.stat(tempaddress)
   577         self._socketstat = os.stat(tempaddress)
   578         # rename will replace the old socket file if exists atomically. the
   578         # rename will replace the old socket file if exists atomically. the
   579         # old server will detect ownership change and exit.
   579         # old server will detect ownership change and exit.
   580         util.rename(tempaddress, self.address)
   580         util.rename(tempaddress, self._realaddress)
   581 
   581 
   582     def _createsymlink(self):
   582     def _createsymlink(self):
   583         if self.baseaddress == self.address:
   583         if self._baseaddress == self._realaddress:
   584             return
   584             return
   585         tempaddress = _tempaddress(self.baseaddress)
   585         tempaddress = _tempaddress(self._baseaddress)
   586         os.symlink(os.path.basename(self.address), tempaddress)
   586         os.symlink(os.path.basename(self._realaddress), tempaddress)
   587         util.rename(tempaddress, self.baseaddress)
   587         util.rename(tempaddress, self._baseaddress)
   588 
   588 
   589     def issocketowner(self):
   589     def _issocketowner(self):
   590         try:
   590         try:
   591             stat = os.stat(self.address)
   591             stat = os.stat(self._realaddress)
   592             return (stat.st_ino == self._socketstat.st_ino and
   592             return (stat.st_ino == self._socketstat.st_ino and
   593                     stat.st_mtime == self._socketstat.st_mtime)
   593                     stat.st_mtime == self._socketstat.st_mtime)
   594         except OSError:
   594         except OSError:
   595             return False
   595             return False
   596 
   596 
   597     def unlinksocket(self, address):
   597     def unlinksocket(self, address):
   598         if not self.issocketowner():
   598         if not self._issocketowner():
   599             return
   599             return
   600         # it is possible to have a race condition here that we may
   600         # it is possible to have a race condition here that we may
   601         # remove another server's socket file. but that's okay
   601         # remove another server's socket file. but that's okay
   602         # since that server will detect and exit automatically and
   602         # since that server will detect and exit automatically and
   603         # the client will start a new server on demand.
   603         # the client will start a new server on demand.
   604         try:
   604         try:
   605             os.unlink(self.address)
   605             os.unlink(self._realaddress)
   606         except OSError as exc:
   606         except OSError as exc:
   607             if exc.errno != errno.ENOENT:
   607             if exc.errno != errno.ENOENT:
   608                 raise
   608                 raise
   609 
   609 
   610     def printbanner(self, address):
   610     def printbanner(self, address):
   611         # no "listening at" message should be printed to simulate hg behavior
   611         # no "listening at" message should be printed to simulate hg behavior
   612         pass
   612         pass
   613 
   613 
   614     def shouldexit(self):
   614     def shouldexit(self):
   615         if not self.issocketowner():
   615         if not self._issocketowner():
   616             self.ui.debug('%s is not owned, exiting.\n' % self.address)
   616             self.ui.debug('%s is not owned, exiting.\n' % self._realaddress)
   617             return True
   617             return True
   618         if time.time() - self.lastactive > self.idletimeout:
   618         if time.time() - self._lastactive > self._idletimeout:
   619             self.ui.debug('being idle too long. exiting.\n')
   619             self.ui.debug('being idle too long. exiting.\n')
   620             return True
   620             return True
   621         return False
   621         return False
   622 
   622 
   623     def newconnection(self):
   623     def newconnection(self):
   624         self.lastactive = time.time()
   624         self._lastactive = time.time()
   625 
   625 
   626     def createcmdserver(self, repo, conn, fin, fout):
   626     def createcmdserver(self, repo, conn, fin, fout):
   627         return chgcmdserver(self.ui, repo, fin, fout, conn,
   627         return chgcmdserver(self.ui, repo, fin, fout, conn,
   628                             self.hashstate, self.baseaddress)
   628                             self._hashstate, self._baseaddress)
   629 
   629 
   630 def chgunixservice(ui, repo, opts):
   630 def chgunixservice(ui, repo, opts):
   631     if repo:
   631     if repo:
   632         # one chgserver can serve multiple repos. drop repo infomation
   632         # one chgserver can serve multiple repos. drop repo infomation
   633         ui.setconfig('bundle', 'mainreporoot', '', 'repo')
   633         ui.setconfig('bundle', 'mainreporoot', '', 'repo')