帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

348 lines
10 KiB

/*
* 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 com.fr.third.eclipse.jgit.internal.storage.file;
import com.fr.third.eclipse.jgit.internal.JGitText;
import com.fr.third.eclipse.jgit.internal.storage.pack.ObjectToPack;
import com.fr.third.eclipse.jgit.lib.AnyObjectId;
import com.fr.third.eclipse.jgit.lib.Constants;
import com.fr.third.eclipse.jgit.lib.ObjectId;
import com.fr.third.eclipse.jgit.lib.ObjectIdOwnerMap;
import com.fr.third.eclipse.jgit.util.BlockList;
import com.fr.third.googlecode.javaewah.EWAHCompressedBitmap;
import com.fr.third.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
import com.fr.third.eclipse.jgit.lib.BitmapIndex.Bitmap;
import com.fr.third.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
* Helper for constructing {@link PackBitmapIndex}es.
*/
public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
private static final int MAX_XOR_OFFSET_SEARCH = 10;
private final EWAHCompressedBitmap commits;
private final EWAHCompressedBitmap trees;
private final EWAHCompressedBitmap blobs;
private final EWAHCompressedBitmap tags;
private final ObjectToPack[] byOffset;
private final BlockList<StoredBitmap>
byAddOrder = new BlockList<StoredBitmap>();
private final ObjectIdOwnerMap<PositionEntry>
positionEntries = new ObjectIdOwnerMap<PositionEntry>();
/**
* Creates a PackBitmapIndex used for building the contents of an index
* file.
*
* @param byName
* objects sorted by name.
*/
public PackBitmapIndexBuilder(List<ObjectToPack> byName) {
super(new ObjectIdOwnerMap<StoredBitmap>());
byOffset = sortByOffset(byName);
int sizeInWords = Math.max(byOffset.length / 64, 4);
commits = new EWAHCompressedBitmap(sizeInWords);
trees = new EWAHCompressedBitmap(sizeInWords);
blobs = new EWAHCompressedBitmap(sizeInWords);
tags = new EWAHCompressedBitmap(sizeInWords);
for (int i = 0; i < byOffset.length; i++) {
int type = byOffset[i].getType();
switch (type) {
case Constants.OBJ_COMMIT:
commits.set(i);
break;
case Constants.OBJ_TREE:
trees.set(i);
break;
case Constants.OBJ_BLOB:
blobs.set(i);
break;
case Constants.OBJ_TAG:
tags.set(i);
break;
default:
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().badObjectType, String.valueOf(type)));
}
}
}
private ObjectToPack[] sortByOffset(List<ObjectToPack> entries) {
ObjectToPack[] result = new ObjectToPack[entries.size()];
for (int i = 0; i < result.length; i++) {
result[i] = entries.get(i);
positionEntries.add(new PositionEntry(result[i], i));
}
Arrays.sort(result, new Comparator<ObjectToPack>() {
public int compare(ObjectToPack a, ObjectToPack b) {
return Long.signum(a.getOffset() - b.getOffset());
}
});
for (int i = 0; i < result.length; i++)
positionEntries.get(result[i]).offsetPosition = i;
return result;
}
/**
* Stores the bitmap for the objectId.
*
* @param objectId
* the object id key for the bitmap.
* @param bitmap
* the bitmap
* @param flags
* the flags to be stored with the bitmap
*/
public void addBitmap(AnyObjectId objectId, Bitmap bitmap, int flags) {
if (bitmap instanceof BitmapBuilder)
bitmap = ((BitmapBuilder) bitmap).build();
EWAHCompressedBitmap compressed;
if (bitmap instanceof CompressedBitmap)
compressed = ((CompressedBitmap) bitmap).getEwahCompressedBitmap();
else
throw new IllegalArgumentException(bitmap.getClass().toString());
addBitmap(objectId, compressed, flags);
}
/**
* Stores the bitmap for the objectId.
*
* @param objectId
* the object id key for the bitmap.
* @param bitmap
* the bitmap
* @param flags
* the flags to be stored with the bitmap
*/
public void addBitmap(
AnyObjectId objectId, EWAHCompressedBitmap bitmap, int flags) {
StoredBitmap result = new StoredBitmap(objectId, bitmap, null, flags);
getBitmaps().add(result);
byAddOrder.add(result);
}
@Override
public EWAHCompressedBitmap ofObjectType(
EWAHCompressedBitmap bitmap, int type) {
switch (type) {
case Constants.OBJ_BLOB:
return getBlobs().and(bitmap);
case Constants.OBJ_TREE:
return getTrees().and(bitmap);
case Constants.OBJ_COMMIT:
return getCommits().and(bitmap);
case Constants.OBJ_TAG:
return getTags().and(bitmap);
}
throw new IllegalArgumentException();
}
@Override
public int findPosition(AnyObjectId objectId) {
PositionEntry entry = positionEntries.get(objectId);
if (entry == null)
return -1;
return entry.offsetPosition;
}
@Override
public ObjectId getObject(int position) throws IllegalArgumentException {
ObjectId objectId = byOffset[position];
if (objectId == null)
throw new IllegalArgumentException();
return objectId;
}
/** @return the commit object bitmap. */
public EWAHCompressedBitmap getCommits() {
return commits;
}
/** @return the tree object bitmap. */
public EWAHCompressedBitmap getTrees() {
return trees;
}
/** @return the blob object bitmap. */
public EWAHCompressedBitmap getBlobs() {
return blobs;
}
/** @return the tag object bitmap. */
public EWAHCompressedBitmap getTags() {
return tags;
}
/** @return the index storage options. */
public int getOptions() {
return PackBitmapIndexV1.OPT_FULL;
}
/** @return the number of bitmaps. */
public int getBitmapCount() {
return getBitmaps().size();
}
/** Removes all the bitmaps entries added. */
public void clearBitmaps() {
byAddOrder.clear();
getBitmaps().clear();
}
@Override
public int getObjectCount() {
return byOffset.length;
}
/** @return an iterator over the xor compressed entries. */
public Iterable<StoredEntry> getCompressedBitmaps() {
// Add order is from oldest to newest. The reverse add order is the
// output order.
return new Iterable<StoredEntry>() {
public Iterator<StoredEntry> iterator() {
return new Iterator<StoredEntry>() {
private int index = byAddOrder.size() - 1;
public boolean hasNext() {
return index >= 0;
}
public StoredEntry next() {
if (!hasNext())
throw new NoSuchElementException();
StoredBitmap item = byAddOrder.get(index);
int bestXorOffset = 0;
EWAHCompressedBitmap bestBitmap = item.getBitmap();
// Attempt to compress the bitmap with an XOR of the
// previously written entries.
for (int i = 1; i <= MAX_XOR_OFFSET_SEARCH; i++) {
int curr = i + index;
if (curr >= byAddOrder.size())
break;
StoredBitmap other = byAddOrder.get(curr);
EWAHCompressedBitmap bitmap = other.getBitmap()
.xor(item.getBitmap());
if (bitmap.sizeInBytes()
< bestBitmap.sizeInBytes()) {
bestBitmap = bitmap;
bestXorOffset = i;
}
}
index--;
PositionEntry entry = positionEntries.get(item);
if (entry == null)
throw new IllegalStateException();
return new StoredEntry(entry.namePosition, bestBitmap,
bestXorOffset, item.getFlags());
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
/** Data object for the on disk representation of a bitmap entry. */
public static final class StoredEntry {
private final long objectId;
private final EWAHCompressedBitmap bitmap;
private final int xorOffset;
private final int flags;
private StoredEntry(long objectId, EWAHCompressedBitmap bitmap,
int xorOffset, int flags) {
this.objectId = objectId;
this.bitmap = bitmap;
this.xorOffset = xorOffset;
this.flags = flags;
}
/** @return the bitmap */
public EWAHCompressedBitmap getBitmap() {
return bitmap;
}
/** @return the xorOffset */
public int getXorOffset() {
return xorOffset;
}
/** @return the flags */
public int getFlags() {
return flags;
}
/** @return the ObjectId */
public long getObjectId() {
return objectId;
}
}
private static final class PositionEntry extends ObjectIdOwnerMap.Entry {
private final int namePosition;
private int offsetPosition;
private PositionEntry(AnyObjectId objectId, int namePosition) {
super(objectId);
this.namePosition = namePosition;
}
}
}