comparison mercurial/hgweb/webcommands.py @ 35416:f84b01257e06

hgweb: render next pages on /graph incrementally Previously, when user scrolled down to see the next page on /graph, all hgweb did was re-render everything that would be visible (by simply incrementing revcount). It was not efficient at all, and this patch makes /graph page behave similarly to the regular /log: every new page only consists of new changesets, no duplication, and only jsdata is based on the full set of changesets required to build accurate graph. This is achieved by adding "?graphtop=<node>" to the next page URL template, effectively remembering where the graph started, and using that value to create the new `tree` that covers the whole visible graph. That variable is then used to produce jsdata for redrawing graph client-side. nextentry is used for the same purpose as on /log page (to format the next page URL), but it's not a part of the graph.
author Anton Shestakov <av6@dwimlabs.net>
date Mon, 11 Dec 2017 15:43:56 +0800
parents a48af4993aa0
children 0fe5d99804bb
comparison
equal deleted inserted replaced
35415:a48af4993aa0 35416:f84b01257e06
1205 lessvars = copy.copy(tmpl.defaults['sessionvars']) 1205 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1206 lessvars['revcount'] = max(revcount / 2, 1) 1206 lessvars['revcount'] = max(revcount / 2, 1)
1207 morevars = copy.copy(tmpl.defaults['sessionvars']) 1207 morevars = copy.copy(tmpl.defaults['sessionvars'])
1208 morevars['revcount'] = revcount * 2 1208 morevars['revcount'] = revcount * 2
1209 1209
1210 graphtop = req.form.get('graphtop', [ctx.hex()])[0]
1211 graphvars = copy.copy(tmpl.defaults['sessionvars'])
1212 graphvars['graphtop'] = graphtop
1213
1210 count = len(web.repo) 1214 count = len(web.repo)
1211 pos = rev 1215 pos = rev
1212 1216
1213 uprev = min(max(0, count - 1), rev + revcount) 1217 uprev = min(max(0, count - 1), rev + revcount)
1214 downrev = max(0, rev - revcount) 1218 downrev = max(0, rev - revcount)
1215 changenav = webutil.revnav(web.repo).gen(pos, revcount, count) 1219 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1216 1220
1217 tree = [] 1221 tree = []
1222 nextentry = []
1223 lastrev = 0
1218 if pos != -1: 1224 if pos != -1:
1219 allrevs = web.repo.changelog.revs(pos, 0) 1225 allrevs = web.repo.changelog.revs(pos, 0)
1220 revs = [] 1226 revs = []
1221 for i in allrevs: 1227 for i in allrevs:
1222 revs.append(i) 1228 revs.append(i)
1223 if len(revs) >= revcount: 1229 if len(revs) >= revcount + 1:
1224 break 1230 break
1231
1232 if len(revs) > revcount:
1233 nextentry = [webutil.commonentry(web.repo, web.repo[revs[-1]])]
1234 revs = revs[:-1]
1235
1236 lastrev = revs[-1]
1225 1237
1226 # We have to feed a baseset to dagwalker as it is expecting smartset 1238 # We have to feed a baseset to dagwalker as it is expecting smartset
1227 # object. This does not have a big impact on hgweb performance itself 1239 # object. This does not have a big impact on hgweb performance itself
1228 # since hgweb graphing code is not itself lazy yet. 1240 # since hgweb graphing code is not itself lazy yet.
1229 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs)) 1241 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1230 # As we said one line above... not lazy. 1242 # As we said one line above... not lazy.
1231 tree = list(item for item in graphmod.colored(dag, web.repo) 1243 tree = list(item for item in graphmod.colored(dag, web.repo)
1232 if item[1] == graphmod.CHANGESET) 1244 if item[1] == graphmod.CHANGESET)
1233 1245
1246 def fulltree():
1247 pos = web.repo[graphtop].rev()
1248 tree = []
1249 if pos != -1:
1250 revs = web.repo.changelog.revs(pos, lastrev)
1251 dag = graphmod.dagwalker(web.repo, smartset.baseset(revs))
1252 tree = list(item for item in graphmod.colored(dag, web.repo)
1253 if item[1] == graphmod.CHANGESET)
1254 return tree
1255
1234 def jsdata(): 1256 def jsdata():
1235 return [{'node': pycompat.bytestr(ctx), 1257 return [{'node': pycompat.bytestr(ctx),
1236 'vertex': vtx, 1258 'vertex': vtx,
1237 'edges': edges} 1259 'edges': edges}
1238 for (id, type, ctx, vtx, edges) in tree] 1260 for (id, type, ctx, vtx, edges) in fulltree()]
1239 1261
1240 def nodes(): 1262 def nodes():
1241 for row, (id, type, ctx, vtx, edges) in enumerate(tree): 1263 for row, (id, type, ctx, vtx, edges) in enumerate(tree):
1242 entry = webutil.commonentry(web.repo, ctx) 1264 entry = webutil.commonentry(web.repo, ctx)
1243 edgedata = [{'col': edge[0], 1265 edgedata = [{'col': edge[0],
1258 rows = len(tree) 1280 rows = len(tree)
1259 1281
1260 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount, 1282 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1261 uprev=uprev, 1283 uprev=uprev,
1262 lessvars=lessvars, morevars=morevars, downrev=downrev, 1284 lessvars=lessvars, morevars=morevars, downrev=downrev,
1285 graphvars=graphvars,
1263 rows=rows, 1286 rows=rows,
1264 bg_height=bg_height, 1287 bg_height=bg_height,
1265 changesets=count, 1288 changesets=count,
1289 nextentry=nextentry,
1266 jsdata=lambda **x: jsdata(), 1290 jsdata=lambda **x: jsdata(),
1267 nodes=lambda **x: nodes(), 1291 nodes=lambda **x: nodes(),
1268 node=ctx.hex(), changenav=changenav) 1292 node=ctx.hex(), changenav=changenav)
1269 1293
1270 def _getdoc(e): 1294 def _getdoc(e):