##// END OF EJS Templates
dirstate: use visitchildrenset in traverse...
dirstate: use visitchildrenset in traverse This speeds up `hg status` a fair amount when there is a very large directory and narrow is in use. Timing numbers according to command: hyperfine --warmup 1 'hg status' HGRCPATH points to a file with the following contents: [extensions] narrow = mozilla-unified (called m-u below) was at revision #468856. regular hash: eb39298e432d treemanifests hash: 0553b7f29eaf large-dir-repo (called l-d-r below) was generated with the following script: #!/bin/bash hg init large-dir-repo mkdir -p large-dir-repo/third_party/rust/log touch large-dir-repo/third_party/rust/log/foo.txt for i in $(seq 1 30000); do d=$(mktemp -d large-dir-repo/third_party/XXXXXXXXX) touch $d/file.txt done hg -R large-dir-repo ci -Am 'rev0' --user test --date '0 0' for repos that use narrow, the narrowspec was this: [includes] rootfilesin:third_party/rust/log [excludes] This narrowspec was chosen due to the size of the third_party/rust directory; this directory was *not* modified in revision #468856 in mozilla-unified. Importantly, when using narrow, these repos had everything checked out (in the case of large-dir-repo, that means all 30,001 directories), *before* adding the narrowspec. This is to simulate the behavior when using a virtual filesystem that shows everything for the user even if they haven't added it to the narrowspec yet. This is not a supported configuration, and `hg update` will not really do the "correct" thing, but non-mutating commands should behave correctly. There are two repos below that do not follow the setup above, 'citc1' and 'citc2', which are using a virtual filesystem and can not be reproduced upstream; these numbers are here mostly to indicate that these performance improvements are not hypothetical, and show the benefits we're hoping to achieve on our real workloads. 'citc1' is closest to large-dir-repo with one of our pathological cases, 'citc2' is an arbitrary repo and closer to "average". I'm not claiming anything less than a 5% speed win as improvements due to this change; these are probably eiter measurement artifacts or constant time improvements. The numbers that aren't changing are shown primarily to prove that this doesn't make anything worse in any case I plan on testing during this series. 'before' is hg from commit c83ad576. 'N' indicates narrow in use, 'T' indicates treemanifest in use. hg status: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 2.284 s +- 0.022 s | 2.274 s +- 0.021 s | 99.6% m-u | | x | 2.289 s +- 0.008 s | 2.284 s +- 0.028 s | 99.8% m-u | x | | 430.8 ms +- 3.1 ms | 424.5 ms +- 3.2 ms | 98.5% m-u | x | x | 429.8 ms +- 2.5 ms | 425.8 ms +- 3.7 ms | 99.1% l-d-r | | | 681.3 ms +- 5.5 ms | 689.6 ms +- 8.0 ms | 101.2% l-d-r | | x | 666.8 ms +- 21.8 ms | 672.5 ms +- 14.9 ms | 100.9% l-d-r | x | | 282.6 ms +- 1.8 ms | 203.0 ms +- 1.2 ms | 71.8% <-- l-d-r | x | x | 275.2 ms +- 3.9 ms | 199.3 ms +- 3.5 ms | 72.4% <-- citc1 | x | x | 1.023 s +- 0.011 s | 398.6 ms +- 9.2 ms | 39.0% <-- citc2 | x | x | 297.9 ms +- 4.4 ms | 289.6 ms +- 4.2 ms | 97.2% hg status --change .: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 478.2 ms +- 2.0 ms | 476.9 ms +- 3.7 ms | 99.7% m-u | | x | 169.5 ms +- 2.7 ms | 169.5 ms +- 2.5 ms | 100.0% m-u | x | | 477.0 ms +- 2.4 ms | 476.1 ms +- 1.4 ms | 99.8% m-u | x | x | 124.7 ms +- 1.9 ms | 124.2 ms +- 3.3 ms | 99.6% l-d-r | | | 97.4 ms +- 1.2 ms | 96.5 ms +- 1.2 ms | 99.1% l-d-r | | x | 4.778 s +- 0.018 s | 4.774 s +- 0.011 s | 99.9% l-d-r | x | | 99.9 ms +- 1.1 ms | 98.8 ms +- 1.3 ms | 98.9% l-d-r | x | x | 848.7 ms +- 7.1 ms | 849.4 ms +- 6.5 ms | 100.1% citc1 | x | x | 4.250 s +- 0.051 s | 4.283 s +- 0.042 s | 100.8% citc2 | x | x | 341.5 ms +- 4.7 ms | 341.5 ms +- 4.1 ms | 100.0% hg update $rev^; hg update $rev: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 4.357 s +- 0.032 s | 4.312 s +- 0.093 s | 99.0% m-u | | x | 3.599 s +- 0.061 s | 3.592 s +- 0.071 s | 99.8% m-u | x | | 1.815 s +- 0.012 s | 1.816 s +- 0.013 s | 100.1% m-u | x | x | 1.110 s +- 0.009 s | 1.106 s +- 0.005 s | 99.6% l-d-r | | | 527.1 ms +- 7.8 ms | 523.3 ms +- 6.5 ms | 99.3% l-d-r | | x | 8.835 s +- 0.067 s | 8.825 s +- 0.064 s | 99.9% l-d-r | x | | 313.0 ms +- 2.2 ms | 312.1 ms +- 1.2 ms | 99.7% l-d-r | x | x | 1.780 s +- 0.011 s | 1.799 s +- 0.013 s | 101.1% citc1 | x | x | 6.825 s +- 0.262 s | 6.707 s +- 0.353 s | 98.3% citc2 | x | x | 776.4 ms +- 4.5 ms | 781.3 ms +- 6.3 ms | 100.6% hg diff: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+------------------------+-----------------------+------------ m-u | | | 1.519 s +- 0.015 s | 1.525 s +- 0.017 s | 100.4% m-u | | x | 1.512 s +- 0.010 s | 1.517 s +- 0.027 s | 100.3% m-u | x | | 420.0 ms +- 3.2 ms | 417.1 ms +- 1.9 ms | 99.3% m-u | x | x | 415.0 ms +- 3.8 ms | 415.7 ms +- 2.7 ms | 100.2% l-d-r | | | 220.8 ms +- 4.0 ms | 220.8 ms +- 3.7 ms | 100.0% l-d-r | | x | 216.6 ms +- 7.5 ms | 211.4 ms +- 2.1 ms | 97.6% l-d-r | x | | 111.9 ms +- 1.8 ms | 112.0 ms +- 1.5 ms | 100.1% l-d-r | x | x | 111.4 ms +- 1.4 ms | 110.2 ms +- 1.0 ms | 98.9% citc1 | x | x | 268.7 ms +- 2.3 ms | 269.6 ms +- 2.8 ms | 100.3% citc2 | x | x | 273.5 ms +- 5.5 ms | 273.9 ms +- 3.7 ms | 100.1% hg diff -c .: repo | N | T | before (mean +- stdev) | after (mean +- stdev) | % of before ------+---+---+--------------------------+-----------------------+---------- m-u | | | 497.1 ms +- 1.4 ms | 500.1 ms +- 2.4 ms | 100.6% m-u | | x | 195.3 ms +- 13.2 ms | 191.6 ms +- 3.0 ms | 98.1% m-u | x | | 476.8 ms +- 1.9 ms | 476.7 ms +- 2.3 ms | 100.0% m-u | x | x | 122.8 ms +- 2.1 ms | 122.9 ms +- 2.0 ms | 100.1% l-d-r | | | 99.3 ms +- 2.3 ms | 98.8 ms +- 1.7 ms | 99.5% l-d-r | | x | 4.875 s +- 0.041 s | 4.847 s +- 0.038 s | 99.4% l-d-r | x | | 98.5 ms +- 1.2 ms | 98.9 ms +- 1.3 ms | 100.4% l-d-r | x | x | 864.6 ms +- 7.4 ms | 855.4 ms +- 6.6 ms | 98.9% citc1 | x | x | 4.505 s +- 0.060 s | 4.466 s +- 0.036 s | 99.1% citc2 | x | x | 368.0 ms +- 4.0 ms | 365.5 ms +- 6.3 ms | 99.3% Differential Revision: https://phab.mercurial-scm.org/D4131

