Browse Source

reftable: fix lookup by ID in merged reftables

On changing a ref, the old SHA1 is not updated in the object => ref
mapping. This means search by object ID may still turn up a ref from
deeper within the stack. To fix this, check all refs produced by the
merged iterator against the merged reftables.

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Change-Id: I41e9cd395b0608eedeeaead0a9fd997238d747c9
tags/v5.6.0.201911271000-m3
Han-Wen Nienhuys 4 years ago
parent
commit
218bacdc1f

+ 13
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java View File

@@ -187,6 +187,19 @@ public class MergedReftableTest {
}
}

@Test
public void tableByIDDeletion() throws IOException {
List<Ref> delta1 = Arrays.asList(
ref("refs/heads/apple", 1),
ref("refs/heads/master", 2));
List<Ref> delta2 = Arrays.asList(ref("refs/heads/master", 3));

MergedReftable mr = merge(write(delta1), write(delta2));
try (RefCursor rc = mr.byObjectId(id(2))) {
assertFalse(rc.next());
}
}

@SuppressWarnings("boxing")
@Test
public void fourTableScan() throws IOException {

+ 37
- 1
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java View File

@@ -131,7 +131,7 @@ public class MergedReftable extends Reftable {
/** {@inheritDoc} */
@Override
public RefCursor byObjectId(AnyObjectId name) throws IOException {
MergedRefCursor m = new MergedRefCursor();
MergedRefCursor m = new FilteringMergedRefCursor(name);
for (int i = 0; i < tables.length; i++) {
m.add(new RefQueueEntry(tables[i].byObjectId(name), i));
}
@@ -250,6 +250,42 @@ public class MergedReftable extends Reftable {
}
}

private class FilteringMergedRefCursor extends MergedRefCursor {
final AnyObjectId filterId;
Ref filteredRef;

FilteringMergedRefCursor(AnyObjectId id) {
filterId = id;
filteredRef = null;
}

@Override
public Ref getRef() {
return filteredRef;
}

@Override
public boolean next() throws IOException {
for (;;) {
boolean ok = super.next();
if (!ok) {
return false;
}

String name = super.getRef().getName();

try (RefCursor c = seekRef(name)) {
if (c.next()) {
if (filterId.equals(c.getRef().getObjectId())) {
filteredRef = c.getRef();
return true;
}
}
}
}
}
}

private static class RefQueueEntry {
static int compare(RefQueueEntry a, RefQueueEntry b) {
int cmp = a.name().compareTo(b.name());

Loading…
Cancel
Save