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
This commit is contained in:
Han-Wen Nienhuys 2019-10-13 19:21:06 +02:00
parent bca00aa5f4
commit 218bacdc1f
2 changed files with 50 additions and 1 deletions

View File

@ -187,6 +187,19 @@ public void twoTableById() throws IOException {
}
}
@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 {

View File

@ -131,7 +131,7 @@ public RefCursor seekRefsWithPrefix(String prefix) throws IOException {
/** {@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 void close() {
}
}
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());