##// END OF EJS Templates
tags: improve documentation...
Gregory Szorc -
r24445:c71edbaf default
parent child Browse files
Show More
@@ -18,12 +18,61 b' import error'
18 import errno
18 import errno
19 import time
19 import time
20
20
21 # The tags cache stores information about heads and the history of tags.
22 #
23 # The cache file consists of two parts. The first part maps head nodes
24 # to .hgtags filenodes. The second part is a history of tags. The two
25 # parts are separated by an empty line.
26 #
27 # The first part consists of lines of the form:
28 #
29 # <headrev> <headnode> [<hgtagsnode>]
30 #
31 # <headrev> is an integer revision and <headnode> is a 40 character hex
32 # node for that changeset. These redundantly identify a repository
33 # head from the time the cache was written.
34 #
35 # <tagnode> is the filenode of .hgtags on that head. Heads with no .hgtags
36 # file will have no <hgtagsnode> (just 2 values per line).
37 #
38 # The filenode cache is ordered from tip to oldest (which is part of why
39 # <headrev> is there: a quick check of the tip from when the cache was
40 # written against the current tip is all that is needed to check whether
41 # the cache is up to date).
42 #
43 # The purpose of the filenode cache is to avoid the most expensive part
44 # of finding global tags, which is looking up the .hgtags filenode in the
45 # manifest for each head. This can take over a minute on repositories
46 # that have large manifests and many heads.
47 #
48 # The second part of the tags cache consists of lines of the form:
49 #
50 # <node> <tag>
51 #
52 # (This format is identical to that of .hgtags files.)
53 #
54 # <tag> is the tag name and <node> is the 40 character hex changeset
55 # the tag is associated with.
56 #
57 # Tags are written sorted by tag name.
58 #
59 # Tags associated with multiple changesets have an entry for each changeset.
60 # The most recent changeset (in terms of revlog ordering for the head
61 # setting it) for each tag is last.
62
21 def findglobaltags(ui, repo, alltags, tagtypes):
63 def findglobaltags(ui, repo, alltags, tagtypes):
22 '''Find global tags in repo by reading .hgtags from every head that
64 '''Find global tags in a repo.
23 has a distinct version of it, using a cache to avoid excess work.
65
24 Updates the dicts alltags, tagtypes in place: alltags maps tag name
66 "alltags" maps tag name to (node, hist) 2-tuples.
25 to (node, hist) pair (see _readtags() below), and tagtypes maps tag
67
26 name to tag type ("global" in this case).'''
68 "tagtypes" maps tag name to tag type. Global tags always have the
69 "global" tag type.
70
71 The "alltags" and "tagtypes" dicts are updated in place. Empty dicts
72 should be passed in.
73
74 The tags cache is read and updated as a side-effect of calling.
75 '''
27 # This is so we can be lazy and assume alltags contains only global
76 # This is so we can be lazy and assume alltags contains only global
28 # tags when we pass it to _writetagcache().
77 # tags when we pass it to _writetagcache().
29 assert len(alltags) == len(tagtypes) == 0, \
78 assert len(alltags) == len(tagtypes) == 0, \
@@ -38,9 +87,9 b' def findglobaltags(ui, repo, alltags, ta'
38 _updatetags(cachetags, 'global', alltags, tagtypes)
87 _updatetags(cachetags, 'global', alltags, tagtypes)
39 return
88 return
40
89
41 seen = set() # set of fnode
90 seen = set() # set of fnode
42 fctx = None
91 fctx = None
43 for head in reversed(heads): # oldest to newest
92 for head in reversed(heads): # oldest to newest
44 assert head in repo.changelog.nodemap, \
93 assert head in repo.changelog.nodemap, \
45 "tag cache returned bogus head %s" % short(head)
94 "tag cache returned bogus head %s" % short(head)
46
95
@@ -60,7 +109,7 b' def findglobaltags(ui, repo, alltags, ta'
60 _writetagcache(ui, repo, heads, tagfnode, alltags)
109 _writetagcache(ui, repo, heads, tagfnode, alltags)
61
110
62 def readlocaltags(ui, repo, alltags, tagtypes):
111 def readlocaltags(ui, repo, alltags, tagtypes):
63 '''Read local tags in repo. Update alltags and tagtypes.'''
112 '''Read local tags in repo. Update alltags and tagtypes.'''
64 try:
113 try:
65 data = repo.vfs.read("localtags")
114 data = repo.vfs.read("localtags")
66 except IOError, inst:
115 except IOError, inst:
@@ -86,14 +135,18 b' def readlocaltags(ui, repo, alltags, tag'
86
135
87 def _readtaghist(ui, repo, lines, fn, recode=None, calcnodelines=False):
136 def _readtaghist(ui, repo, lines, fn, recode=None, calcnodelines=False):
88 '''Read tag definitions from a file (or any source of lines).
137 '''Read tag definitions from a file (or any source of lines).
138
89 This function returns two sortdicts with similar information:
139 This function returns two sortdicts with similar information:
140
90 - the first dict, bintaghist, contains the tag information as expected by
141 - the first dict, bintaghist, contains the tag information as expected by
91 the _readtags function, i.e. a mapping from tag name to (node, hist):
142 the _readtags function, i.e. a mapping from tag name to (node, hist):
92 - node is the node id from the last line read for that name,
143 - node is the node id from the last line read for that name,
93 - hist is the list of node ids previously associated with it (in file
144 - hist is the list of node ids previously associated with it (in file
94 order). All node ids are binary, not hex.
145 order). All node ids are binary, not hex.
146
95 - the second dict, hextaglines, is a mapping from tag name to a list of
147 - the second dict, hextaglines, is a mapping from tag name to a list of
96 [hexnode, line number] pairs, ordered from the oldest to the newest node.
148 [hexnode, line number] pairs, ordered from the oldest to the newest node.
149
97 When calcnodelines is False the hextaglines dict is not calculated (an
150 When calcnodelines is False the hextaglines dict is not calculated (an
98 empty dict is returned). This is done to improve this function's
151 empty dict is returned). This is done to improve this function's
99 performance in cases where the line numbers are not needed.
152 performance in cases where the line numbers are not needed.
@@ -139,10 +192,13 b' def _readtaghist(ui, repo, lines, fn, re'
139
192
140 def _readtags(ui, repo, lines, fn, recode=None, calcnodelines=False):
193 def _readtags(ui, repo, lines, fn, recode=None, calcnodelines=False):
141 '''Read tag definitions from a file (or any source of lines).
194 '''Read tag definitions from a file (or any source of lines).
142 Return a mapping from tag name to (node, hist): node is the node id
195
143 from the last line read for that name, and hist is the list of node
196 Returns a mapping from tag name to (node, hist).
144 ids previously associated with it (in file order). All node ids are
197
145 binary, not hex.'''
198 "node" is the node id from the last line read for that name. "hist"
199 is the list of node ids previously associated with it (in file order).
200 All node ids are binary, not hex.
201 '''
146 filetags, nodelines = _readtaghist(ui, repo, lines, fn, recode=recode,
202 filetags, nodelines = _readtaghist(ui, repo, lines, fn, recode=recode,
147 calcnodelines=calcnodelines)
203 calcnodelines=calcnodelines)
148 for tag, taghist in filetags.items():
204 for tag, taghist in filetags.items():
@@ -174,23 +230,23 b' def _updatetags(filetags, tagtype, allta'
174 ahist.extend([n for n in bhist if n not in ahist])
230 ahist.extend([n for n in bhist if n not in ahist])
175 alltags[name] = anode, ahist
231 alltags[name] = anode, ahist
176
232
233 def _readtagcache(ui, repo):
234 '''Read the tag cache.
177
235
178 # The tag cache only stores info about heads, not the tag contents
236 Returns a tuple (heads, fnodes, cachetags, shouldwrite).
179 # from each head. I.e. it doesn't try to squeeze out the maximum
237
180 # performance, but is simpler has a better chance of actually
238 If the cache is completely up-to-date, "cachetags" is a dict of the
181 # working correctly. And this gives the biggest performance win: it
239 form returned by _readtags() and "heads" and "fnodes" are None and
182 # avoids looking up .hgtags in the manifest for every head, and it
240 "shouldwrite" is False.
183 # can avoid calling heads() at all if there have been no changes to
184 # the repo.
185
241
186 def _readtagcache(ui, repo):
242 If the cache is not up to date, "cachetags" is None. "heads" is a list
187 '''Read the tag cache and return a tuple (heads, fnodes, cachetags,
243 of all heads currently in the repository, ordered from tip to oldest.
188 shouldwrite). If the cache is completely up-to-date, cachetags is a
244 "fnodes" is a mapping from head to .hgtags filenode. "shouldwrite" is
189 dict of the form returned by _readtags(); otherwise, it is None and
245 True.
190 heads and fnodes are set. In that case, heads is the list of all
246
191 heads currently in the repository (ordered from tip to oldest) and
247 If the cache is not up to date, the caller is responsible for reading tag
192 fnodes is a mapping from head to .hgtags filenode. If those two are
248 info from each returned head. (See findglobaltags().)
193 set, caller is responsible for reading tag info from each head.'''
249 '''
194
250
195 try:
251 try:
196 cachefile = repo.vfs('cache/tags', 'r')
252 cachefile = repo.vfs('cache/tags', 'r')
@@ -199,21 +255,9 b' def _readtagcache(ui, repo):'
199 except IOError:
255 except IOError:
200 cachefile = None
256 cachefile = None
201
257
202 # The cache file consists of lines like
258 cacherevs = [] # list of headrev
203 # <headrev> <headnode> [<tagnode>]
259 cacheheads = [] # list of headnode
204 # where <headrev> and <headnode> redundantly identify a repository
260 cachefnode = {} # map headnode to filenode
205 # head from the time the cache was written, and <tagnode> is the
206 # filenode of .hgtags on that head. Heads with no .hgtags file will
207 # have no <tagnode>. The cache is ordered from tip to oldest (which
208 # is part of why <headrev> is there: a quick visual check is all
209 # that's required to ensure correct order).
210 #
211 # This information is enough to let us avoid the most expensive part
212 # of finding global tags, which is looking up <tagnode> in the
213 # manifest for each head.
214 cacherevs = [] # list of headrev
215 cacheheads = [] # list of headnode
216 cachefnode = {} # map headnode to filenode
217 if cachefile:
261 if cachefile:
218 try:
262 try:
219 for line in cachelines:
263 for line in cachelines:
@@ -301,7 +345,6 b' def _readtagcache(ui, repo):'
301 return (repoheads, cachefnode, None, True)
345 return (repoheads, cachefnode, None, True)
302
346
303 def _writetagcache(ui, repo, heads, tagfnode, cachetags):
347 def _writetagcache(ui, repo, heads, tagfnode, cachetags):
304
305 try:
348 try:
306 cachefile = repo.vfs('cache/tags', 'w', atomictemp=True)
349 cachefile = repo.vfs('cache/tags', 'w', atomictemp=True)
307 except (OSError, IOError):
350 except (OSError, IOError):
General Comments 0
You need to be logged in to leave comments. Login now