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