File last commit:

r37509:685ad41f default
r38991:a3cabe94 default
Show More
followlines.js
286 lines | 10.6 KiB | application/javascript | JavascriptLexer
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // followlines.js - JavaScript utilities for followlines UI
//
// Copyright 2017 Logilab SA <contact@logilab.fr>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//** Install event listeners for line block selection and followlines action */
document.addEventListener('DOMContentLoaded', function() {
var sourcelines = document.getElementsByClassName('sourcelines')[0];
if (typeof sourcelines === 'undefined') {
return;
}
// URL to complement with "linerange" query parameter
var targetUri = sourcelines.dataset.logurl;
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (typeof targetUri === 'undefined') {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // Tag of children of "sourcelines" element on which to add "line
// selection" style.
var selectableTag = sourcelines.dataset.selectabletag;
if (typeof selectableTag === 'undefined') {
return;
}
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 var isHead = parseInt(sourcelines.dataset.ishead || "0");
Denis Laxalde
hgweb: position the "followlines" box close to latest cursor position
r31849 //* position "element" on top-right of cursor */
function positionTopRight(element, event) {
var x = (event.clientX + 10) + 'px',
y = (event.clientY - 20) + 'px';
element.style.top = y;
element.style.left = x;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // retrieve all direct *selectable* children of class="sourcelines"
// element
var selectableElements = Array.prototype.filter.call(
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 sourcelines.children,
av6
hgweb: add missing semicolons to followlines.js...
r35027 function(x) { return x.tagName === selectableTag; });
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var btnTitleStart = 'start following lines history from here';
var btnTitleEnd = 'terminate line block selection here';
//** return a <button> element with +/- spans */
function createButton() {
var btn = document.createElement('button');
btn.title = btnTitleStart;
btn.classList.add('btn-followlines');
var plusSpan = document.createElement('span');
plusSpan.classList.add('followlines-plus');
plusSpan.textContent = '+';
btn.appendChild(plusSpan);
var br = document.createElement('br');
btn.appendChild(br);
var minusSpan = document.createElement('span');
minusSpan.classList.add('followlines-minus');
minusSpan.textContent = '−';
btn.appendChild(minusSpan);
return btn;
}
// extend DOM with CSS class for selection highlight and action buttons
av6
hgweb: add missing semicolons to followlines.js...
r35027 var followlinesButtons = [];
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 for (var i = 0; i < selectableElements.length; i++) {
selectableElements[i].classList.add('followlines-select');
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var btn = createButton();
followlinesButtons.push(btn);
// insert the <button> as child of `selectableElements[i]` unless the
// latter has itself a child with a "followlines-btn-parent" class
// (annotate view)
var btnSupportElm = selectableElements[i];
var childSupportElms = btnSupportElm.getElementsByClassName(
'followlines-btn-parent');
if ( childSupportElms.length > 0 ) {
btnSupportElm = childSupportElms[0];
}
av6
hgweb: insert followlines buttons before any children, including text nodes...
r37509 var refNode = btnSupportElm.childNodes[0]; // node to insert <button> before
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 btnSupportElm.insertBefore(btn, refNode);
}
// ** re-initialize followlines buttons */
function resetButtons() {
for (var i = 0; i < followlinesButtons.length; i++) {
var btn = followlinesButtons[i];
btn.title = btnTitleStart;
btn.classList.remove('btn-followlines-end');
btn.classList.remove('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
var lineSelectedCSSClass = 'followlines-selected';
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 //** add CSS class on selectable elements in `from`-`to` line range */
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 function addSelectedCSSClass(from, to) {
for (var i = from; i <= to; i++) {
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 selectableElements[i].classList.add(lineSelectedCSSClass);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
}
//** remove CSS class from previously selected lines */
function removeSelectedCSSClass() {
var elements = sourcelines.getElementsByClassName(
lineSelectedCSSClass);
while (elements.length) {
elements[0].classList.remove(lineSelectedCSSClass);
}
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // ** return the element of type "selectableTag" parent of `element` */
function selectableParent(element) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var parent = element.parentElement;
if (parent === null) {
return null;
}
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (element.tagName === selectableTag && parent.isSameNode(sourcelines)) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return element;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 return selectableParent(parent);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // ** update buttons title and style upon first click */
function updateButtons(selectable) {
for (var i = 0; i < followlinesButtons.length; i++) {
var btn = followlinesButtons[i];
btn.title = btnTitleEnd;
btn.classList.add('btn-followlines-end');
}
// on clicked button, change title to "cancel"
var clicked = selectable.getElementsByClassName('btn-followlines')[0];
clicked.title = 'cancel';
clicked.classList.remove('btn-followlines-end');
}
//** add `listener` on "click" event for all `followlinesButtons` */
function buttonsAddEventListener(listener) {
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].addEventListener('click', listener);
}
}
//** remove `listener` on "click" event for all `followlinesButtons` */
function buttonsRemoveEventListener(listener) {
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].removeEventListener('click', listener);
}
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 //** event handler for "click" on the first line of a block */
function lineSelectStart(e) {
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var startElement = selectableParent(e.target.parentElement);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 if (startElement === null) {
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // not a "selectable" element (maybe <a>): abort, keeping event
// listener registered for other click with a "selectable" target
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // update button tooltip text and CSS
updateButtons(startElement);
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var startId = parseInt(startElement.id.slice(1));
startElement.classList.add(lineSelectedCSSClass); // CSS
// remove this event listener
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsRemoveEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** event handler for "click" on the last line of the block */
function lineSelectEnd(e) {
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var endElement = selectableParent(e.target.parentElement);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 if (endElement === null) {
// not a <span> (maybe <a>): abort, keeping event listener
// registered for other click with <span> target
return;
}
// remove this event listener
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsRemoveEventListener(lineSelectEnd);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // reset button tooltip text
resetButtons();
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // compute line range (startId, endId)
var endId = parseInt(endElement.id.slice(1));
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (endId === startId) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // clicked twice the same line, cancel and reset initial state
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // (CSS, event listener for selection start)
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 removeSelectedCSSClass();
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
var inviteElement = endElement;
if (endId < startId) {
var tmp = endId;
endId = startId;
startId = tmp;
inviteElement = startElement;
}
addSelectedCSSClass(startId - 1, endId -1); // CSS
// append the <div id="followlines"> element to last line of the
// selection block
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 var divAndButton = followlinesBox(targetUri, startId, endId, isHead);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var div = divAndButton[0],
button = divAndButton[1];
inviteElement.appendChild(div);
Denis Laxalde
hgweb: position the "followlines" box close to latest cursor position
r31849 // set position close to cursor (top-right)
positionTopRight(div, e);
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // hide all buttons
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].classList.add('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** event handler for cancelling selection */
function cancel() {
// remove invite box
div.parentNode.removeChild(div);
// restore initial event listeners
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
buttonsRemoveEventListener(cancel);
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].classList.remove('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // remove styles on selected lines
removeSelectedCSSClass();
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 resetButtons();
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
// bind cancel event to click on <button>
button.addEventListener('click', cancel);
// as well as on an click on any source line
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(cancel);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectEnd);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
}
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** return a <div id="followlines"> and inner cancel <button> elements */
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 function followlinesBox(targetUri, fromline, toline, isHead) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // <div id="followlines">
var div = document.createElement('div');
div.id = 'followlines';
// <div class="followlines-cancel">
var buttonDiv = document.createElement('div');
buttonDiv.classList.add('followlines-cancel');
// <button>x</button>
var button = document.createElement('button');
button.textContent = 'x';
buttonDiv.appendChild(button);
div.appendChild(buttonDiv);
// <div class="followlines-link">
var aDiv = document.createElement('div');
aDiv.classList.add('followlines-link');
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aDiv.textContent = 'follow history of lines ' + fromline + ':' + toline + ':';
var linesep = document.createElement('br');
aDiv.appendChild(linesep);
// link to "ascending" followlines
var aAsc = document.createElement('a');
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var url = targetUri + '?patch=&linerange=' + fromline + ':' + toline;
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aAsc.setAttribute('href', url);
Denis Laxalde
hgweb: change text of followlines links to "older / newer"...
r32071 aAsc.textContent = 'older';
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aDiv.appendChild(aAsc);
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070
if (!isHead) {
var sep = document.createTextNode(' / ');
aDiv.appendChild(sep);
// link to "descending" followlines
var aDesc = document.createElement('a');
aDesc.setAttribute('href', url + '&descend=');
Denis Laxalde
hgweb: change text of followlines links to "older / newer"...
r32071 aDesc.textContent = 'newer';
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 aDiv.appendChild(aDesc);
}
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 div.appendChild(aDiv);
return [div, button];
}
}, false);