PackBitmapIndexRemapper.java

  1. /*
  2.  * Copyright (C) 2013, Google Inc.
  3.  * and other copyright owners as documented in the project's IP log.
  4.  *
  5.  * This program and the accompanying materials are made available
  6.  * under the terms of the Eclipse Distribution License v1.0 which
  7.  * accompanies this distribution, is reproduced below, and is
  8.  * available at http://www.eclipse.org/org/documents/edl-v10.php
  9.  *
  10.  * All rights reserved.
  11.  *
  12.  * Redistribution and use in source and binary forms, with or
  13.  * without modification, are permitted provided that the following
  14.  * conditions are met:
  15.  *
  16.  * - Redistributions of source code must retain the above copyright
  17.  *   notice, this list of conditions and the following disclaimer.
  18.  *
  19.  * - Redistributions in binary form must reproduce the above
  20.  *   copyright notice, this list of conditions and the following
  21.  *   disclaimer in the documentation and/or other materials provided
  22.  *   with the distribution.
  23.  *
  24.  * - Neither the name of the Eclipse Foundation, Inc. nor the
  25.  *   names of its contributors may be used to endorse or promote
  26.  *   products derived from this software without specific prior
  27.  *   written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  */

  43. package org.eclipse.jgit.internal.storage.file;

  44. import java.util.Collections;
  45. import java.util.Iterator;
  46. import java.util.NoSuchElementException;

  47. import org.eclipse.jgit.internal.storage.file.BasePackBitmapIndex.StoredBitmap;
  48. import org.eclipse.jgit.lib.AnyObjectId;
  49. import org.eclipse.jgit.lib.BitmapIndex;
  50. import org.eclipse.jgit.lib.ObjectId;
  51. import org.eclipse.jgit.lib.ObjectIdOwnerMap;

  52. import com.googlecode.javaewah.EWAHCompressedBitmap;
  53. import com.googlecode.javaewah.IntIterator;

  54. /**
  55.  * A PackBitmapIndex that remaps the bitmaps in the previous index to the
  56.  * positions in the new pack index. Note, unlike typical PackBitmapIndex
  57.  * implementations this implementation is not thread safe, as it is intended to
  58.  * be used with a PackBitmapIndexBuilder, which is also not thread safe.
  59.  */
  60. public class PackBitmapIndexRemapper extends PackBitmapIndex
  61.         implements Iterable<PackBitmapIndexRemapper.Entry> {

  62.     private final BasePackBitmapIndex oldPackIndex;
  63.     final PackBitmapIndex newPackIndex;
  64.     private final ObjectIdOwnerMap<StoredBitmap> convertedBitmaps;
  65.     private final BitSet inflated;
  66.     private final int[] prevToNewMapping;

  67.     /**
  68.      * A PackBitmapIndex that maps the positions in the prevBitmapIndex to the
  69.      * ones in the newIndex.
  70.      *
  71.      * @param prevBitmapIndex
  72.      *            the bitmap index with the old mapping.
  73.      * @param newIndex
  74.      *            the bitmap index with the new mapping.
  75.      * @return a bitmap index that attempts to do the mapping between the two.
  76.      */
  77.     public static PackBitmapIndexRemapper newPackBitmapIndex(
  78.             BitmapIndex prevBitmapIndex, PackBitmapIndex newIndex) {
  79.         if (!(prevBitmapIndex instanceof BitmapIndexImpl))
  80.             return new PackBitmapIndexRemapper(newIndex);

  81.         PackBitmapIndex prevIndex = ((BitmapIndexImpl) prevBitmapIndex)
  82.                 .getPackBitmapIndex();
  83.         if (!(prevIndex instanceof BasePackBitmapIndex))
  84.             return new PackBitmapIndexRemapper(newIndex);

  85.         return new PackBitmapIndexRemapper(
  86.                 (BasePackBitmapIndex) prevIndex, newIndex);
  87.     }

  88.     private PackBitmapIndexRemapper(PackBitmapIndex newPackIndex) {
  89.         this.oldPackIndex = null;
  90.         this.newPackIndex = newPackIndex;
  91.         this.convertedBitmaps = null;
  92.         this.inflated = null;
  93.         this.prevToNewMapping = null;
  94.     }

  95.     private PackBitmapIndexRemapper(
  96.             BasePackBitmapIndex oldPackIndex, PackBitmapIndex newPackIndex) {
  97.         this.oldPackIndex = oldPackIndex;
  98.         this.newPackIndex = newPackIndex;
  99.         convertedBitmaps = new ObjectIdOwnerMap<>();
  100.         inflated = new BitSet(newPackIndex.getObjectCount());

  101.         prevToNewMapping = new int[oldPackIndex.getObjectCount()];
  102.         for (int pos = 0; pos < prevToNewMapping.length; pos++)
  103.             prevToNewMapping[pos] = newPackIndex.findPosition(
  104.                     oldPackIndex.getObject(pos));
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     public int findPosition(AnyObjectId objectId) {
  109.         return newPackIndex.findPosition(objectId);
  110.     }

  111.     /** {@inheritDoc} */
  112.     @Override
  113.     public ObjectId getObject(int position) throws IllegalArgumentException {
  114.         return newPackIndex.getObject(position);
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public int getObjectCount() {
  119.         return newPackIndex.getObjectCount();
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public EWAHCompressedBitmap ofObjectType(
  124.             EWAHCompressedBitmap bitmap, int type) {
  125.         return newPackIndex.ofObjectType(bitmap, type);
  126.     }

  127.     /** {@inheritDoc} */
  128.     @Override
  129.     public Iterator<Entry> iterator() {
  130.         if (oldPackIndex == null)
  131.             return Collections.<Entry> emptyList().iterator();

  132.         final Iterator<StoredBitmap> it = oldPackIndex.getBitmaps().iterator();
  133.         return new Iterator<Entry>() {
  134.             private Entry entry;

  135.             @Override
  136.             public boolean hasNext() {
  137.                 while (entry == null && it.hasNext()) {
  138.                     StoredBitmap sb = it.next();
  139.                     if (newPackIndex.findPosition(sb) != -1)
  140.                         entry = new Entry(sb, sb.getFlags());
  141.                 }
  142.                 return entry != null;
  143.             }

  144.             @Override
  145.             public Entry next() {
  146.                 if (!hasNext())
  147.                     throw new NoSuchElementException();

  148.                 Entry res = entry;
  149.                 entry = null;
  150.                 return res;
  151.             }

  152.             @Override
  153.             public void remove() {
  154.                 throw new UnsupportedOperationException();
  155.             }
  156.         };
  157.     }

  158.     /** {@inheritDoc} */
  159.     @Override
  160.     public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
  161.         EWAHCompressedBitmap bitmap = newPackIndex.getBitmap(objectId);
  162.         if (bitmap != null || oldPackIndex == null)
  163.             return bitmap;

  164.         StoredBitmap stored = convertedBitmaps.get(objectId);
  165.         if (stored != null)
  166.             return stored.getBitmap();

  167.         StoredBitmap oldBitmap = oldPackIndex.getBitmaps().get(objectId);
  168.         if (oldBitmap == null)
  169.             return null;

  170.         if (newPackIndex.findPosition(objectId) == -1)
  171.             return null;

  172.         inflated.clear();
  173.         for (IntIterator i = oldBitmap.getBitmap().intIterator(); i.hasNext();)
  174.             inflated.set(prevToNewMapping[i.next()]);
  175.         bitmap = inflated.toEWAHCompressedBitmap();
  176.         bitmap.trim();
  177.         convertedBitmaps.add(
  178.                 new StoredBitmap(objectId, bitmap, null, oldBitmap.getFlags()));
  179.         return bitmap;
  180.     }

  181.     /** An entry in the old PackBitmapIndex. */
  182.     public static final class Entry extends ObjectId {
  183.         private final int flags;

  184.         Entry(AnyObjectId src, int flags) {
  185.             super(src);
  186.             this.flags = flags;
  187.         }

  188.         /** @return the flags associated with the bitmap. */
  189.         public int getFlags() {
  190.             return flags;
  191.         }
  192.     }

  193.     /** {@inheritDoc} */
  194.     @Override
  195.     public int getBitmapCount() {
  196.         // The count is only useful for the end index, not the remapper.
  197.         return 0;
  198.     }
  199. }