Package org.eclipse.jgit.internal.storage.file

Source Code of org.eclipse.jgit.internal.storage.file.BitmapIndexImpl$CompressedBitmap

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

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

import java.text.MessageFormat;
import java.util.Iterator;
import java.util.NoSuchElementException;

import javaewah.EWAHCompressedBitmap;
import javaewah.IntIterator;

import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.BitmapIndex;
import org.eclipse.jgit.lib.BitmapObject;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
import org.eclipse.jgit.util.BlockList;

/** A compressed bitmap representation of the entire object graph. */
public class BitmapIndexImpl implements BitmapIndex {
  private static final int EXTRA_BITS = 10 * 1024;

  private final PackBitmapIndex packIndex;

  private final MutableBitmapIndex mutableIndex;

  private final int indexObjectCount;

  /**
   * Creates a BitmapIndex that is back by Compressed bitmaps.
   *
   * @param packIndex
   *            the bitmap index for the pack.
   */
  public BitmapIndexImpl(PackBitmapIndex packIndex) {
    this.packIndex = packIndex;
    mutableIndex = new MutableBitmapIndex();
    indexObjectCount = packIndex.getObjectCount();
  }

  PackBitmapIndex getPackBitmapIndex() {
    return packIndex;
  }

  public CompressedBitmap getBitmap(AnyObjectId objectId) {
    EWAHCompressedBitmap compressed = packIndex.getBitmap(objectId);
    if (compressed == null)
      return null;
    return new CompressedBitmap(compressed);
  }

  public CompressedBitmapBuilder newBitmapBuilder() {
    return new CompressedBitmapBuilder();
  }

  private int findPosition(AnyObjectId objectId) {
    int position = packIndex.findPosition(objectId);
    if (position < 0) {
      position = mutableIndex.findPosition(objectId);
      if (position >= 0)
        position += indexObjectCount;
    }
    return position;
  }

  private int addObject(AnyObjectId objectId, int type) {
    int position = findPosition(objectId);
    if (position < 0) {
      position = mutableIndex.addObject(objectId, type);
      position += indexObjectCount;
    }
    return position;
  }

  private static final class ComboBitset {
    private InflatingBitSet inflatingBitmap;

    private BitSet toAdd;

    private BitSet toRemove;

    private ComboBitset() {
      this(new EWAHCompressedBitmap());
    }

    private ComboBitset(EWAHCompressedBitmap bitmap) {
      this.inflatingBitmap = new InflatingBitSet(bitmap);
    }

    EWAHCompressedBitmap combine() {
      EWAHCompressedBitmap toAddCompressed = null;
      if (toAdd != null) {
        toAddCompressed = toAdd.toEWAHCompressedBitmap();
        toAdd = null;
      }

      EWAHCompressedBitmap toRemoveCompressed = null;
      if (toRemove != null) {
        toRemoveCompressed = toRemove.toEWAHCompressedBitmap();
        toRemove = null;
      }

      if (toAddCompressed != null)
        or(toAddCompressed);
      if (toRemoveCompressed != null)
        andNot(toRemoveCompressed);
      return inflatingBitmap.getBitmap();
    }

    void or(EWAHCompressedBitmap inbits) {
      if (toRemove != null)
        combine();
      inflatingBitmap = inflatingBitmap.or(inbits);
    }

    void andNot(EWAHCompressedBitmap inbits) {
      if (toAdd != null || toRemove != null)
        combine();
      inflatingBitmap = inflatingBitmap.andNot(inbits);
    }

    void xor(EWAHCompressedBitmap inbits) {
      if (toAdd != null || toRemove != null)
        combine();
      inflatingBitmap = inflatingBitmap.xor(inbits);
    }

    boolean contains(int position) {
      if (toRemove != null && toRemove.get(position))
        return false;
      if (toAdd != null && toAdd.get(position))
        return true;
      return inflatingBitmap.contains(position);
    }

    void remove(int position) {
      if (toAdd != null)
        toAdd.clear(position);

      if (inflatingBitmap.maybeContains(position)) {
        if (toRemove == null)
          toRemove = new BitSet(position + EXTRA_BITS);
        toRemove.set(position);
      }
    }

