/* * Copyright (C) 2013, Google Inc. and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.internal.storage.file; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import org.eclipse.jgit.internal.storage.file.BasePackBitmapIndex.StoredBitmap; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.ObjectId; import com.googlecode.javaewah.EWAHCompressedBitmap; import com.googlecode.javaewah.IntIterator; /** * A PackBitmapIndex that remaps the bitmaps in the previous index to the * positions in the new pack index. Note, unlike typical PackBitmapIndex * implementations this implementation is not thread safe, as it is intended to * be used with a PackBitmapIndexBuilder, which is also not thread safe. */ public class PackBitmapIndexRemapper implements PackBitmapIndex, Iterable { private final BasePackBitmapIndex oldPackIndex; final PackBitmapIndex newPackIndex; private final BitSet inflated; private final int[] prevToNewMapping; /** * A PackBitmapIndex that maps the positions in the prevBitmapIndex to the * ones in the newIndex. * * @param prevBitmapIndex * the bitmap index with the old mapping. * @param newIndex * the bitmap index with the new mapping. * @return a bitmap index that attempts to do the mapping between the two. */ public static PackBitmapIndexRemapper newPackBitmapIndex( BitmapIndex prevBitmapIndex, PackBitmapIndex newIndex) { if (!(prevBitmapIndex instanceof BitmapIndexImpl)) return new PackBitmapIndexRemapper(newIndex); PackBitmapIndex prevIndex = ((BitmapIndexImpl) prevBitmapIndex) .getPackBitmapIndex(); if (!(prevIndex instanceof BasePackBitmapIndex)) return new PackBitmapIndexRemapper(newIndex); return new PackBitmapIndexRemapper( (BasePackBitmapIndex) prevIndex, newIndex); } private PackBitmapIndexRemapper(PackBitmapIndex newPackIndex) { this.oldPackIndex = null; this.newPackIndex = newPackIndex; this.inflated = null; this.prevToNewMapping = null; } private PackBitmapIndexRemapper( BasePackBitmapIndex oldPackIndex, PackBitmapIndex newPackIndex) { this.oldPackIndex = oldPackIndex; this.newPackIndex = newPackIndex; inflated = new BitSet(newPackIndex.getObjectCount()); prevToNewMapping = new int[oldPackIndex.getObjectCount()]; for (int pos = 0; pos < prevToNewMapping.length; pos++) prevToNewMapping[pos] = newPackIndex.findPosition( oldPackIndex.getObject(pos)); } @Override public int findPosition(AnyObjectId objectId) { return newPackIndex.findPosition(objectId); } @Override public ObjectId getObject(int position) throws IllegalArgumentException { return newPackIndex.getObject(position); } @Override public int getObjectCount() { return newPackIndex.getObjectCount(); } @Override public int getBaseBitmapCount() { return newPackIndex.getBaseBitmapCount(); } @Override public long getBaseBitmapSizeInBytes() { return newPackIndex.getBaseBitmapSizeInBytes(); } @Override public int getXorBitmapCount() { return newPackIndex.getXorBitmapCount(); } @Override public long getXorBitmapSizeInBytes() { return newPackIndex.getXorBitmapSizeInBytes(); } @Override public EWAHCompressedBitmap ofObjectType( EWAHCompressedBitmap bitmap, int type) { return newPackIndex.ofObjectType(bitmap, type); } @Override public Iterator iterator() { if (oldPackIndex == null) return Collections. emptyList().iterator(); final Iterator it = oldPackIndex.getBitmaps().iterator(); return new Iterator<>() { private Entry entry; @Override public boolean hasNext() { while (entry == null && it.hasNext()) { StoredBitmap sb = it.next(); if (newPackIndex.findPosition(sb) != -1) entry = new Entry(sb, sb.getFlags()); } return entry != null; } @Override public Entry next() { if (!hasNext()) throw new NoSuchElementException(); Entry res = entry; entry = null; return res; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) { EWAHCompressedBitmap bitmap = newPackIndex.getBitmap(objectId); if (bitmap != null || oldPackIndex == null) return bitmap; StoredBitmap oldBitmap = oldPackIndex.getBitmaps().get(objectId); if (oldBitmap == null) return null; if (newPackIndex.findPosition(objectId) == -1) return null; inflated.clear(); for (IntIterator i = oldBitmap.getBitmapWithoutCaching() .intIterator(); i.hasNext();) inflated.set(prevToNewMapping[i.next()]); bitmap = inflated.toEWAHCompressedBitmap(); bitmap.trim(); return bitmap; } /** An entry in the old PackBitmapIndex. */ public static final class Entry extends ObjectId { private final int flags; Entry(AnyObjectId src, int flags) { super(src); this.flags = flags; } /** * Get flags * * @return the flags associated with the bitmap. */ public int getFlags() { return flags; } } @Override public int getBitmapCount() { // The count is only useful for the end index, not the remapper. return 0; } }