1
1
=======================
3
3
=======================
8
The format of trac "revs" is in flux, but is closer to bzr revision
9
ids than to bzr revision numbers. This is needed to make multiple
10
branch support work and may allow showing more useful things (think
11
"subdiffs" of merges). There are a couple of annoyances:
13
- trac revs are not quite strings: the "@" character is special and
14
they need to be usable as parameter in a http GET request. So we
15
need to escape a bunch of stuff. The intention originally was to use
16
normalize_rev but I think that will not really work very well since
17
trac seems to *sometimes* hand you normalized revs and *sometimes*
18
raw revs (meaning "normalizing" something twice has to be safe if we
19
use it for escaping). So instead we keep our "actual" revids
20
completely contained, only giving trac escaped revids, unescaping
21
before handing them to bzrlib.
23
- trac wants to have a total ordering on revs. If we were using revnos
24
this would of course be trivial but with revids it is not,
25
especially if we start mixing branches. Will have to sort that out
26
at some point. Currently we determine which one is an ancestor of
27
the other, falling back to a time-based comparison if this fails.
8
The format of trac "revs" is in flux.
9
Currently the following guidelines are used:
11
- A revision as Trac sees is always consists of a branch name followed
12
by a comma and some string identifying the revision. The branch name
13
is important, as Trac thinks of the repository as a single tree, so
14
a revision id by itself wouldn't give us an absolute path in that
15
tree if there were multiple branches containing that revision.
17
- If there is only a single branch at the root of the directory
18
configured as the bzr repository in Trac, then no branch name will
19
be included in revision strings. In this case, simple revision
20
numbers will work as Trac links, too. Maybe a future version of
21
trac-bzr will allow users to configure a "default branch" to obtain
22
simple revision names even when dealing with multiple branches.
24
- When generating revision strings, we prefer (dotted) revision
25
numbers over bzr revision identifiers. Only when the revision in
26
question hasn't been merged into that branch yet we emit a revision
27
id instead. Usually people should never encounter such revisions
28
trough Trac links, and we might simply reject them in the future,
29
but for now they're handled in this fashion.
31
- Wenn accepting revision strings, we accept both dotted revision
32
numbers and revision identifiers.
34
- Some characters are special to Trac, and shouldn't be part of a
35
revision as Trac sees it. These include ``/`` and ``@``. For this
36
reason, slashes in the branch name are replaced by commas, and
37
revision identifiers will always be url-quoted. Branch names
38
containing commas or percent signs will be url-quoted as well, which
39
will ensure backwards compatibility with versions that used ot
40
url-quote slashes and colons, so we have to url-unquote branch
43
- It seems that Trac takes care of quoting special characters, percent
44
signs in particular, when generating links, and will unquote them
45
before handing them to Trac. If you find an indication to the
46
contrary, it might be a bug in Trac.
51
- trac wants to have a total ordering on revs. If one of the two
52
revisions to be compared is an ancestor of the other, then we can
53
compare them using the revision graph. bzrlib provides
54
``Graph.is_ancestor`` for a one-way comparison. It internally uses
55
``Graph.heads``, which we can use to get both ways at once. If the
56
two branches are uncomparable using the partial ordering given by
57
the ancestry graph, we compare them using timestamps instead. In the
58
presence of a clock skew, this can lead to inconsistent results: if
59
*a* is ancestor of *b* but *a* has a later timestamp than *b*, and
60
if *c* is uncomparable to either, then by ancestry copparison
61
*a* < *b* but by time comparison *b* < *c* < *a*.
29
63
- trac occasionally compares path values, which means we have to be
30
64
careful about "normalizing" those. Currently the format is the one
68
102
determine the right "most recent" revision. Because it is pretty
69
103
common to iterate over the children afterwards and we need to
70
104
determine their most recent revision anyway we cache those values
71
(BzrDirNode.revcache). Speeds up the source browser in a directory
105
(``BzrDirNode.revcache``). Speeds up the source browser in a directory
72
106
with a couple of subdirs.
74
BzrDirNode.get_history is a bit slow and pretty memory-hungry. Again
108
``BzrDirNode.get_history`` is a bit slow and pretty memory-hungry. Again
75
109
the need to manually pick up changes to children is the root cause.
76
110
It has to construct full inventories and/or deltas between revisions
77
111
to pick up changes to children, while for the other node types we just
78
112
have to open the "versionedfile" for that particular file.
80
Probably the most questionable optimization is calling lock_read in
81
BzrRepository.__init__. This provides a *very* noticable speed boost
82
by keeping the branch locked for the entire web request (try timing a
114
Probably the most questionable optimization is keeping branches locked
115
for the whole request. This provides a *very* noticable speed boost by
116
keeping the branch locked for the entire web request (try timing a
83
117
"log" of the root dir, which pulls in a hundred BzrChangesets). And at
84
118
a glance it looks like trac was designed with this thing in mind: it
85
119
has a close method for "closing the connection". Unfortunately it does
86
120
not actually call this method... We have a __del__ method to try to
87
121
improve the chance the branch is unlocked, and bzr has one too, and
88
122
this seems to be working so far. It is probably not really reliable
123
though. And care has to be taken to avoid uncollectable cycles with
124
objects containing __del__ methods, as this would cause serious memory