]> source.dussan.org Git - jgit.git/commitdiff
Implement get nth offset in PackIndex. 53/14153/2
authorColby Ranger <cranger@google.com>
Fri, 28 Jun 2013 21:02:26 +0000 (14:02 -0700)
committerColby Ranger <cranger@google.com>
Fri, 28 Jun 2013 22:36:20 +0000 (15:36 -0700)
Currently, the offset can only be retrieved by ObjectId or iterating all
of the entries. Add a method to lookup the offset by position in the
index sorted by SHA1.

Change-Id: I45e9ac8b752d1dab47b202753a1dcca7122b958e

org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java

index aa3817e3adfc1c248aa15ed51c8cf8eb400f9849..7eeb0c0eaa3ad38cfa5d1e071d2bee81d2af3971 100644 (file)
@@ -157,6 +157,21 @@ public abstract class PackIndexTestCase extends RepositoryTestCase {
                }
        }
 
+       /**
+        * Compare offset from iterator entries with output of getOffset() method.
+        */
+       @Test
+       public void testCompareEntriesOffsetsWithGetOffsets() {
+               int i = 0;
+               for (MutableEntry me : smallIdx) {
+                       assertEquals(smallIdx.getOffset(i++), me.getOffset());
+               }
+               int j = 0;
+               for (MutableEntry me : denseIdx) {
+                       assertEquals(denseIdx.getOffset(j++), me.getOffset());
+               }
+       }
+
        /**
         * Test partial results of iterator comparing to content of well-known
         * (prepared) dense index, that may need multi-level indexing.
index 44baeb190c07a31845193028b1ac48fede3f09d8..0040aea713199da73898719ab52c041d386e5d5f 100644 (file)
@@ -244,6 +244,19 @@ public abstract class PackIndex implements Iterable<PackIndex.MutableEntry> {
                return getObjectId(((long) u31) << 1 | one);
        }
 
+       /**
+        * Get offset in a pack for the n-th object entry returned by
+        * {@link #iterator()}.
+        *
+        * @param nthPosition
+        *            unsigned 32 bit position within the traversal of
+        *            {@link #iterator()} for which the caller needs the offset. The
+        *            first returned {@link MutableEntry} is 0, the second is 1,
+        *            etc. Positions past 2**31-1 are negative, but still valid.
+        * @return the offset in a pack for the corresponding entry.
+        */
+       abstract long getOffset(long nthPosition);
+
        /**
         * Locate the file offset position for the requested object.
         *
index 8c381fb830565cc31921416da9f1cf09791f821f..2d574d80a0b66a64c8657be58483ca148f87137d 100644 (file)
@@ -113,15 +113,13 @@ class PackIndexV1 extends PackIndex {
                return n64;
        }
 
-       @Override
-       public ObjectId getObjectId(final long nthPosition) {
+       private int findLevelOne(final long nthPosition) {
                int levelOne = Arrays.binarySearch(idxHeader, nthPosition + 1);
-               long base;
                if (levelOne >= 0) {
                        // If we hit the bucket exactly the item is in the bucket, or
                        // any bucket before it which has the same object count.
                        //
-                       base = idxHeader[levelOne];
+                       long base = idxHeader[levelOne];
                        while (levelOne > 0 && base == idxHeader[levelOne - 1])
                                levelOne--;
                } else {
@@ -129,13 +127,30 @@ class PackIndexV1 extends PackIndex {
                        //
                        levelOne = -(levelOne + 1);
                }
+               return levelOne;
+       }
+
+       private int getLevelTwo(final long nthPosition, final int levelOne) {
+               final long base = levelOne > 0 ? idxHeader[levelOne - 1] : 0;
+               return (int) (nthPosition - base);
+       }
 
-               base = levelOne > 0 ? idxHeader[levelOne - 1] : 0;
-               final int p = (int) (nthPosition - base);
+       @Override
+       public ObjectId getObjectId(final long nthPosition) {
+               final int levelOne = findLevelOne(nthPosition);
+               final int p = getLevelTwo(nthPosition, levelOne);
                final int dataIdx = idOffset(p);
                return ObjectId.fromRaw(idxdata[levelOne], dataIdx);
        }
 
+       @Override
+       long getOffset(long nthPosition) {
+               final int levelOne = findLevelOne(nthPosition);
+               final int levelTwo = getLevelTwo(nthPosition, levelOne);
+               final int p = (4 + Constants.OBJECT_ID_LENGTH) * levelTwo;
+               return NB.decodeUInt32(idxdata[levelOne], p);
+       }
+
        @Override
        public long findOffset(final AnyObjectId objId) {
                final int levelOne = objId.getFirstByte();
index 9b1a5f3ce1be1010cd83ce1b7249a33d8f4c6696..9d2caa2e880d449c85d95e999296df8c9eec5f90 100644 (file)
@@ -170,15 +170,13 @@ class PackIndexV2 extends PackIndex {
                return offset64.length / 8;
        }
 
-       @Override
-       public ObjectId getObjectId(final long nthPosition) {
+       private int findLevelOne(final long nthPosition) {
                int levelOne = Arrays.binarySearch(fanoutTable, nthPosition + 1);
-               long base;
                if (levelOne >= 0) {
                        // If we hit the bucket exactly the item is in the bucket, or
                        // any bucket before it which has the same object count.
                        //
-                       base = fanoutTable[levelOne];
+                       long base = fanoutTable[levelOne];
                        while (levelOne > 0 && base == fanoutTable[levelOne - 1])
                                levelOne--;
                } else {
@@ -186,19 +184,39 @@ class PackIndexV2 extends PackIndex {
                        //
                        levelOne = -(levelOne + 1);
                }
+               return levelOne;
+       }
 
-               base = levelOne > 0 ? fanoutTable[levelOne - 1] : 0;
-               final int p = (int) (nthPosition - base);
+       private int getLevelTwo(final long nthPosition, final int levelOne) {
+               final long base = levelOne > 0 ? fanoutTable[levelOne - 1] : 0;
+               return (int) (nthPosition - base);
+       }
+
+       @Override
+       public ObjectId getObjectId(final long nthPosition) {
+               final int levelOne = findLevelOne(nthPosition);
+               final int p = getLevelTwo(nthPosition, levelOne);
                final int p4 = p << 2;
                return ObjectId.fromRaw(names[levelOne], p4 + p); // p * 5
        }
 
+       @Override
+       public long getOffset(final long nthPosition) {
+               final int levelOne = findLevelOne(nthPosition);
+               final int levelTwo = getLevelTwo(nthPosition, levelOne);
+               return getOffset(levelOne, levelTwo);
+       }
+
        @Override
        public long findOffset(final AnyObjectId objId) {
                final int levelOne = objId.getFirstByte();
                final int levelTwo = binarySearchLevelTwo(objId, levelOne);
                if (levelTwo == -1)
                        return -1;
+               return getOffset(levelOne, levelTwo);
+       }
+
+       private long getOffset(final int levelOne, final int levelTwo) {
                final long p = NB.decodeUInt32(offset32[levelOne], levelTwo << 2);
                if ((p & IS_O64) != 0)
                        return NB.decodeUInt64(offset64, (8 * (int) (p & ~IS_O64)));