Use RefMap instead of HashMap

HashMap<String, Ref> has a memory overhead for refs. Use RefMap.

Change-Id: I3fb4616135dacf687cc3bc2b473effc66ccef5e6
Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
This commit is contained in:
Masaya Suzuki 2019-03-19 20:42:10 -07:00
parent 40e74f8a1a
commit 47e37b0fa4
4 changed files with 122 additions and 6 deletions

View File

@ -127,6 +127,41 @@ public void testBuilder_AddThenSort() {
assertSame(REF_B, list.get(1));
}
@Test
public void testBuilder_AddThenDedupe() {
RefList.Builder<Ref> builder = new RefList.Builder<>(1);
builder.add(REF_B);
builder.add(REF_A);
builder.add(REF_A);
builder.add(REF_B);
builder.add(REF_c);
builder.sort();
builder.dedupe((a, b) -> b);
RefList<Ref> list = builder.toRefList();
assertEquals(3, list.size());
assertSame(REF_A, list.get(0));
assertSame(REF_B, list.get(1));
assertSame(REF_c, list.get(2));
}
@Test
public void testBuilder_AddThenDedupe_Border() {
RefList.Builder<Ref> builder = new RefList.Builder<>(1);
builder.sort();
builder.dedupe((a, b) -> b);
RefList<Ref> list = builder.toRefList();
assertTrue(list.isEmpty());
builder = new RefList.Builder<>(1);
builder.add(REF_A);
builder.sort();
builder.dedupe((a, b) -> b);
list = builder.toRefList();
assertEquals(1, list.size());
}
@Test
public void testBuilder_AddAll() {
RefList.Builder<Ref> builder = new RefList.Builder<>(1);

View File

@ -44,8 +44,7 @@
package org.eclipse.jgit.transport;
import static java.util.Collections.unmodifiableMap;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static org.eclipse.jgit.util.RefMap.toRefMap;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REF_IN_WANT;
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_FETCH;
@ -817,7 +816,7 @@ private Map<String, Ref> getAdvertisedOrDefaultRefs() throws IOException {
// Fall back to all refs.
setAdvertisedRefs(
db.getRefDatabase().getRefs().stream()
.collect(toMap(Ref::getName, identity())));
.collect(toRefMap((a, b) -> b)));
}
return refs;
}
@ -836,7 +835,7 @@ private Map<String, Ref> getFilteredRefs(Collection<String> refPrefixes)
String[] prefixes = refPrefixes.toArray(new String[0]);
Map<String, Ref> rs =
db.getRefDatabase().getRefsByPrefix(prefixes).stream()
.collect(toMap(Ref::getName, identity(), (a, b) -> b));
.collect(toRefMap((a, b) -> b));
if (refFilter != RefFilter.DEFAULT) {
return refFilter.filter(rs);
}
@ -848,7 +847,7 @@ private Map<String, Ref> getFilteredRefs(Collection<String> refPrefixes)
return refs.values().stream()
.filter(ref -> refPrefixes.stream()
.anyMatch(ref.getName()::startsWith))
.collect(toMap(Ref::getName, identity()));
.collect(toRefMap((a, b) -> b));
}
/**
@ -871,7 +870,7 @@ private static Map<String, Ref> mapRefs(
names.stream()
.map(refs::get)
.filter(Objects::nonNull)
.collect(toMap(Ref::getName, identity(), (a, b) -> b)));
.collect(toRefMap((a, b) -> b)));
}
/**

View File

@ -48,7 +48,10 @@
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BinaryOperator;
import java.util.stream.Collector;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefComparator;
@ -332,6 +335,32 @@ public String toString() {
return r.toString();
}
/**
* Create a {@link Collector} for {@link Ref}.
*
* @param mergeFunction
* if specified the result will be sorted and deduped.
* @return {@link Collector} for {@link Ref}
* @since 5.4
*/
public static <T extends Ref> Collector<T, ?, RefList<T>> toRefList(
@Nullable BinaryOperator<T> mergeFunction) {
return Collector.of(
() -> new Builder<>(),
Builder<T>::add, (b1, b2) -> {
Builder<T> b = new Builder<>();
b.addAll(b1);
b.addAll(b2);
return b;
}, (b) -> {
if (mergeFunction != null) {
b.sort();
b.dedupe(mergeFunction);
}
return b.toRefList();
});
}
/**
* Builder to facilitate fast construction of an immutable RefList.
*
@ -404,6 +433,16 @@ public void add(T ref) {
list[size++] = ref;
}
/**
* Add all items from another builder.
*
* @param other
* @since 5.4
*/
public void addAll(Builder other) {
addAll(other.list, 0, other.size);
}
/**
* Add all items from a source array.
* <p>
@ -444,6 +483,31 @@ public void sort() {
Arrays.sort(list, 0, size, RefComparator.INSTANCE);
}
/**
* Dedupe the refs in place. Must be called after {@link #sort}.
*
* @param mergeFunction
*/
@SuppressWarnings("unchecked")
void dedupe(BinaryOperator<T> mergeFunction) {
if (size == 0) {
return;
}
int lastElement = 0;
for (int i = 1; i < size; i++) {
if (RefComparator.INSTANCE.compare(list[lastElement],
list[i]) == 0) {
list[lastElement] = mergeFunction
.apply((T) list[lastElement], (T) list[i]);
} else {
list[lastElement + 1] = list[i];
lastElement++;
}
}
size = lastElement + 1;
Arrays.fill(list, size, list.length, null);
}
/** @return an unmodifiable list using this collection's backing array. */
public RefList<T> toRefList() {
return new RefList<>(list, size);

View File

@ -49,6 +49,9 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
@ -285,6 +288,21 @@ public String toString() {
return r.toString();
}
/**
* Create a {@link Collector} for {@link Ref}.
*
* @param mergeFunction
* @return {@link Collector} for {@link Ref}
* @since 5.4
*/
public static Collector<Ref, ?, RefMap> toRefMap(
BinaryOperator<Ref> mergeFunction) {
return Collectors.collectingAndThen(RefList.toRefList(mergeFunction),
(refs) -> new RefMap("", //$NON-NLS-1$
refs, RefList.emptyList(),
RefList.emptyList()));
}
private String toRefName(String name) {
if (0 < prefix.length())
name = prefix + name;