Browse Source

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>
stable-5.4
Masaya Suzuki 6 years ago
parent
commit
47e37b0fa4
  1. 35
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java
  2. 11
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
  3. 64
      org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
  4. 18
      org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java

35
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefListTest.java

@ -127,6 +127,41 @@ public class RefListTest {
assertSame(REF_B, list.get(1)); 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 @Test
public void testBuilder_AddAll() { public void testBuilder_AddAll() {
RefList.Builder<Ref> builder = new RefList.Builder<>(1); RefList.Builder<Ref> builder = new RefList.Builder<>(1);

11
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

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

64
org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java

@ -48,7 +48,10 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; 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.Ref;
import org.eclipse.jgit.lib.RefComparator; import org.eclipse.jgit.lib.RefComparator;
@ -332,6 +335,32 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
return r.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. * Builder to facilitate fast construction of an immutable RefList.
* *
@ -404,6 +433,16 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
list[size++] = 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. * Add all items from a source array.
* <p> * <p>
@ -444,6 +483,31 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
Arrays.sort(list, 0, size, RefComparator.INSTANCE); 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. */ /** @return an unmodifiable list using this collection's backing array. */
public RefList<T> toRefList() { public RefList<T> toRefList() {
return new RefList<>(list, size); return new RefList<>(list, size);

18
org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java

@ -49,6 +49,9 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; 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.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
@ -285,6 +288,21 @@ public class RefMap extends AbstractMap<String, Ref> {
return r.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) { private String toRefName(String name) {
if (0 < prefix.length()) if (0 < prefix.length())
name = prefix + name; name = prefix + name;

Loading…
Cancel
Save