1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import java.text.MessageFormat;
14
15 import org.eclipse.jgit.errors.CorruptObjectException;
16 import org.eclipse.jgit.internal.JGitText;
17 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
18 import org.eclipse.jgit.lib.ObjectId;
19
20
21
22
23
24
25
26
27
28
29
30 public class PackReverseIndex {
31
32 private final PackIndex index;
33
34
35 private final long bucketSize;
36
37
38
39
40
41
42
43
44
45
46 private final int[] offsetIndex;
47
48
49 private final int[] nth;
50
51
52
53
54
55
56
57
58 public PackReverseIndex(PackIndex packIndex) {
59 index = packIndex;
60
61 final long cnt = index.getObjectCount();
62 if (cnt + 1 > Integer.MAX_VALUE)
63 throw new IllegalArgumentException(
64 JGitText.get().hugeIndexesAreNotSupportedByJgitYet);
65
66 if (cnt == 0) {
67 bucketSize = Long.MAX_VALUE;
68 offsetIndex = new int[1];
69 nth = new int[0];
70 return;
71 }
72
73 final long[] offsetsBySha1 = new long[(int) cnt];
74
75 long maxOffset = 0;
76 int ith = 0;
77 for (MutableEntry me : index) {
78 final long o = me.getOffset();
79 offsetsBySha1[ith++] = o;
80 if (o > maxOffset)
81 maxOffset = o;
82 }
83
84 bucketSize = maxOffset / cnt + 1;
85 int[] bucketIndex = new int[(int) cnt];
86 int[] bucketValues = new int[(int) cnt + 1];
87 for (int oi = 0; oi < offsetsBySha1.length; oi++) {
88 final long o = offsetsBySha1[oi];
89 final int bucket = (int) (o / bucketSize);
90 final int bucketValuesPos = oi + 1;
91 final int current = bucketIndex[bucket];
92 bucketIndex[bucket] = bucketValuesPos;
93 bucketValues[bucketValuesPos] = current;
94 }
95
96 int nthByOffset = 0;
97 nth = new int[offsetsBySha1.length];
98 offsetIndex = bucketIndex;
99 for (int bi = 0; bi < bucketIndex.length; bi++) {
100 final int start = nthByOffset;
101
102 for (int vi = bucketIndex[bi]; vi > 0; vi = bucketValues[vi]) {
103 final int nthBySha1 = vi - 1;
104 final long o = offsetsBySha1[nthBySha1];
105 int insertion = nthByOffset++;
106 for (; start < insertion; insertion--) {
107 if (o > offsetsBySha1[nth[insertion - 1]])
108 break;
109 nth[insertion] = nth[insertion - 1];
110 }
111 nth[insertion] = nthBySha1;
112 }
113 offsetIndex[bi] = nthByOffset;
114 }
115 }
116
117
118
119
120
121
122
123
124
125 public ObjectId findObject(long offset) {
126 final int ith = binarySearch(offset);
127 if (ith < 0)
128 return null;
129 return index.getObjectId(nth[ith]);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 public long findNextOffset(long offset, long maxOffset)
148 throws CorruptObjectException {
149 final int ith = binarySearch(offset);
150 if (ith < 0)
151 throw new CorruptObjectException(
152 MessageFormat.format(
153 JGitText.get().cantFindObjectInReversePackIndexForTheSpecifiedOffset,
154 Long.valueOf(offset)));
155
156 if (ith + 1 == nth.length)
157 return maxOffset;
158 return index.getOffset(nth[ith + 1]);
159 }
160
161 int findPostion(long offset) {
162 return binarySearch(offset);
163 }
164
165 private int binarySearch(long offset) {
166 int bucket = (int) (offset / bucketSize);
167 int low = bucket == 0 ? 0 : offsetIndex[bucket - 1];
168 int high = offsetIndex[bucket];
169 while (low < high) {
170 final int mid = (low + high) >>> 1;
171 final long o = index.getOffset(nth[mid]);
172 if (offset < o)
173 high = mid;
174 else if (offset == o)
175 return mid;
176 else
177 low = mid + 1;
178 }
179 return -1;
180 }
181
182 ObjectId findObjectByPosition(int nthPosition) {
183 return index.getObjectId(nth[nthPosition]);
184 }
185 }