    void set(int position) {
      if (toRemove != null)
        toRemove.clear(position);

      if (toAdd == null)
        toAdd = new BitSet(position + EXTRA_BITS);
      toAdd.set(position);
    }
  }

  private final class CompressedBitmapBuilder implements BitmapBuilder {
    private ComboBitset bitset = new ComboBitset();

    public boolean add(AnyObjectId objectId, int type) {
      int position = addObject(objectId, type);
      if (bitset.contains(position))
        return false;

      Bitmap entry = getBitmap(objectId);
      if (entry != null) {
        or(entry);
        return false;
      }

      bitset.set(position);
      return true;
    }

    public boolean contains(AnyObjectId objectId) {
      int position = findPosition(objectId);
      return 0 <= position && bitset.contains(position);
    }

    public void remove(AnyObjectId objectId) {
      int position = findPosition(objectId);
      if (0 <= position)
        bitset.remove(position);
    }

    public CompressedBitmapBuilder or(Bitmap other) {
      if (isSameCompressedBitmap(other)) {
        bitset.or(((CompressedBitmap) other).bitmap);
      } else if (isSameCompressedBitmapBuilder(other)) {
        CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
        bitset.or(b.bitset.combine());
      } else {
        throw new IllegalArgumentException();
      }
      return this;
    }

    public CompressedBitmapBuilder andNot(Bitmap other) {
      if (isSameCompressedBitmap(other)) {
        bitset.andNot(((CompressedBitmap) other).bitmap);
      } else if (isSameCompressedBitmapBuilder(other)) {
        CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
        bitset.andNot(b.bitset.combine());
      } else {
        throw new IllegalArgumentException();
      }
      return this;
    }

    public CompressedBitmapBuilder xor(Bitmap other) {
      if (isSameCompressedBitmap(other)) {
        bitset.xor(((CompressedBitmap) other).bitmap);
      } else if (isSameCompressedBitmapBuilder(other)) {
        CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
        bitset.xor(b.bitset.combine());
      } else {
        throw new IllegalArgumentException();
      }
      return this;
    }

    /** @return the fully built immutable bitmap */
    public CompressedBitmap build() {
      return new CompressedBitmap(bitset.combine());
    }

    public Iterator<BitmapObject> iterator() {
      return build().iterator();
    }

    public int cardinality() {
      return bitset.combine().cardinality();
    }

    public boolean removeAllOrNone(PackBitmapIndex index) {
      if (!packIndex.equals(index))
        return false;

      EWAHCompressedBitmap curr = bitset.combine()
          .xor(ones(indexObjectCount));

      IntIterator ii = curr.intIterator();
      if (ii.hasNext() && ii.next() < indexObjectCount)
        return false;
      bitset = new ComboBitset(curr);
      return true;
    }

    private BitmapIndexImpl getBitmapIndex() {
      return BitmapIndexImpl.this;
    }
  }

  final class CompressedBitmap implements Bitmap {
    private final EWAHCompressedBitmap bitmap;

    private CompressedBitmap(EWAHCompressedBitmap bitmap) {
      this.bitmap = bitmap;
    }

    public CompressedBitmap or(Bitmap other) {
      return new CompressedBitmap(bitmap.or(bitmapOf(other)));
    }

    public CompressedBitmap andNot(Bitmap other) {
      return new CompressedBitmap(bitmap.andNot(bitmapOf(other)));
    }

    public CompressedBitmap xor(Bitmap other) {
      return new CompressedBitmap(bitmap.xor(bitmapOf(other)));
    }

    private EWAHCompressedBitmap bitmapOf(Bitmap other) {
      if (isSameCompressedBitmap(other))
        return ((CompressedBitmap) other).bitmap;
      if (isSameCompressedBitmapBuilder(other))
        return ((CompressedBitmapBuilder) other).build().bitmap;
      CompressedBitmapBuilder builder = newBitmapBuilder();
      builder.or(other);
      return builder.build().bitmap;
    }

    private final IntIterator ofObjectType(int type) {
      return packIndex.ofObjectType(bitmap, type).intIterator();
    }

