Merge changes from topic 'update-index-ref-decorator'
* changes: RefCursor: Remove unnecessary getUpdateIndex method RefDatabase/Ref: Add versioning to reference database
This commit is contained in:
commit
f5bdb9745f
|
@ -61,6 +61,7 @@
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -134,6 +135,33 @@ public void testCreate() throws IOException {
|
|||
assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD)));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testVersioningNotImplemented_exactRef() throws IOException {
|
||||
assertFalse(refdir.hasVersioning());
|
||||
|
||||
Ref ref = refdir.exactRef(HEAD);
|
||||
assertNotNull(ref);
|
||||
ref.getUpdateIndex(); // Not implemented on FS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersioningNotImplemented_getRefs() throws Exception {
|
||||
assertFalse(refdir.hasVersioning());
|
||||
|
||||
RevCommit C = repo.commit().parent(B).create();
|
||||
repo.update("master", C);
|
||||
List<Ref> refs = refdir.getRefs();
|
||||
|
||||
for (Ref ref : refs) {
|
||||
try {
|
||||
ref.getUpdateIndex();
|
||||
fail("FS doesn't implement ref versioning");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRefs_EmptyDatabase() throws IOException {
|
||||
Map<String, Ref> all;
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
package org.eclipse.jgit.internal.storage.reftable;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.HEAD;
|
||||
import static org.eclipse.jgit.lib.Constants.MASTER;
|
||||
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
|
||||
import static org.eclipse.jgit.lib.Constants.R_HEADS;
|
||||
import static org.eclipse.jgit.lib.Ref.Storage.NEW;
|
||||
|
@ -68,6 +69,7 @@
|
|||
import org.eclipse.jgit.lib.ObjectIdRef;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.RefComparator;
|
||||
import org.eclipse.jgit.lib.SymbolicRef;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MergedReftableTest {
|
||||
|
@ -128,6 +130,7 @@ public void oneTableScan() throws IOException {
|
|||
Ref act = rc.getRef();
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(1, act.getUpdateIndex());
|
||||
}
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -145,6 +148,7 @@ public void deleteIsHidden() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/master", rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +166,7 @@ public void twoTableSeek() throws IOException {
|
|||
assertEquals("refs/heads/master", rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertFalse(rc.next());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +182,7 @@ public void twoTableById() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/master", rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
@ -212,6 +218,7 @@ public void fourTableScan() throws IOException {
|
|||
Ref act = rc.getRef();
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -231,9 +238,11 @@ public void scanDuplicates() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/apple", rc.getRef().getName());
|
||||
assertEquals(id(3), rc.getRef().getObjectId());
|
||||
assertEquals(2000, rc.getRef().getUpdateIndex());
|
||||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/banana", rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(1000, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
@ -251,12 +260,14 @@ public void scanIncludeDeletes() throws IOException {
|
|||
Ref r = rc.getRef();
|
||||
assertEquals("refs/heads/master", r.getName());
|
||||
assertEquals(id(8), r.getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
r = rc.getRef();
|
||||
assertEquals("refs/heads/next", r.getName());
|
||||
assertEquals(NEW, r.getStorage());
|
||||
assertNull(r.getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -277,6 +288,7 @@ public void oneTableSeek() throws IOException {
|
|||
Ref act = rc.getRef();
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(1, act.getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
@ -303,17 +315,17 @@ public void missedUpdate() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/a", rc.getRef().getName());
|
||||
assertEquals(id(1), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getUpdateIndex());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/b", rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(2, rc.getUpdateIndex());
|
||||
assertEquals(2, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
assertEquals("refs/heads/c", rc.getRef().getName());
|
||||
assertEquals(id(3), rc.getRef().getObjectId());
|
||||
assertEquals(3, rc.getUpdateIndex());
|
||||
assertEquals(3, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,6 +356,63 @@ public void compaction() throws IOException {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void versioningSymbolicReftargetMoves() throws IOException {
|
||||
Ref master = ref(MASTER, 100);
|
||||
|
||||
List<Ref> delta1 = Arrays.asList(master, sym(HEAD, MASTER));
|
||||
List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
|
||||
|
||||
MergedReftable mr = merge(write(delta1, 1), write(delta2, 2));
|
||||
Ref head = mr.exactRef(HEAD);
|
||||
assertEquals(head.getUpdateIndex(), 1);
|
||||
|
||||
Ref masterRef = mr.exactRef(MASTER);
|
||||
assertEquals(masterRef.getUpdateIndex(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void versioningSymbolicRefMoves() throws IOException {
|
||||
Ref branchX = ref("refs/heads/branchX", 200);
|
||||
|
||||
List<Ref> delta1 = Arrays.asList(ref(MASTER, 100), branchX,
|
||||
sym(HEAD, MASTER));
|
||||
List<Ref> delta2 = Arrays.asList(sym(HEAD, "refs/heads/branchX"));
|
||||
List<Ref> delta3 = Arrays.asList(sym(HEAD, MASTER));
|
||||
|
||||
MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
|
||||
write(delta3, 3));
|
||||
Ref head = mr.exactRef(HEAD);
|
||||
assertEquals(head.getUpdateIndex(), 3);
|
||||
|
||||
Ref masterRef = mr.exactRef(MASTER);
|
||||
assertEquals(masterRef.getUpdateIndex(), 1);
|
||||
|
||||
Ref branchRef = mr.exactRef(MASTER);
|
||||
assertEquals(branchRef.getUpdateIndex(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void versioningResolveRef() throws IOException {
|
||||
List<Ref> delta1 = Arrays.asList(sym(HEAD, "refs/heads/tmp"),
|
||||
sym("refs/heads/tmp", MASTER), ref(MASTER, 100));
|
||||
List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
|
||||
List<Ref> delta3 = Arrays.asList(ref(MASTER, 300));
|
||||
|
||||
MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
|
||||
write(delta3, 3));
|
||||
Ref head = mr.exactRef(HEAD);
|
||||
Ref resolvedHead = mr.resolve(head);
|
||||
assertEquals(resolvedHead.getObjectId(), id(300));
|
||||
assertEquals("HEAD has not moved", resolvedHead.getUpdateIndex(), 1);
|
||||
|
||||
Ref master = mr.exactRef(MASTER);
|
||||
Ref resolvedMaster = mr.resolve(master);
|
||||
assertEquals(resolvedMaster.getObjectId(), id(300));
|
||||
assertEquals("master also has update index",
|
||||
resolvedMaster.getUpdateIndex(), 3);
|
||||
}
|
||||
|
||||
private static MergedReftable merge(byte[]... table) {
|
||||
List<Reftable> stack = new ArrayList<>(table.length);
|
||||
for (byte[] b : table) {
|
||||
|
@ -360,6 +429,14 @@ private static Ref ref(String name, int id) {
|
|||
return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
|
||||
}
|
||||
|
||||
private static Ref sym(String name, String target) {
|
||||
return new SymbolicRef(name, newRef(target));
|
||||
}
|
||||
|
||||
private static Ref newRef(String name) {
|
||||
return new ObjectIdRef.Unpeeled(NEW, name, null);
|
||||
}
|
||||
|
||||
private static Ref delete(String name) {
|
||||
return new ObjectIdRef.Unpeeled(NEW, name, null);
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ public void oneTable() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals(MASTER, rc.getRef().getName());
|
||||
assertEquals(id(1), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getUpdateIndex());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ public void twoTablesOneRef() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals(MASTER, rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getUpdateIndex());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,12 +203,12 @@ public void twoTablesTwoRefs() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals(MASTER, rc.getRef().getName());
|
||||
assertEquals(id(3), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getUpdateIndex());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
assertEquals(NEXT, rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getUpdateIndex());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@ public void oneIdRef() throws IOException {
|
|||
assertFalse(act.isSymbolic());
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(0, act.getUpdateIndex());
|
||||
assertNull(act.getPeeledObjectId());
|
||||
assertFalse(rc.wasDeleted());
|
||||
assertFalse(rc.next());
|
||||
|
@ -195,6 +196,7 @@ public void oneIdRef() throws IOException {
|
|||
Ref act = rc.getRef();
|
||||
assertNotNull(act);
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(0, act.getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
@ -216,6 +218,7 @@ public void oneTagRef() throws IOException {
|
|||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(exp.getPeeledObjectId(), act.getPeeledObjectId());
|
||||
assertEquals(0, act.getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,6 +240,7 @@ public void oneSymbolicRef() throws IOException {
|
|||
assertNotNull(act.getLeaf());
|
||||
assertEquals(MASTER, act.getTarget().getName());
|
||||
assertNull(act.getObjectId());
|
||||
assertEquals(0, act.getUpdateIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,14 +254,17 @@ public void resolveSymbolicRef() throws IOException {
|
|||
Ref head = t.exactRef(HEAD);
|
||||
assertNull(head.getObjectId());
|
||||
assertEquals("refs/heads/tmp", head.getTarget().getName());
|
||||
assertEquals(0, head.getUpdateIndex());
|
||||
|
||||
head = t.resolve(head);
|
||||
assertNotNull(head);
|
||||
assertEquals(id(1), head.getObjectId());
|
||||
assertEquals(0, head.getUpdateIndex());
|
||||
|
||||
Ref master = t.exactRef(MASTER);
|
||||
assertNotNull(master);
|
||||
assertSame(master, t.resolve(master));
|
||||
assertEquals(0, master.getUpdateIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -335,14 +342,17 @@ public void namespaceHeads() throws IOException {
|
|||
try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) {
|
||||
assertTrue(rc.next());
|
||||
assertEquals(V1_0, rc.getRef().getName());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) {
|
||||
assertTrue(rc.next());
|
||||
assertEquals(MASTER, rc.getRef().getName());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
assertEquals(NEXT, rc.getRef().getName());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -432,11 +442,12 @@ public void withReflog() throws IOException {
|
|||
assertTrue(rc.next());
|
||||
assertEquals(MASTER, rc.getRef().getName());
|
||||
assertEquals(id(1), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getUpdateIndex());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertTrue(rc.next());
|
||||
assertEquals(NEXT, rc.getRef().getName());
|
||||
assertEquals(id(2), rc.getRef().getObjectId());
|
||||
assertEquals(1, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
try (LogCursor lc = t.allLogs()) {
|
||||
|
@ -569,6 +580,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
|
|||
assertTrue("has 42", rc.next());
|
||||
assertEquals("refs/heads/42", rc.getRef().getName());
|
||||
assertEquals(id(42), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
try (RefCursor rc = t.byObjectId(id(100))) {
|
||||
|
@ -579,6 +591,7 @@ public void byObjectIdOneRefNoIndex() throws IOException {
|
|||
assertTrue("has master", rc.next());
|
||||
assertEquals("refs/heads/master", rc.getRef().getName());
|
||||
assertEquals(id(100), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -600,6 +613,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
|
|||
assertTrue("has 42", rc.next());
|
||||
assertEquals("refs/heads/42", rc.getRef().getName());
|
||||
assertEquals(id(42), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
try (RefCursor rc = t.byObjectId(id(100))) {
|
||||
|
@ -610,6 +624,7 @@ public void byObjectIdOneRefWithIndex() throws IOException {
|
|||
assertTrue("has master", rc.next());
|
||||
assertEquals("refs/heads/master", rc.getRef().getName());
|
||||
assertEquals(id(100), rc.getRef().getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -654,7 +669,6 @@ public void badCrc32() throws IOException {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static void assertScan(List<Ref> refs, Reftable t)
|
||||
throws IOException {
|
||||
try (RefCursor rc = t.allRefs()) {
|
||||
|
@ -663,6 +677,7 @@ private static void assertScan(List<Ref> refs, Reftable t)
|
|||
Ref act = rc.getRef();
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
}
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
|
@ -676,6 +691,7 @@ private static void assertSeek(List<Ref> refs, Reftable t)
|
|||
Ref act = rc.getRef();
|
||||
assertEquals(exp.getName(), act.getName());
|
||||
assertEquals(exp.getObjectId(), act.getObjectId());
|
||||
assertEquals(0, rc.getRef().getUpdateIndex());
|
||||
assertFalse(rc.next());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@
|
|||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -114,11 +118,44 @@ public void testConstructor_Peeled() {
|
|||
assertSame(ID_B, r.getPeeledObjectId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateIndex() {
|
||||
ObjectIdRef r;
|
||||
|
||||
r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A, 3);
|
||||
assertTrue(r.getUpdateIndex() == 3);
|
||||
|
||||
r = new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B, 4);
|
||||
assertTrue(r.getUpdateIndex() == 4);
|
||||
|
||||
r = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A, 5);
|
||||
assertTrue(r.getUpdateIndex() == 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateIndexNotSet() {
|
||||
List<ObjectIdRef> r = Arrays.asList(
|
||||
new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A),
|
||||
new ObjectIdRef.PeeledTag(Ref.Storage.LOOSE, name, ID_A, ID_B),
|
||||
new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, name, ID_A));
|
||||
|
||||
for (ObjectIdRef ref : r) {
|
||||
try {
|
||||
ref.getUpdateIndex();
|
||||
fail("Update index wasn't set. It must throw");
|
||||
} catch (UnsupportedOperationException u) {
|
||||
// Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
ObjectIdRef r;
|
||||
|
||||
r = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, ID_A);
|
||||
assertEquals("Ref[" + name + "=" + ID_A.name() + "]", r.toString());
|
||||
assertEquals("Ref[" + name + "=" + ID_A.name() + "(-1)]",
|
||||
r.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public void testConstructor() {
|
|||
SymbolicRef r;
|
||||
|
||||
t = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, targetName, null);
|
||||
r = new SymbolicRef(name, t);
|
||||
r = new SymbolicRef(name, t, 1);
|
||||
assertSame(Ref.Storage.LOOSE, r.getStorage());
|
||||
assertSame(name, r.getName());
|
||||
assertNull("no id on new ref", r.getObjectId());
|
||||
|
@ -77,9 +77,10 @@ public void testConstructor() {
|
|||
assertSame("leaf is t", t, r.getLeaf());
|
||||
assertSame("target is t", t, r.getTarget());
|
||||
assertTrue("is symbolic", r.isSymbolic());
|
||||
assertTrue("holds update index", r.getUpdateIndex() == 1);
|
||||
|
||||
t = new ObjectIdRef.Unpeeled(Ref.Storage.PACKED, targetName, ID_A);
|
||||
r = new SymbolicRef(name, t);
|
||||
r = new SymbolicRef(name, t, 2);
|
||||
assertSame(Ref.Storage.LOOSE, r.getStorage());
|
||||
assertSame(name, r.getName());
|
||||
assertSame(ID_A, r.getObjectId());
|
||||
|
@ -88,6 +89,7 @@ public void testConstructor() {
|
|||
assertSame("leaf is t", t, r.getLeaf());
|
||||
assertSame("target is t", t, r.getTarget());
|
||||
assertTrue("is symbolic", r.isSymbolic());
|
||||
assertTrue("holds update index", r.getUpdateIndex() == 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -133,6 +135,6 @@ public void testToString() {
|
|||
d = new SymbolicRef("D", c);
|
||||
|
||||
assertEquals("SymbolicRef[D -> C -> B -> " + targetName + "="
|
||||
+ ID_A.name() + "]", d.toString());
|
||||
+ ID_A.name() + "(-1)]", d.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,12 @@ protected DfsReftableDatabase(DfsRepository repo) {
|
|||
super(repo);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean hasVersioning() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean performsAtomicTransactions() {
|
||||
|
|
|
@ -170,24 +170,27 @@ long readUpdateIndexDelta() {
|
|||
return readVarint64();
|
||||
}
|
||||
|
||||
Ref readRef() throws IOException {
|
||||
Ref readRef(long minUpdateIndex) throws IOException {
|
||||
long updateIndex = minUpdateIndex + readUpdateIndexDelta();
|
||||
String name = RawParseUtils.decode(UTF_8, nameBuf, 0, nameLen);
|
||||
switch (valueType & VALUE_TYPE_MASK) {
|
||||
case VALUE_NONE: // delete
|
||||
return newRef(name);
|
||||
return newRef(name, updateIndex);
|
||||
|
||||
case VALUE_1ID:
|
||||
return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId());
|
||||
return new ObjectIdRef.PeeledNonTag(PACKED, name, readValueId(),
|
||||
updateIndex);
|
||||
|
||||
case VALUE_2ID: { // annotated tag
|
||||
ObjectId id1 = readValueId();
|
||||
ObjectId id2 = readValueId();
|
||||
return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2);
|
||||
return new ObjectIdRef.PeeledTag(PACKED, name, id1, id2,
|
||||
updateIndex);
|
||||
}
|
||||
|
||||
case VALUE_SYMREF: {
|
||||
String val = readValueString();
|
||||
return new SymbolicRef(name, newRef(val));
|
||||
return new SymbolicRef(name, newRef(val, updateIndex), updateIndex);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -410,7 +413,7 @@ void verifyIndex() throws IOException {
|
|||
* <ul>
|
||||
* <li>{@link #name()}
|
||||
* <li>{@link #match(byte[], boolean)}
|
||||
* <li>{@link #readRef()}
|
||||
* <li>{@link #readRef(long)}
|
||||
* <li>{@link #readLogUpdateIndex()}
|
||||
* <li>{@link #readLogEntry()}
|
||||
* <li>{@link #readBlockPositionList()}
|
||||
|
@ -575,8 +578,8 @@ private long readVarint64() {
|
|||
return val;
|
||||
}
|
||||
|
||||
private static Ref newRef(String name) {
|
||||
return new ObjectIdRef.Unpeeled(NEW, name, null);
|
||||
private static Ref newRef(String name, long updateIndex) {
|
||||
return new ObjectIdRef.Unpeeled(NEW, name, null, updateIndex);
|
||||
}
|
||||
|
||||
private static IOException invalidBlock() {
|
||||
|
|
|
@ -168,7 +168,6 @@ private class MergedRefCursor extends RefCursor {
|
|||
private final PriorityQueue<RefQueueEntry> queue;
|
||||
private RefQueueEntry head;
|
||||
private Ref ref;
|
||||
private long updateIndex;
|
||||
|
||||
MergedRefCursor() {
|
||||
queue = new PriorityQueue<>(queueSize(), RefQueueEntry::compare);
|
||||
|
@ -206,7 +205,6 @@ public boolean next() throws IOException {
|
|||
}
|
||||
|
||||
ref = t.rc.getRef();
|
||||
updateIndex = t.rc.getUpdateIndex();
|
||||
boolean include = includeDeletes || !t.rc.wasDeleted();
|
||||
add(t);
|
||||
skipShadowedRefs(ref.getName());
|
||||
|
@ -241,11 +239,6 @@ public Ref getRef() {
|
|||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUpdateIndex() {
|
||||
return updateIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (head != null) {
|
||||
|
@ -285,7 +278,7 @@ String name() {
|
|||
}
|
||||
|
||||
long updateIndex() {
|
||||
return rc.getUpdateIndex();
|
||||
return rc.getRef().getUpdateIndex();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,13 +68,6 @@ public abstract class RefCursor implements AutoCloseable {
|
|||
*/
|
||||
public abstract Ref getRef();
|
||||
|
||||
/**
|
||||
* Get updateIndex that last modified the current reference.
|
||||
*
|
||||
* @return updateIndex that last modified the current reference.
|
||||
*/
|
||||
public abstract long getUpdateIndex();
|
||||
|
||||
/**
|
||||
* Whether the current reference was deleted.
|
||||
*
|
||||
|
|
|
@ -280,7 +280,7 @@ private Ref resolve(Ref ref, int depth) throws IOException {
|
|||
if (dst == null) {
|
||||
return null; // claim it doesn't exist
|
||||
}
|
||||
return new SymbolicRef(ref.getName(), dst);
|
||||
return new SymbolicRef(ref.getName(), dst, ref.getUpdateIndex());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
|
@ -256,7 +256,7 @@ public Stats getStats() {
|
|||
private void mergeRefs(MergedReftable mr) throws IOException {
|
||||
try (RefCursor rc = mr.allRefs()) {
|
||||
while (rc.next()) {
|
||||
writer.writeRef(rc.getRef(), rc.getUpdateIndex());
|
||||
writer.writeRef(rc.getRef(), rc.getRef().getUpdateIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -479,7 +479,6 @@ private class RefCursorImpl extends RefCursor {
|
|||
private final boolean prefix;
|
||||
|
||||
private Ref ref;
|
||||
private long updateIndex;
|
||||
BlockReader block;
|
||||
|
||||
RefCursorImpl(long scanEnd, byte[] match, boolean prefix) {
|
||||
|
@ -508,8 +507,7 @@ public boolean next() throws IOException {
|
|||
return false;
|
||||
}
|
||||
|
||||
updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
|
||||
ref = block.readRef();
|
||||
ref = block.readRef(minUpdateIndex);
|
||||
if (!includeDeletes && wasDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -522,11 +520,6 @@ public Ref getRef() {
|
|||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUpdateIndex() {
|
||||
return updateIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Do nothing.
|
||||
|
@ -605,7 +598,6 @@ private class ObjCursorImpl extends RefCursor {
|
|||
private final ObjectId match;
|
||||
|
||||
private Ref ref;
|
||||
private long updateIndex;
|
||||
private int listIdx;
|
||||
|
||||
private LongList blockPos;
|
||||
|
@ -679,8 +671,7 @@ public boolean next() throws IOException {
|
|||
}
|
||||
|
||||
block.parseKey();
|
||||
updateIndex = minUpdateIndex + block.readUpdateIndexDelta();
|
||||
ref = block.readRef();
|
||||
ref = block.readRef(minUpdateIndex);
|
||||
ObjectId id = ref.getObjectId();
|
||||
if (id != null && match.equals(id)
|
||||
&& (includeDeletes || !wasDeleted())) {
|
||||
|
@ -694,11 +685,6 @@ public Ref getRef() {
|
|||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUpdateIndex() {
|
||||
return updateIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Do nothing.
|
||||
|
|
|
@ -67,7 +67,25 @@ public static class Unpeeled extends ObjectIdRef {
|
|||
*/
|
||||
public Unpeeled(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id) {
|
||||
super(st, name, id);
|
||||
super(st, name, id, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ref pairing with update index.
|
||||
*
|
||||
* @param st
|
||||
* method used to store this ref.
|
||||
* @param name
|
||||
* name of this ref.
|
||||
* @param id
|
||||
* current value of the ref. May be {@code null} to indicate
|
||||
* a ref that does not exist yet.
|
||||
* @param updateIndex
|
||||
* number increasing with each update to the reference.
|
||||
*/
|
||||
public Unpeeled(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id, long updateIndex) {
|
||||
super(st, name, id, updateIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,7 +118,28 @@ public static class PeeledTag extends ObjectIdRef {
|
|||
*/
|
||||
public PeeledTag(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id, @NonNull ObjectId p) {
|
||||
super(st, name, id);
|
||||
super(st, name, id, -1);
|
||||
peeledObjectId = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ref pairing with update index.
|
||||
*
|
||||
* @param st
|
||||
* method used to store this ref.
|
||||
* @param name
|
||||
* name of this ref.
|
||||
* @param id
|
||||
* current value of the ref. May be {@code null} to indicate
|
||||
* a ref that does not exist yet.
|
||||
* @param p
|
||||
* the first non-tag object that tag {@code id} points to.
|
||||
* @param updateIndex
|
||||
* number increasing with each update to the reference.
|
||||
*/
|
||||
public PeeledTag(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id, @NonNull ObjectId p, long updateIndex) {
|
||||
super(st, name, id, updateIndex);
|
||||
peeledObjectId = p;
|
||||
}
|
||||
|
||||
|
@ -131,7 +170,25 @@ public static class PeeledNonTag extends ObjectIdRef {
|
|||
*/
|
||||
public PeeledNonTag(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id) {
|
||||
super(st, name, id);
|
||||
super(st, name, id, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ref pairing with update index.
|
||||
*
|
||||
* @param st
|
||||
* method used to store this ref.
|
||||
* @param name
|
||||
* name of this ref.
|
||||
* @param id
|
||||
* current value of the ref. May be {@code null} to indicate
|
||||
* a ref that does not exist yet.
|
||||
* @param updateIndex
|
||||
* number increasing with each update to the reference.
|
||||
*/
|
||||
public PeeledNonTag(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id, long updateIndex) {
|
||||
super(st, name, id, updateIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,6 +209,8 @@ public boolean isPeeled() {
|
|||
|
||||
private final ObjectId objectId;
|
||||
|
||||
private final long updateIndex;
|
||||
|
||||
/**
|
||||
* Create a new ref pairing.
|
||||
*
|
||||
|
@ -162,12 +221,16 @@ public boolean isPeeled() {
|
|||
* @param id
|
||||
* current value of the ref. May be {@code null} to indicate a
|
||||
* ref that does not exist yet.
|
||||
* @param updateIndex
|
||||
* number that increases with each ref update. Set to -1 if the
|
||||
* storage doesn't support versioning.
|
||||
*/
|
||||
protected ObjectIdRef(@NonNull Storage st, @NonNull String name,
|
||||
@Nullable ObjectId id) {
|
||||
@Nullable ObjectId id, long updateIndex) {
|
||||
this.name = name;
|
||||
this.storage = st;
|
||||
this.objectId = id;
|
||||
this.updateIndex = updateIndex;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
@ -211,6 +274,15 @@ public Storage getStorage() {
|
|||
return storage;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public long getUpdateIndex() {
|
||||
if (updateIndex == -1) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return updateIndex;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@NonNull
|
||||
@Override
|
||||
|
@ -220,7 +292,9 @@ public String toString() {
|
|||
r.append(getName());
|
||||
r.append('=');
|
||||
r.append(ObjectId.toString(getObjectId()));
|
||||
r.append(']');
|
||||
r.append('(');
|
||||
r.append(updateIndex); // Print value, even if -1
|
||||
r.append(")]"); //$NON-NLS-1$
|
||||
return r.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,4 +217,27 @@ public boolean isPacked() {
|
|||
*/
|
||||
@NonNull
|
||||
Storage getStorage();
|
||||
|
||||
/**
|
||||
* Indicator of the relative order between updates of a specific reference
|
||||
* name. A number that increases when a reference is updated.
|
||||
* <p>
|
||||
* With symbolic references, the update index refers to updates of the
|
||||
* symbolic reference itself. For example, if HEAD points to
|
||||
* refs/heads/master, then the update index for exactRef("HEAD") will only
|
||||
* increase when HEAD changes to point to another ref, regardless of how
|
||||
* many times refs/heads/master is updated.
|
||||
* <p>
|
||||
* Should not be used unless the {@code RefDatabase} that instantiated the
|
||||
* ref supports versioning (see {@link RefDatabase#hasVersioning()})
|
||||
*
|
||||
* @return the update index (i.e. version) of this reference.
|
||||
* @throws UnsupportedOperationException
|
||||
* if the creator of the instance (e.g. {@link RefDatabase})
|
||||
* doesn't support versioning and doesn't override this method
|
||||
* @since 5.3
|
||||
*/
|
||||
default long getUpdateIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,19 @@ public abstract class RefDatabase {
|
|||
*/
|
||||
public abstract void close();
|
||||
|
||||
/**
|
||||
* With versioning, each reference has a version number that increases on
|
||||
* update. See {@link Ref#getUpdateIndex()}.
|
||||
*
|
||||
* @implSpec This method returns false by default. Implementations
|
||||
* supporting versioning must override it to return true.
|
||||
* @return true if the implementation assigns update indices to references.
|
||||
* @since 5.3
|
||||
*/
|
||||
public boolean hasVersioning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a proposed reference name overlaps with an existing one.
|
||||
* <p>
|
||||
|
|
|
@ -58,6 +58,8 @@ public class SymbolicRef implements Ref {
|
|||
|
||||
private final Ref target;
|
||||
|
||||
private final long updateIndex;
|
||||
|
||||
/**
|
||||
* Create a new ref pairing.
|
||||
*
|
||||
|
@ -69,6 +71,24 @@ public class SymbolicRef implements Ref {
|
|||
public SymbolicRef(@NonNull String refName, @NonNull Ref target) {
|
||||
this.name = refName;
|
||||
this.target = target;
|
||||
this.updateIndex = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ref pairing.
|
||||
*
|
||||
* @param refName
|
||||
* name of this ref.
|
||||
* @param target
|
||||
* the ref we reference and derive our value from.
|
||||
* @param updateIndex
|
||||
* index that increases with each update of the reference
|
||||
*/
|
||||
public SymbolicRef(@NonNull String refName, @NonNull Ref target,
|
||||
long updateIndex) {
|
||||
this.name = refName;
|
||||
this.target = target;
|
||||
this.updateIndex = updateIndex;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
@ -128,6 +148,15 @@ public boolean isPeeled() {
|
|||
return getLeaf().isPeeled();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public long getUpdateIndex() {
|
||||
if (updateIndex == -1) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return updateIndex;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@SuppressWarnings("nls")
|
||||
@Override
|
||||
|
@ -143,7 +172,9 @@ public String toString() {
|
|||
r.append(cur.getName());
|
||||
r.append('=');
|
||||
r.append(ObjectId.toString(cur.getObjectId()));
|
||||
r.append("]");
|
||||
r.append("(");
|
||||
r.append(updateIndex); // Print value, even if -1
|
||||
r.append(")]");
|
||||
return r.toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue