]> source.dussan.org Git - jgit.git/commitdiff
reftable: fix seeking to refs in reflog implementation 87/146787/8
authorHan-Wen Nienhuys <hanwen@google.com>
Mon, 29 Jul 2019 08:58:50 +0000 (10:58 +0200)
committerHan-Wen Nienhuys <hanwen@google.com>
Mon, 19 Aug 2019 09:10:20 +0000 (11:10 +0200)
Small reftables omit the log index. Currently,
ReftableWriter#shouldHaveIndex does this if there is a single-block
log, but other writers could decide on different criteria.

In the case that the log index is missing, we have to linearly search
for the right block. It is never appropriate to use binary search on
blocks for log data, as the blocks are compressed and therefore
irregularly sized.

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Change-Id: Id59874edf6bf45c7dec502d9465888e077ffe198

org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java

index a1421669837f2ca405fce01954e4a4851bf8e460..db9a4d0ac137754a5b661eb227f01003a8cda2d6 100644 (file)
@@ -471,6 +471,51 @@ public class ReftableTest {
                }
        }
 
+       @Test
+       public void reflogSeek() throws IOException {
+               PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
+               String msg = "test";
+               String msgNext = "test next";
+
+               ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+               ReftableWriter writer = new ReftableWriter()
+                               .setMinUpdateIndex(1)
+                               .setMaxUpdateIndex(1)
+                               .begin(buffer);
+
+               writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
+               writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msgNext);
+
+               writer.finish();
+               byte[] table = buffer.toByteArray();
+
+               ReftableReader t = read(table);
+               try (LogCursor c = t.seekLog(MASTER, Long.MAX_VALUE)) {
+                       assertTrue(c.next());
+                       assertEquals(c.getReflogEntry().getComment(), msg);
+               }
+               try (LogCursor c = t.seekLog(MASTER, 0)) {
+                       assertFalse(c.next());
+               }
+               try (LogCursor c = t.seekLog(MASTER, 1)) {
+                       assertTrue(c.next());
+                       assertEquals(c.getUpdateIndex(), 1);
+                       assertEquals(c.getReflogEntry().getComment(), msg);
+               }
+               try (LogCursor c = t.seekLog(NEXT, Long.MAX_VALUE)) {
+                       assertTrue(c.next());
+                       assertEquals(c.getReflogEntry().getComment(), msgNext);
+               }
+               try (LogCursor c = t.seekLog(NEXT, 0)) {
+                       assertFalse(c.next());
+               }
+               try (LogCursor c = t.seekLog(NEXT, 1)) {
+                       assertTrue(c.next());
+                       assertEquals(c.getUpdateIndex(), 1);
+                       assertEquals(c.getReflogEntry().getComment(), msgNext);
+               }
+       }
+
        @Test
        public void onlyReflog() throws IOException {
                PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
index bf3a9aeca019ca5e678c73d98c34f3965fe00c1e..226e675e41a7dcc9fafd095e7b241948a33fc1d7 100644 (file)
@@ -255,6 +255,32 @@ public class ReftableReader extends Reftable {
                        block.seekKey(key);
                        return block;
                }
+               if (blockType == LOG_BLOCK_TYPE) {
+                       // No index. Log blocks are irregularly sized, so we can't do binary search
+                       // between blocks. Scan over blocks instead.
+                       BlockReader block = readBlock(startPos, endPos);
+
+                       for (;;) {
+                               if (block == null || block.type() != LOG_BLOCK_TYPE) {
+                                       return null;
+                               }
+
+                               int result = block.seekKey(key);
+                               if (result <= 0) {
+                                       // == 0 : we found the key.
+                                       // < 0 : the key is before this block. Either the ref name is there
+                                       // but only at a newer updateIndex, or it is absent. We leave it to
+                                       // logcursor to distinguish between both cases.
+                                       return block;
+                               }
+
+                               long pos = block.endPosition();
+                               if (pos >= endPos) {
+                                       return null;
+                               }
+                               block = readBlock(pos, endPos);
+                       }
+               }
                return binarySearch(blockType, key, startPos, endPos);
        }