mercurial/branchmap.py
changeset 41565 bf7fb97aecf1
parent 41396 3461814417f3
child 41566 eb7ce452e0fb
equal deleted inserted replaced
41564:a5493a251ad3 41565:bf7fb97aecf1
    28 
    28 
    29 calcsize = struct.calcsize
    29 calcsize = struct.calcsize
    30 pack_into = struct.pack_into
    30 pack_into = struct.pack_into
    31 unpack_from = struct.unpack_from
    31 unpack_from = struct.unpack_from
    32 
    32 
    33 def _filename(repo):
       
    34     """name of a branchcache file for a given repo or repoview"""
       
    35     filename = "branch2"
       
    36     if repo.filtername:
       
    37         filename = '%s-%s' % (filename, repo.filtername)
       
    38     return filename
       
    39 
       
    40 def read(repo):
       
    41     f = None
       
    42     try:
       
    43         f = repo.cachevfs(_filename(repo))
       
    44         lineiter = iter(f)
       
    45         cachekey = next(lineiter).rstrip('\n').split(" ", 2)
       
    46         last, lrev = cachekey[:2]
       
    47         last, lrev = bin(last), int(lrev)
       
    48         filteredhash = None
       
    49         if len(cachekey) > 2:
       
    50             filteredhash = bin(cachekey[2])
       
    51         bcache = branchcache(tipnode=last, tiprev=lrev,
       
    52                               filteredhash=filteredhash)
       
    53         if not bcache.validfor(repo):
       
    54             # invalidate the cache
       
    55             raise ValueError(r'tip differs')
       
    56         cl = repo.changelog
       
    57         for l in lineiter:
       
    58             l = l.rstrip('\n')
       
    59             if not l:
       
    60                 continue
       
    61             node, state, label = l.split(" ", 2)
       
    62             if state not in 'oc':
       
    63                 raise ValueError(r'invalid branch state')
       
    64             label = encoding.tolocal(label.strip())
       
    65             node = bin(node)
       
    66             if not cl.hasnode(node):
       
    67                 raise ValueError(
       
    68                     r'node %s does not exist' % pycompat.sysstr(hex(node)))
       
    69             bcache.setdefault(label, []).append(node)
       
    70             if state == 'c':
       
    71                 bcache._closednodes.add(node)
       
    72 
       
    73     except (IOError, OSError):
       
    74         return None
       
    75 
       
    76     except Exception as inst:
       
    77         if repo.ui.debugflag:
       
    78             msg = 'invalid branchheads cache'
       
    79             if repo.filtername is not None:
       
    80                 msg += ' (%s)' % repo.filtername
       
    81             msg += ': %s\n'
       
    82             repo.ui.debug(msg % pycompat.bytestr(inst))
       
    83         bcache = None
       
    84 
       
    85     finally:
       
    86         if f:
       
    87             f.close()
       
    88 
       
    89     return bcache
       
    90 
    33 
    91 ### Nearest subset relation
    34 ### Nearest subset relation
    92 # Nearest subset of filter X is a filter Y so that:
    35 # Nearest subset of filter X is a filter Y so that:
    93 # * Y is included in X,
    36 # * Y is included in X,
    94 # * X - Y is as small as possible.
    37 # * X - Y is as small as possible.
   105     filtername = repo.filtername
    48     filtername = repo.filtername
   106     bcache = repo._branchcaches.get(filtername)
    49     bcache = repo._branchcaches.get(filtername)
   107 
    50 
   108     revs = []
    51     revs = []
   109     if bcache is None or not bcache.validfor(repo):
    52     if bcache is None or not bcache.validfor(repo):
   110         bcache = read(repo)
    53         bcache = branchcache.fromfile(repo)
   111         if bcache is None:
    54         if bcache is None:
   112             subsetname = subsettable.get(filtername)
    55             subsetname = subsettable.get(filtername)
   113             if subsetname is None:
    56             if subsetname is None:
   114                 bcache = branchcache()
    57                 bcache = branchcache()
   115             else:
    58             else:
   179 
   122 
   180     The open/closed state is represented by a single letter 'o' or 'c'.
   123     The open/closed state is represented by a single letter 'o' or 'c'.
   181     This field can be used to avoid changelog reads when determining if a
   124     This field can be used to avoid changelog reads when determining if a
   182     branch head closes a branch or not.
   125     branch head closes a branch or not.
   183     """
   126     """
       
   127     @classmethod
       
   128     def fromfile(cls, repo):
       
   129         f = None
       
   130         try:
       
   131             f = repo.cachevfs(cls._filename(repo))
       
   132             lineiter = iter(f)
       
   133             cachekey = next(lineiter).rstrip('\n').split(" ", 2)
       
   134             last, lrev = cachekey[:2]
       
   135             last, lrev = bin(last), int(lrev)
       
   136             filteredhash = None
       
   137             if len(cachekey) > 2:
       
   138                 filteredhash = bin(cachekey[2])
       
   139             bcache = cls(tipnode=last, tiprev=lrev, filteredhash=filteredhash)
       
   140             if not bcache.validfor(repo):
       
   141                 # invalidate the cache
       
   142                 raise ValueError(r'tip differs')
       
   143             cl = repo.changelog
       
   144             for line in lineiter:
       
   145                 line = line.rstrip('\n')
       
   146                 if not line:
       
   147                     continue
       
   148                 node, state, label = line.split(" ", 2)
       
   149                 if state not in 'oc':
       
   150                     raise ValueError(r'invalid branch state')
       
   151                 label = encoding.tolocal(label.strip())
       
   152                 node = bin(node)
       
   153                 if not cl.hasnode(node):
       
   154                     raise ValueError(
       
   155                         r'node %s does not exist' % pycompat.sysstr(hex(node)))
       
   156                 bcache.setdefault(label, []).append(node)
       
   157                 if state == 'c':
       
   158                     bcache._closednodes.add(node)
       
   159 
       
   160         except (IOError, OSError):
       
   161             return None
       
   162 
       
   163         except Exception as inst:
       
   164             if repo.ui.debugflag:
       
   165                 msg = 'invalid branchheads cache'
       
   166                 if repo.filtername is not None:
       
   167                     msg += ' (%s)' % repo.filtername
       
   168                 msg += ': %s\n'
       
   169                 repo.ui.debug(msg % pycompat.bytestr(inst))
       
   170             bcache = None
       
   171 
       
   172         finally:
       
   173             if f:
       
   174                 f.close()
       
   175 
       
   176         return bcache
       
   177 
       
   178     @staticmethod
       
   179     def _filename(repo):
       
   180         """name of a branchcache file for a given repo or repoview"""
       
   181         filename = "branch2"
       
   182         if repo.filtername:
       
   183             filename = '%s-%s' % (filename, repo.filtername)
       
   184         return filename
   184 
   185 
   185     def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
   186     def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
   186                  filteredhash=None, closednodes=None):
   187                  filteredhash=None, closednodes=None):
   187         super(branchcache, self).__init__(entries)
   188         super(branchcache, self).__init__(entries)
   188         self.tipnode = tipnode
   189         self.tipnode = tipnode
   244         return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
   245         return branchcache(self, self.tipnode, self.tiprev, self.filteredhash,
   245                            self._closednodes)
   246                            self._closednodes)
   246 
   247 
   247     def write(self, repo):
   248     def write(self, repo):
   248         try:
   249         try:
   249             f = repo.cachevfs(_filename(repo), "w", atomictemp=True)
   250             f = repo.cachevfs(self._filename(repo), "w", atomictemp=True)
   250             cachekey = [hex(self.tipnode), '%d' % self.tiprev]
   251             cachekey = [hex(self.tipnode), '%d' % self.tiprev]
   251             if self.filteredhash is not None:
   252             if self.filteredhash is not None:
   252                 cachekey.append(hex(self.filteredhash))
   253                 cachekey.append(hex(self.filteredhash))
   253             f.write(" ".join(cachekey) + '\n')
   254             f.write(" ".join(cachekey) + '\n')
   254             nodecount = 0
   255             nodecount = 0