View Javadoc
1   /*
2    * Copyright (C) 2013, 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  
11  package org.eclipse.jgit.internal.storage.file;
12  
13  import java.util.Collections;
14  import java.util.Iterator;
15  import java.util.NoSuchElementException;
16  
17  import org.eclipse.jgit.internal.storage.file.BasePackBitmapIndex.StoredBitmap;
18  import org.eclipse.jgit.lib.AnyObjectId;
19  import org.eclipse.jgit.lib.BitmapIndex;
20  import org.eclipse.jgit.lib.ObjectId;
21  
22  import com.googlecode.javaewah.EWAHCompressedBitmap;
23  import com.googlecode.javaewah.IntIterator;
24  
25  /**
26   * A PackBitmapIndex that remaps the bitmaps in the previous index to the
27   * positions in the new pack index. Note, unlike typical PackBitmapIndex
28   * implementations this implementation is not thread safe, as it is intended to
29   * be used with a PackBitmapIndexBuilder, which is also not thread safe.
30   */
31  public class PackBitmapIndexRemapper extends PackBitmapIndex
32  		implements Iterable<PackBitmapIndexRemapper.Entry> {
33  
34  	private final BasePackBitmapIndex oldPackIndex;
35  	final PackBitmapIndex newPackIndex;
36  	private final BitSet inflated;
37  	private final int[] prevToNewMapping;
38  
39  	/**
40  	 * A PackBitmapIndex that maps the positions in the prevBitmapIndex to the
41  	 * ones in the newIndex.
42  	 *
43  	 * @param prevBitmapIndex
44  	 *            the bitmap index with the old mapping.
45  	 * @param newIndex
46  	 *            the bitmap index with the new mapping.
47  	 * @return a bitmap index that attempts to do the mapping between the two.
48  	 */
49  	public static PackBitmapIndexRemapper newPackBitmapIndex(
50  			BitmapIndex prevBitmapIndex, PackBitmapIndex newIndex) {
51  		if (!(prevBitmapIndex instanceof BitmapIndexImpl))
52  			return new PackBitmapIndexRemapper(newIndex);
53  
54  		PackBitmapIndex prevIndex = ((BitmapIndexImpl) prevBitmapIndex)
55  				.getPackBitmapIndex();
56  		if (!(prevIndex instanceof BasePackBitmapIndex))
57  			return new PackBitmapIndexRemapper(newIndex);
58  
59  		return new PackBitmapIndexRemapper(
60  				(BasePackBitmapIndex) prevIndex, newIndex);
61  	}
62  
63  	private PackBitmapIndexRemapper(PackBitmapIndex newPackIndex) {
64  		this.oldPackIndex = null;
65  		this.newPackIndex = newPackIndex;
66  		this.inflated = null;
67  		this.prevToNewMapping = null;
68  	}
69  
70  	private PackBitmapIndexRemapper(
71  			BasePackBitmapIndex oldPackIndex, PackBitmapIndex newPackIndex) {
72  		this.oldPackIndex = oldPackIndex;
73  		this.newPackIndex = newPackIndex;
74  		inflated = new BitSet(newPackIndex.getObjectCount());
75  
76  		prevToNewMapping = new int[oldPackIndex.getObjectCount()];
77  		for (int pos = 0; pos < prevToNewMapping.length; pos++)
78  			prevToNewMapping[pos] = newPackIndex.findPosition(
79  					oldPackIndex.getObject(pos));
80  	}
81  
82  	/** {@inheritDoc} */
83  	@Override
84  	public int findPosition(AnyObjectId objectId) {
85  		return newPackIndex.findPosition(objectId);
86  	}
87  
88  	/** {@inheritDoc} */
89  	@Override
90  	public ObjectId getObject(int position) throws IllegalArgumentException {
91  		return newPackIndex.getObject(position);
92  	}
93  
94  	/** {@inheritDoc} */
95  	@Override
96  	public int getObjectCount() {
97  		return newPackIndex.getObjectCount();
98  	}
99  
100 	/** {@inheritDoc} */
101 	@Override
102 	public EWAHCompressedBitmap ofObjectType(
103 			EWAHCompressedBitmap bitmap, int type) {
104 		return newPackIndex.ofObjectType(bitmap, type);
105 	}
106 
107 	/** {@inheritDoc} */
108 	@Override
109 	public Iterator<Entry> iterator() {
110 		if (oldPackIndex == null)
111 			return Collections.<Entry> emptyList().iterator();
112 
113 		final Iterator<StoredBitmap> it = oldPackIndex.getBitmaps().iterator();
114 		return new Iterator<Entry>() {
115 			private Entry entry;
116 
117 			@Override
118 			public boolean hasNext() {
119 				while (entry == null && it.hasNext()) {
120 					StoredBitmap sb = it.next();
121 					if (newPackIndex.findPosition(sb) != -1)
122 						entry = new Entry(sb, sb.getFlags());
123 				}
124 				return entry != null;
125 			}
126 
127 			@Override
128 			public Entry next() {
129 				if (!hasNext())
130 					throw new NoSuchElementException();
131 
132 				Entry res = entry;
133 				entry = null;
134 				return res;
135 			}
136 
137 			@Override
138 			public void remove() {
139 				throw new UnsupportedOperationException();
140 			}
141 		};
142 	}
143 
144 	/** {@inheritDoc} */
145 	@Override
146 	public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
147 		EWAHCompressedBitmap bitmap = newPackIndex.getBitmap(objectId);
148 		if (bitmap != null || oldPackIndex == null)
149 			return bitmap;
150 
151 		StoredBitmap oldBitmap = oldPackIndex.getBitmaps().get(objectId);
152 		if (oldBitmap == null)
153 			return null;
154 
155 		if (newPackIndex.findPosition(objectId) == -1)
156 			return null;
157 
158 		inflated.clear();
159 		for (IntIterator i = oldBitmap.getBitmapWithoutCaching()
160 				.intIterator(); i.hasNext();)
161 			inflated.set(prevToNewMapping[i.next()]);
162 		bitmap = inflated.toEWAHCompressedBitmap();
163 		bitmap.trim();
164 		return bitmap;
165 	}
166 
167 	/** An entry in the old PackBitmapIndex. */
168 	public static final class Entry extends ObjectId {
169 		private final int flags;
170 
171 		Entry(AnyObjectId src, int flags) {
172 			super(src);
173 			this.flags = flags;
174 		}
175 
176 		/** @return the flags associated with the bitmap. */
177 		public int getFlags() {
178 			return flags;
179 		}
180 	}
181 
182 	/** {@inheritDoc} */
183 	@Override
184 	public int getBitmapCount() {
185 		// The count is only useful for the end index, not the remapper.
186 		return 0;
187 	}
188 }