it gets worse
[ikiwiki] / doc / bugs / transitive_dependencies.mdwn
1 If a sidebar contains a map, or inline (etc), one would expect a
2 add/remove of any of the mapped/inlined pages to cause a full wiki
3 rebuild. But this does not happen.
4
5 If page A inlines page B, which inlines page C, a change to C will cause B
6 to be updated, but A will not "notice" that this means A needs to be
7 updated.
8
9 One way to look at this bug is that it's a bug in where dependencies are
10 recorded when preprocessing the rendered or sidebar page. The current code
11 does:
12
13         add_depends($params{page}, $somepage);
14
15 Where `$params{page}` is page B. If this is changed to `$params{destpage}`,
16 then the dependency is added to page A, and updates to C cause it to
17 change. This does result in the page A's getting lots more dependency info
18 recorded than before (essentially a copy of all the B's dependency info).
19
20 It's also a fragile, since all plugins that handle dependencies have to be
21 changed, and do this going forward. And it seems non-obvious that this should
22 be done. Or really, whether to use `page` or `destpage` there. Currently,
23 making the "wrong" choice and using `destpage` instead of `page` (which nearly
24 everything uses) will just result in semi-redundant dependency info being
25 recorded. If we make destpage mandatory to fix this, goofing up will lead to
26 this bug coming back. Ugh.
27
28 ----
29
30 ## rebuild = change approach
31
32 [[!template id=gitbranch branch=origin/transitive-dependencies author="[[joey]]"]]
33
34 Another approach to fix it is to say that anything that causes a
35 rebuild of B is treated as a change of B. Then when C is changed, B is
36 rebuilt due to dependencies, and in turn this means A is rebuilt because B
37 "changed". 
38
39 This is essentially what is done with wikilinks now, and why, if a sidebar
40 links to page C, add/remove of C causes all pages to be rebuilt, as seen 
41 here:
42
43         removing old page meep
44         building sidebar.mdwn, which links to meep
45         building TourBusStop.mdwn, which depends on sidebar
46         building contact.mdwn, which depends on sidebar
47         ...
48
49 Downsides here:
50
51 * Means a minimum of 2x as much time spent resolving dependencies,
52   at least in my simple implementation, which re-runs the dependency
53   resolution loop until no new pages are rebuilt.
54   (I added an optimisation that gets it down to 1.5X as much work on
55   average, still 2x as much worst case. I suppose building a directed
56   graph and traversing it would be theoretically more efficient.)
57 * Causes extra work for some transitive dependencies that we don't
58   actually care about. This is amelorated, but not solved by 
59   the current work on [[todo/dependency_types]].
60   For example, changing index causes
61   plugins/brokenlinks to update in the first pass; if there's a second
62   pass, plugins/map is no longer updated (contentless dependencies FTW),
63   but plugins is, because it depends on plugins/brokenlinks.
64   (Of course, this is just a special case of the issue that a real
65   modification to plugins/brokenlinks causes an unnecessary update of
66   plugins, and could be solved by adding more dependency types.)
67
68 [[done]] --[[Joey]] 
69
70 > Some questions/comments...  I've thought about this a lot for [[todo/tracking_bugs_with_dependencies]].
71
72 >  * When you say that anything that causes a rebuild of B is treated as a change of B, are you: i) Treating
73 > any rebuild as a change, or ii) Treating any rebuild that gives a new result as a change?  Option ii) would
74 > lead to fewer rebuilds.  Implementation is easy: when you're about to rebuild a page, load the old rendered html in.  Do the rebuild.  Compare
75 > the new and old html.  If there is a difference, then mark that page as having changed.  If there is no difference
76 > then you don't need to mark that pages as changed, even though it has been rebuilt.  (This would ignore pages in meta-data that don't
77 > cause changes in html, but I don't think that is a huge issue.)
78
79 >> That is a good idea. I will have to look at it to see if the overhead of
80 >> reading back in the html of every page before building actually is a
81 >> win though. So far, I've focused on avoiding unnecessary rebuilds, and
82 >> there is still some room for more dependency types doing so.
83 >> (Particularly for metadata dependencies..) --[[Joey]] 
84
85 >  * The second comment I have relates to cycles in transitive dependencies.  At the moment I don't think this is
86 > possible, but with some additions it may well become so.  This could be problematic as it could lead to a)
87 > updates that never complete, or b) it being theoretically unclear what the final result should be (i.e. you
88 > can construct logical paradoxes in the system).  I think the point above about marking things as changed only when
89 > the output actually changes fixes any cases that are well defined.  For logical paradoxes and infinite loops (e.g.
90 > two pages that include each other), you might want to put a limit on the number of times you'll rebuild a page in any
91 > given run of ikiwiki.  Say, only allow a page to rebuild twice on any run, regardless of whether a page it depends on changes.
92 > This is not a perfect solution, but would be a good approximation. -- [[Will]]
93
94 >> Ikiwiki only builds any given output file once per run, already. --[[Joey]]