    public Iterator<BitmapObject> iterator() {
      final IntIterator dynamic = bitmap.andNot(ones(indexObjectCount))
          .intIterator();
      final IntIterator commits = ofObjectType(Constants.OBJ_COMMIT);
      final IntIterator trees = ofObjectType(Constants.OBJ_TREE);
      final IntIterator blobs = ofObjectType(Constants.OBJ_BLOB);
      final IntIterator tags = ofObjectType(Constants.OBJ_TAG);
      return new Iterator<BitmapObject>() {
        private final BitmapObjectImpl out = new BitmapObjectImpl();
        private int type;
        private IntIterator cached = dynamic;

        public boolean hasNext() {
          if (!cached.hasNext()) {
            if (commits.hasNext()) {
              type = Constants.OBJ_COMMIT;
              cached = commits;
            } else if (trees.hasNext()) {
              type = Constants.OBJ_TREE;
              cached = trees;
            } else if (blobs.hasNext()) {
              type = Constants.OBJ_BLOB;
              cached = blobs;
            } else if (tags.hasNext()) {
              type = Constants.OBJ_TAG;
              cached = tags;
            } else {
              return false;
            }
          }
          return true;
        }

        public BitmapObject next() {
          if (!hasNext())
            throw new NoSuchElementException();

          int position = cached.next();
          if (position < indexObjectCount) {
            out.type = type;
            out.objectId = packIndex.getObject(position);
          } else {
            position -= indexObjectCount;
            MutableEntry entry = mutableIndex.getObject(position);
            out.type = entry.type;
            out.objectId = entry;
          }
          return out;
        }

        public void remove() {
          throw new UnsupportedOperationException();
        }
      };
    }

    EWAHCompressedBitmap getEwahCompressedBitmap() {
      return bitmap;
    }

    private BitmapIndexImpl getPackBitmapIndex() {
      return BitmapIndexImpl.this;
    }
  }

  private static final class MutableBitmapIndex {
    private final ObjectIdOwnerMap<MutableEntry>
        revMap = new ObjectIdOwnerMap<MutableEntry>();

    private final BlockList<MutableEntry>
        revList = new BlockList<MutableEntry>();

    int findPosition(AnyObjectId objectId) {
      MutableEntry entry = revMap.get(objectId);
      if (entry == null)
        return -1;
      return entry.position;
    }

    MutableEntry getObject(int position) {
      try {
        MutableEntry entry = revList.get(position);
        if (entry == null)
          throw new IllegalArgumentException(MessageFormat.format(
              JGitText.get().objectNotFound,
              String.valueOf(position)));
        return entry;
      } catch (IndexOutOfBoundsException ex) {
        throw new IllegalArgumentException(ex);
      }
    }

    int addObject(AnyObjectId objectId, int type) {
      MutableEntry entry = new MutableEntry(
          objectId, type, revList.size());
      revList.add(entry);
      revMap.add(entry);
      return entry.position;
    }
  }

  private static final class MutableEntry extends ObjectIdOwnerMap.Entry {
    private final int type;

    private final int position;

    MutableEntry(AnyObjectId objectId, int type, int position) {
      super(objectId);
      this.type = type;
      this.position = position;
    }
  }

  private static final class BitmapObjectImpl extends BitmapObject {
    private ObjectId objectId;

    private int type;

    @Override
    public ObjectId getObjectId() {
      return objectId;
    }

    @Override
    public int getType() {
      return type;
    }
  }

  private boolean isSameCompressedBitmap(Bitmap other) {
    if (other instanceof CompressedBitmap) {
      CompressedBitmap b = (CompressedBitmap) other;
      return this == b.getPackBitmapIndex();
    }
    return false;
  }

  private boolean isSameCompressedBitmapBuilder(Bitmap other) {
    if (other instanceof CompressedBitmapBuilder) {
      CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
      return this == b.getBitmapIndex();
    }
    return false;
  }

  private static final EWAHCompressedBitmap ones(int sizeInBits) {
    EWAHCompressedBitmap mask = new EWAHCompressedBitmap();
    mask.addStreamOfEmptyWords(
        true, sizeInBits / EWAHCompressedBitmap.wordinbits);
    int remaining = sizeInBits % EWAHCompressedBitmap.wordinbits;
    if (remaining > 0)
      mask.add((1L << remaining) - 1, remaining);
    return mask;
  }
}
TOP

Related Classes of org.eclipse.jgit.internal.storage.file.BitmapIndexImpl$CompressedBitmap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.