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 import java.util.Collections;
48 import java.util.Comparator;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.NoSuchElementException;
52
53 import org.eclipse.jgit.internal.JGitText;
54 import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
55 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
56 import org.eclipse.jgit.lib.AnyObjectId;
57 import org.eclipse.jgit.lib.BitmapIndex.Bitmap;
58 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
59 import org.eclipse.jgit.lib.Constants;
60 import org.eclipse.jgit.lib.ObjectId;
61 import org.eclipse.jgit.lib.ObjectIdOwnerMap;
62 import org.eclipse.jgit.util.BlockList;
63
64 import com.googlecode.javaewah.EWAHCompressedBitmap;
65
66
67
68
69
70 public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
71 private static final int MAX_XOR_OFFSET_SEARCH = 10;
72
73 private final EWAHCompressedBitmap commits;
74 private final EWAHCompressedBitmap trees;
75 private final EWAHCompressedBitmap blobs;
76 private final EWAHCompressedBitmap tags;
77 private final BlockList<PositionEntry> byOffset;
78 final BlockList<StoredBitmap>
79 byAddOrder = new BlockList<>();
80 final ObjectIdOwnerMap<PositionEntry>
81 positionEntries = new ObjectIdOwnerMap<>();
82
83
84
85
86
87
88
89
90
91 public PackBitmapIndexBuilder(List<ObjectToPack> objects) {
92 super(new ObjectIdOwnerMap<StoredBitmap>());
93 byOffset = new BlockList<>(objects.size());
94 sortByOffsetAndIndex(byOffset, positionEntries, objects);
95
96
97
98
99 int sizeInWords = Math.max(4, byOffset.size() / 64 / 3);
100 commits = new EWAHCompressedBitmap(sizeInWords);
101 trees = new EWAHCompressedBitmap(sizeInWords);
102 blobs = new EWAHCompressedBitmap(sizeInWords);
103 tags = new EWAHCompressedBitmap(sizeInWords);
104 for (int i = 0; i < objects.size(); i++) {
105 int type = objects.get(i).getType();
106 switch (type) {
107 case Constants.OBJ_COMMIT:
108 commits.set(i);
109 break;
110 case Constants.OBJ_TREE:
111 trees.set(i);
112 break;
113 case Constants.OBJ_BLOB:
114 blobs.set(i);
115 break;
116 case Constants.OBJ_TAG:
117 tags.set(i);
118 break;
119 default:
120 throw new IllegalArgumentException(MessageFormat.format(
121 JGitText.get().badObjectType, String.valueOf(type)));
122 }
123 }
124 commits.trim();
125 trees.trim();
126 blobs.trim();
127 tags.trim();
128 }
129
130 private static void sortByOffsetAndIndex(BlockList<PositionEntry> byOffset,
131 ObjectIdOwnerMap<PositionEntry> positionEntries,
132 List<ObjectToPack> entries) {
133 for (int i = 0; i < entries.size(); i++) {
134 positionEntries.add(new PositionEntry(entries.get(i), i));
135 }
136 Collections.sort(entries, new Comparator<ObjectToPack>() {
137 @Override
138 public int compare(ObjectToPack a, ObjectToPack b) {
139 return Long.signum(a.getOffset() - b.getOffset());
140 }
141 });
142 for (int i = 0; i < entries.size(); i++) {
143 PositionEntry e = positionEntries.get(entries.get(i));
144 e.offsetPosition = i;
145 byOffset.add(e);
146 }
147 }
148
149
150
151
152
153
154 public ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> getObjectSet() {
155 ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> r = new ObjectIdOwnerMap<>();
156 for (PositionEntry e : byOffset) {
157 r.add(new ObjectIdOwnerMap.Entry(e) {
158
159 });
160 }
161 return r;
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public void addBitmap(AnyObjectId objectId, Bitmap bitmap, int flags) {
175 if (bitmap instanceof BitmapBuilder)
176 bitmap = ((BitmapBuilder) bitmap).build();
177
178 EWAHCompressedBitmap compressed;
179 if (bitmap instanceof CompressedBitmap)
180 compressed = ((CompressedBitmap) bitmap).getEwahCompressedBitmap();
181 else
182 throw new IllegalArgumentException(bitmap.getClass().toString());
183
184 addBitmap(objectId, compressed, flags);
185 }
186
187
188
189
190
191
192
193
194
195
196
197 public void addBitmap(
198 AnyObjectId objectId, EWAHCompressedBitmap bitmap, int flags) {
199 bitmap.trim();
200 StoredBitmap result = new StoredBitmap(objectId, bitmap, null, flags);
201 getBitmaps().add(result);
202 byAddOrder.add(result);
203 }
204
205
206 @Override
207 public EWAHCompressedBitmap ofObjectType(
208 EWAHCompressedBitmap bitmap, int type) {
209 switch (type) {
210 case Constants.OBJ_BLOB:
211 return getBlobs().and(bitmap);
212 case Constants.OBJ_TREE:
213 return getTrees().and(bitmap);
214 case Constants.OBJ_COMMIT:
215 return getCommits().and(bitmap);
216 case Constants.OBJ_TAG:
217 return getTags().and(bitmap);
218 }
219 throw new IllegalArgumentException();
220 }
221
222
223 @Override
224 public int findPosition(AnyObjectId objectId) {
225 PositionEntry entry = positionEntries.get(objectId);
226 if (entry == null)
227 return -1;
228 return entry.offsetPosition;
229 }
230
231
232 @Override
233 public ObjectId getObject(int position) throws IllegalArgumentException {
234 ObjectId objectId = byOffset.get(position);
235 if (objectId == null)
236 throw new IllegalArgumentException();
237 return objectId;
238 }
239
240
241
242
243
244
245 public EWAHCompressedBitmap getCommits() {
246 return commits;
247 }
248
249
250
251
252
253
254 public EWAHCompressedBitmap getTrees() {
255 return trees;
256 }
257
258
259
260
261
262
263 public EWAHCompressedBitmap getBlobs() {
264 return blobs;
265 }
266
267
268
269
270
271
272 public EWAHCompressedBitmap getTags() {
273 return tags;
274 }
275
276
277
278
279
280
281 public int getOptions() {
282 return PackBitmapIndexV1.OPT_FULL;
283 }
284
285
286 @Override
287 public int getBitmapCount() {
288 return getBitmaps().size();
289 }
290
291
292
293
294 public void clearBitmaps() {
295 byAddOrder.clear();
296 getBitmaps().clear();
297 }
298
299
300 @Override
301 public int getObjectCount() {
302 return byOffset.size();
303 }
304
305
306
307
308
309
310 public Iterable<StoredEntry> getCompressedBitmaps() {
311
312
313 return new Iterable<StoredEntry>() {
314 @Override
315 public Iterator<StoredEntry> iterator() {
316 return new Iterator<StoredEntry>() {
317 private int index = byAddOrder.size() - 1;
318
319 @Override
320 public boolean hasNext() {
321 return index >= 0;
322 }
323
324 @Override
325 public StoredEntry next() {
326 if (!hasNext())
327 throw new NoSuchElementException();
328 StoredBitmap item = byAddOrder.get(index);
329 int bestXorOffset = 0;
330 EWAHCompressedBitmap bestBitmap = item.getBitmap();
331
332
333
334 for (int i = 1; i <= MAX_XOR_OFFSET_SEARCH; i++) {
335 int curr = i + index;
336 if (curr >= byAddOrder.size())
337 break;
338
339 StoredBitmap other = byAddOrder.get(curr);
340 EWAHCompressedBitmap bitmap = other.getBitmap()
341 .xor(item.getBitmap());
342
343 if (bitmap.sizeInBytes()
344 < bestBitmap.sizeInBytes()) {
345 bestBitmap = bitmap;
346 bestXorOffset = i;
347 }
348 }
349 index--;
350
351 PositionEntry entry = positionEntries.get(item);
352 if (entry == null)
353 throw new IllegalStateException();
354 return new StoredEntry(entry.namePosition, bestBitmap,
355 bestXorOffset, item.getFlags());
356 }
357
358 @Override
359 public void remove() {
360 throw new UnsupportedOperationException();
361 }
362 };
363 }
364 };
365 }
366
367
368 public static final class StoredEntry {
369 private final long objectId;
370 private final EWAHCompressedBitmap bitmap;
371 private final int xorOffset;
372 private final int flags;
373
374 StoredEntry(long objectId, EWAHCompressedBitmap bitmap,
375 int xorOffset, int flags) {
376 this.objectId = objectId;
377 this.bitmap = bitmap;
378 this.xorOffset = xorOffset;
379 this.flags = flags;
380 }
381
382
383 public EWAHCompressedBitmap getBitmap() {
384 return bitmap;
385 }
386
387
388 public int getXorOffset() {
389 return xorOffset;
390 }
391
392
393 public int getFlags() {
394 return flags;
395 }
396
397
398 public long getObjectId() {
399 return objectId;
400 }
401 }
402
403 private static final class PositionEntry extends ObjectIdOwnerMap.Entry {
404 final int namePosition;
405
406 int offsetPosition;
407
408 PositionEntry(AnyObjectId objectId, int namePosition) {
409 super(objectId);
410 this.namePosition = namePosition;
411 }
412 }
413 }