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