Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

BitmapIndexImpl.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * Copyright (C) 2012, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.storage.file;
  11. import java.text.MessageFormat;
  12. import java.util.Iterator;
  13. import java.util.NoSuchElementException;
  14. import org.eclipse.jgit.internal.JGitText;
  15. import org.eclipse.jgit.lib.AnyObjectId;
  16. import org.eclipse.jgit.lib.BitmapIndex;
  17. import org.eclipse.jgit.lib.BitmapObject;
  18. import org.eclipse.jgit.lib.Constants;
  19. import org.eclipse.jgit.lib.ObjectId;
  20. import org.eclipse.jgit.lib.ObjectIdOwnerMap;
  21. import org.eclipse.jgit.util.BlockList;
  22. import com.googlecode.javaewah.EWAHCompressedBitmap;
  23. import com.googlecode.javaewah.IntIterator;
  24. /**
  25. * A compressed bitmap representation of the entire object graph.
  26. */
  27. public class BitmapIndexImpl implements BitmapIndex {
  28. private static final int EXTRA_BITS = 10 * 1024;
  29. final PackBitmapIndex packIndex;
  30. final MutableBitmapIndex mutableIndex;
  31. final int indexObjectCount;
  32. /**
  33. * Creates a BitmapIndex that is back by Compressed bitmaps.
  34. *
  35. * @param packIndex
  36. * the bitmap index for the pack.
  37. */
  38. public BitmapIndexImpl(PackBitmapIndex packIndex) {
  39. this.packIndex = packIndex;
  40. mutableIndex = new MutableBitmapIndex();
  41. indexObjectCount = packIndex.getObjectCount();
  42. }
  43. PackBitmapIndex getPackBitmapIndex() {
  44. return packIndex;
  45. }
  46. /** {@inheritDoc} */
  47. @Override
  48. public CompressedBitmap getBitmap(AnyObjectId objectId) {
  49. EWAHCompressedBitmap compressed = packIndex.getBitmap(objectId);
  50. if (compressed == null)
  51. return null;
  52. return new CompressedBitmap(compressed, this);
  53. }
  54. /** {@inheritDoc} */
  55. @Override
  56. public CompressedBitmapBuilder newBitmapBuilder() {
  57. return new CompressedBitmapBuilder(this);
  58. }
  59. int findPosition(AnyObjectId objectId) {
  60. int position = packIndex.findPosition(objectId);
  61. if (position < 0) {
  62. position = mutableIndex.findPosition(objectId);
  63. if (position >= 0)
  64. position += indexObjectCount;
  65. }
  66. return position;
  67. }
  68. int findOrInsert(AnyObjectId objectId, int type) {
  69. int position = findPosition(objectId);
  70. if (position < 0) {
  71. position = mutableIndex.findOrInsert(objectId, type);
  72. position += indexObjectCount;
  73. }
  74. return position;
  75. }
  76. private static final class ComboBitset {
  77. private InflatingBitSet inflatingBitmap;
  78. private BitSet toAdd;
  79. private BitSet toRemove;
  80. ComboBitset() {
  81. this(new EWAHCompressedBitmap());
  82. }
  83. ComboBitset(EWAHCompressedBitmap bitmap) {
  84. this.inflatingBitmap = new InflatingBitSet(bitmap);
  85. }
  86. EWAHCompressedBitmap combine() {
  87. EWAHCompressedBitmap toAddCompressed = null;
  88. if (toAdd != null) {
  89. toAddCompressed = toAdd.toEWAHCompressedBitmap();
  90. toAdd = null;
  91. }
  92. EWAHCompressedBitmap toRemoveCompressed = null;
  93. if (toRemove != null) {
  94. toRemoveCompressed = toRemove.toEWAHCompressedBitmap();
  95. toRemove = null;
  96. }
  97. if (toAddCompressed != null)
  98. or(toAddCompressed);
  99. if (toRemoveCompressed != null)
  100. andNot(toRemoveCompressed);
  101. return inflatingBitmap.getBitmap();
  102. }
  103. void or(EWAHCompressedBitmap inbits) {
  104. if (toRemove != null)
  105. combine();
  106. inflatingBitmap = inflatingBitmap.or(inbits);
  107. }
  108. void andNot(EWAHCompressedBitmap inbits) {
  109. if (toAdd != null || toRemove != null)
  110. combine();
  111. inflatingBitmap = inflatingBitmap.andNot(inbits);
  112. }
  113. void xor(EWAHCompressedBitmap inbits) {
  114. if (toAdd != null || toRemove != null)
  115. combine();
  116. inflatingBitmap = inflatingBitmap.xor(inbits);
  117. }
  118. boolean contains(int position) {
  119. if (toRemove != null && toRemove.get(position))
  120. return false;
  121. if (toAdd != null && toAdd.get(position))
  122. return true;
  123. return inflatingBitmap.contains(position);
  124. }
  125. void remove(int position) {
  126. if (toAdd != null)
  127. toAdd.clear(position);
  128. if (inflatingBitmap.maybeContains(position)) {
  129. if (toRemove == null)
  130. toRemove = new BitSet(position + EXTRA_BITS);
  131. toRemove.set(position);
  132. }
  133. }
  134. void set(int position) {
  135. if (toRemove != null)
  136. toRemove.clear(position);
  137. if (toAdd == null)
  138. toAdd = new BitSet(position + EXTRA_BITS);
  139. toAdd.set(position);
  140. }
  141. }
  142. private static final class CompressedBitmapBuilder implements BitmapBuilder {
  143. private ComboBitset bitset;
  144. private final BitmapIndexImpl bitmapIndex;
  145. CompressedBitmapBuilder(BitmapIndexImpl bitmapIndex) {
  146. this.bitset = new ComboBitset();
  147. this.bitmapIndex = bitmapIndex;
  148. }
  149. @Override
  150. public boolean contains(AnyObjectId objectId) {
  151. int position = bitmapIndex.findPosition(objectId);
  152. return 0 <= position && bitset.contains(position);
  153. }
  154. @Override
  155. public BitmapBuilder addObject(AnyObjectId objectId, int type) {
  156. bitset.set(bitmapIndex.findOrInsert(objectId, type));
  157. return this;
  158. }
  159. @Override
  160. public void remove(AnyObjectId objectId) {
  161. int position = bitmapIndex.findPosition(objectId);
  162. if (0 <= position)
  163. bitset.remove(position);
  164. }
  165. @Override
  166. public CompressedBitmapBuilder or(Bitmap other) {
  167. bitset.or(ewahBitmap(other));
  168. return this;
  169. }
  170. @Override
  171. public CompressedBitmapBuilder andNot(Bitmap other) {
  172. bitset.andNot(ewahBitmap(other));
  173. return this;
  174. }
  175. @Override
  176. public CompressedBitmapBuilder xor(Bitmap other) {
  177. bitset.xor(ewahBitmap(other));
  178. return this;
  179. }
  180. /** @return the fully built immutable bitmap */
  181. @Override
  182. public CompressedBitmap build() {
  183. return new CompressedBitmap(bitset.combine(), bitmapIndex);
  184. }
  185. @Override
  186. public Iterator<BitmapObject> iterator() {
  187. return build().iterator();
  188. }
  189. @Override
  190. public int cardinality() {
  191. return bitset.combine().cardinality();
  192. }
  193. @Override
  194. public boolean removeAllOrNone(PackBitmapIndex index) {
  195. if (!bitmapIndex.packIndex.equals(index))
  196. return false;
  197. EWAHCompressedBitmap curr = bitset.combine()
  198. .xor(ones(bitmapIndex.indexObjectCount));
  199. IntIterator ii = curr.intIterator();
  200. if (ii.hasNext() && ii.next() < bitmapIndex.indexObjectCount)
  201. return false;
  202. bitset = new ComboBitset(curr);
  203. return true;
  204. }
  205. @Override
  206. public BitmapIndexImpl getBitmapIndex() {
  207. return bitmapIndex;
  208. }
  209. @Override
  210. public EWAHCompressedBitmap retrieveCompressed() {
  211. return build().retrieveCompressed();
  212. }
  213. private EWAHCompressedBitmap ewahBitmap(Bitmap other) {
  214. if (other instanceof CompressedBitmap) {
  215. CompressedBitmap b = (CompressedBitmap) other;
  216. if (b.bitmapIndex != bitmapIndex) {
  217. throw new IllegalArgumentException();
  218. }
  219. return b.bitmap;
  220. }
  221. if (other instanceof CompressedBitmapBuilder) {
  222. CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
  223. if (b.bitmapIndex != bitmapIndex) {
  224. throw new IllegalArgumentException();
  225. }
  226. return b.bitset.combine();
  227. }
  228. throw new IllegalArgumentException();
  229. }
  230. }
  231. /**
  232. * Wrapper for a {@link EWAHCompressedBitmap} and {@link PackBitmapIndex}.
  233. * <p>
  234. * For a EWAHCompressedBitmap {@code bitmap} representing a vector of
  235. * bits, {@code new CompressedBitmap(bitmap, bitmapIndex)} represents the
  236. * objects at those positions in {@code bitmapIndex.packIndex}.
  237. */
  238. public static final class CompressedBitmap implements Bitmap {
  239. final EWAHCompressedBitmap bitmap;
  240. final BitmapIndexImpl bitmapIndex;
  241. /**
  242. * Construct compressed bitmap for given bitmap and bitmap index
  243. *
  244. * @param bitmap
  245. * @param bitmapIndex
  246. */
  247. public CompressedBitmap(EWAHCompressedBitmap bitmap, BitmapIndexImpl bitmapIndex) {
  248. this.bitmap = bitmap;
  249. this.bitmapIndex = bitmapIndex;
  250. }
  251. @Override
  252. public CompressedBitmap or(Bitmap other) {
  253. return new CompressedBitmap(bitmap.or(ewahBitmap(other)), bitmapIndex);
  254. }
  255. @Override
  256. public CompressedBitmap andNot(Bitmap other) {
  257. return new CompressedBitmap(bitmap.andNot(ewahBitmap(other)), bitmapIndex);
  258. }
  259. @Override
  260. public CompressedBitmap xor(Bitmap other) {
  261. return new CompressedBitmap(bitmap.xor(ewahBitmap(other)), bitmapIndex);
  262. }
  263. private final IntIterator ofObjectType(int type) {
  264. return bitmapIndex.packIndex.ofObjectType(bitmap, type).intIterator();
  265. }
  266. @Override
  267. public Iterator<BitmapObject> iterator() {
  268. final IntIterator dynamic = bitmap.andNot(ones(bitmapIndex.indexObjectCount))
  269. .intIterator();
  270. final IntIterator commits = ofObjectType(Constants.OBJ_COMMIT);
  271. final IntIterator trees = ofObjectType(Constants.OBJ_TREE);
  272. final IntIterator blobs = ofObjectType(Constants.OBJ_BLOB);
  273. final IntIterator tags = ofObjectType(Constants.OBJ_TAG);
  274. return new Iterator<BitmapObject>() {
  275. private final BitmapObjectImpl out = new BitmapObjectImpl();
  276. private int type;
  277. private IntIterator cached = dynamic;
  278. @Override
  279. public boolean hasNext() {
  280. if (!cached.hasNext()) {
  281. if (commits.hasNext()) {
  282. type = Constants.OBJ_COMMIT;
  283. cached = commits;
  284. } else if (trees.hasNext()) {
  285. type = Constants.OBJ_TREE;
  286. cached = trees;
  287. } else if (blobs.hasNext()) {
  288. type = Constants.OBJ_BLOB;
  289. cached = blobs;
  290. } else if (tags.hasNext()) {
  291. type = Constants.OBJ_TAG;
  292. cached = tags;
  293. } else {
  294. return false;
  295. }
  296. }
  297. return true;
  298. }
  299. @Override
  300. public BitmapObject next() {
  301. if (!hasNext())
  302. throw new NoSuchElementException();
  303. int position = cached.next();
  304. if (position < bitmapIndex.indexObjectCount) {
  305. out.type = type;
  306. out.objectId = bitmapIndex.packIndex.getObject(position);
  307. } else {
  308. position -= bitmapIndex.indexObjectCount;
  309. MutableEntry entry = bitmapIndex.mutableIndex.getObject(position);
  310. out.type = entry.type;
  311. out.objectId = entry;
  312. }
  313. return out;
  314. }
  315. @Override
  316. public void remove() {
  317. throw new UnsupportedOperationException();
  318. }
  319. };
  320. }
  321. @Override
  322. public EWAHCompressedBitmap retrieveCompressed() {
  323. return bitmap;
  324. }
  325. private EWAHCompressedBitmap ewahBitmap(Bitmap other) {
  326. if (other instanceof CompressedBitmap) {
  327. CompressedBitmap b = (CompressedBitmap) other;
  328. if (b.bitmapIndex != bitmapIndex) {
  329. throw new IllegalArgumentException();
  330. }
  331. return b.bitmap;
  332. }
  333. if (other instanceof CompressedBitmapBuilder) {
  334. CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
  335. if (b.bitmapIndex != bitmapIndex) {
  336. throw new IllegalArgumentException();
  337. }
  338. return b.bitset.combine();
  339. }
  340. throw new IllegalArgumentException();
  341. }
  342. }
  343. private static final class MutableBitmapIndex {
  344. private final ObjectIdOwnerMap<MutableEntry>
  345. revMap = new ObjectIdOwnerMap<>();
  346. private final BlockList<MutableEntry>
  347. revList = new BlockList<>();
  348. int findPosition(AnyObjectId objectId) {
  349. MutableEntry entry = revMap.get(objectId);
  350. if (entry == null)
  351. return -1;
  352. return entry.position;
  353. }
  354. MutableEntry getObject(int position) {
  355. try {
  356. MutableEntry entry = revList.get(position);
  357. if (entry == null)
  358. throw new IllegalArgumentException(MessageFormat.format(
  359. JGitText.get().objectNotFound,
  360. String.valueOf(position)));
  361. return entry;
  362. } catch (IndexOutOfBoundsException ex) {
  363. throw new IllegalArgumentException(ex);
  364. }
  365. }
  366. int findOrInsert(AnyObjectId objectId, int type) {
  367. MutableEntry entry = new MutableEntry(
  368. objectId, type, revList.size());
  369. revList.add(entry);
  370. revMap.add(entry);
  371. return entry.position;
  372. }
  373. }
  374. private static final class MutableEntry extends ObjectIdOwnerMap.Entry {
  375. final int type;
  376. final int position;
  377. MutableEntry(AnyObjectId objectId, int type, int position) {
  378. super(objectId);
  379. this.type = type;
  380. this.position = position;
  381. }
  382. }
  383. private static final class BitmapObjectImpl extends BitmapObject {
  384. private ObjectId objectId;
  385. private int type;
  386. @Override
  387. public ObjectId getObjectId() {
  388. return objectId;
  389. }
  390. @Override
  391. public int getType() {
  392. return type;
  393. }
  394. }
  395. static final EWAHCompressedBitmap ones(int sizeInBits) {
  396. EWAHCompressedBitmap mask = new EWAHCompressedBitmap();
  397. mask.addStreamOfEmptyWords(
  398. true, sizeInBits / EWAHCompressedBitmap.WORD_IN_BITS);
  399. int remaining = sizeInBits % EWAHCompressedBitmap.WORD_IN_BITS;
  400. if (remaining > 0)
  401. mask.addWord((1L << remaining) - 1, remaining);
  402. return mask;
  403. }
  404. }