Improve PatchSet.Id.fromRef performance and avoid double-parsing
If5a39210 optimized PatchSet.isRef() to improve the performance of VisibleRefFilter during ref advertisement on large repositories. However, typical large Gerrit repositories are dominated by patch set refs, in which case the relatively slower PatchSet.Id.fromRef() would be called after each call to isRef(). Teach fromRef() to return null for invalid refs, and switch to a character-by-character implementation like the former isRef() implementation, which also avoids any allocations until returning. Add small tests for various ref formats; the new parser is somewhat more strict. On a test project with 50,000 changes (50,004 refs), this reduces average ls-remote time on my MacBook Air by about 30%, 57653us to 40480us (3 warmup runs then average of 10). Leave isRef(), now implemented as "fromRef() != null". This may be marginally less efficient than before, since it involves allocating a PatchSet.Id. This makes the code more maintainable; when writing tests, I found several inconsistencies between the old isRef()/fromRef() implementations. Rather than fix these, I stuck with one implementation. In any case, remaining isRef() callers are not called on every ref in the repo in a tight loop, so the performance impact should be minimal. Change-Id: I9dfb074a7c2312512960fd070aef323c33f80dbd
This commit is contained in:
committed by
Yacob Yonas
parent
2148bf294d
commit
50678c33f2
@@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2014 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.reviewdb.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class PatchSetTest {
|
||||
@Test
|
||||
public void parseRefNames() {
|
||||
assertRef(1, 1, "refs/changes/01/1/1");
|
||||
assertRef(1234, 56, "refs/changes/34/1234/56");
|
||||
|
||||
// Not even close.
|
||||
assertNotRef(null);
|
||||
assertNotRef("");
|
||||
assertNotRef("01/1/1");
|
||||
assertNotRef("HEAD");
|
||||
assertNotRef("refs/tags/v1");
|
||||
|
||||
// Invalid characters.
|
||||
assertNotRef("refs/changes/0x/1/1");
|
||||
assertNotRef("refs/changes/01/x/1");
|
||||
assertNotRef("refs/changes/01/1/x");
|
||||
|
||||
// Truncations.
|
||||
assertNotRef("refs/changes/");
|
||||
assertNotRef("refs/changes/1");
|
||||
assertNotRef("refs/changes/01");
|
||||
assertNotRef("refs/changes/01/");
|
||||
assertNotRef("refs/changes/01/1/");
|
||||
assertNotRef("refs/changes/01/1/1/");
|
||||
assertNotRef("refs/changes/01//1/1");
|
||||
|
||||
// Leading zeroes.
|
||||
assertNotRef("refs/changes/01/01/1");
|
||||
assertNotRef("refs/changes/01/1/01");
|
||||
|
||||
// Mismatched last 2 digits.
|
||||
assertNotRef("refs/changes/35/1234/56");
|
||||
}
|
||||
|
||||
private static void assertRef(int changeId, int psId, String refName) {
|
||||
assertTrue(PatchSet.isRef(refName));
|
||||
assertEquals(new PatchSet.Id(new Change.Id(changeId), psId),
|
||||
PatchSet.Id.fromRef(refName));
|
||||
}
|
||||
|
||||
private static void assertNotRef(String refName) {
|
||||
assertFalse(PatchSet.isRef(refName));
|
||||
assertNull(PatchSet.Id.fromRef(refName));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user