Optimize RefDirectory.isNameConflicting()
Avoid having to scan over ALL loose refs to determine if the name is nested within or is a container of an existing reference. This can get really expensive if there are too many loose refs. Instead use exactRef and getRefsByPrefix which scan based on a prefix. With a simple shell script(like below) using jgit client to create 1k refs in a new repository on NFS, this change brings down the time from 12mins to 7mins. for ref in $(seq 1 1000); do jgit branch "$ref" done Here are few recorded elapsed times to create a new branch on NFS based repositories with varying loose refs count. As we see here, this change improves the name conflicting check from O(n^2) to O(1). loose_refs_count with_change without_change 50 44 ms 164 ms 300 45 ms 1193 ms 1k 38 ms 2610 ms 2k 44 ms 6003 ms 9k 46 ms 27860 ms 20k 45 ms 48591 ms 50k 51 ms 135471 ms 110k 43 ms 294252 ms 160k 52 ms 430976 ms Change-Id: Ie994fc184b8f82811bfb37b111eb9733dbe3e6e0 Signed-off-by: Kaushik Lingarkar <quic_kaushikl@quicinc.com>
This commit is contained in:
parent
5e0cfce5ad
commit
303dd019d1
|
@ -276,47 +276,18 @@ public void refresh() {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public boolean isNameConflicting(String name) throws IOException {
|
public boolean isNameConflicting(String name) throws IOException {
|
||||||
RefList<Ref> packed = getPackedRefs();
|
|
||||||
RefList<LooseRef> loose = getLooseRefs();
|
|
||||||
|
|
||||||
// Cannot be nested within an existing reference.
|
// Cannot be nested within an existing reference.
|
||||||
int lastSlash = name.lastIndexOf('/');
|
int lastSlash = name.lastIndexOf('/');
|
||||||
while (0 < lastSlash) {
|
while (0 < lastSlash) {
|
||||||
String needle = name.substring(0, lastSlash);
|
String needle = name.substring(0, lastSlash);
|
||||||
if (loose.contains(needle) || packed.contains(needle))
|
if (exactRef(needle) != null) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
lastSlash = name.lastIndexOf('/', lastSlash - 1);
|
lastSlash = name.lastIndexOf('/', lastSlash - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot be the container of an existing reference.
|
// Cannot be the container of an existing reference.
|
||||||
String prefix = name + '/';
|
return !getRefsByPrefix(name + '/').isEmpty();
|
||||||
int idx;
|
|
||||||
|
|
||||||
idx = -(packed.find(prefix) + 1);
|
|
||||||
if (idx < packed.size() && packed.get(idx).getName().startsWith(prefix))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
idx = -(loose.find(prefix) + 1);
|
|
||||||
if (idx < loose.size() && loose.get(idx).getName().startsWith(prefix))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RefList<LooseRef> getLooseRefs() {
|
|
||||||
final RefList<LooseRef> oldLoose = looseRefs.get();
|
|
||||||
|
|
||||||
LooseScanner scan = new LooseScanner(oldLoose);
|
|
||||||
scan.scan(ALL);
|
|
||||||
|
|
||||||
RefList<LooseRef> loose;
|
|
||||||
if (scan.newLoose != null) {
|
|
||||||
loose = scan.newLoose.toRefList();
|
|
||||||
if (looseRefs.compareAndSet(oldLoose, loose))
|
|
||||||
modCnt.incrementAndGet();
|
|
||||||
} else
|
|
||||||
loose = oldLoose;
|
|
||||||
return loose;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
|
Loading…
Reference in New Issue