--- /dev/null
+/*
+ * Copyright (C) 2018, Google LLC.
+ * 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 org.eclipse.jgit.internal.storage.dfs;
+
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.DEFAULT_COMPARATOR;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.RECEIVE;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class PackSourceTest {
+ @Test
+ public void defaultComaprator() throws Exception {
+ assertEquals(0, DEFAULT_COMPARATOR.compare(INSERT, INSERT));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(RECEIVE, RECEIVE));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(COMPACT, COMPACT));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(GC, GC));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(GC_REST, GC_REST));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(GC_TXN, GC_TXN));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(UNREACHABLE_GARBAGE, UNREACHABLE_GARBAGE));
+
+ assertEquals(0, DEFAULT_COMPARATOR.compare(INSERT, RECEIVE));
+ assertEquals(0, DEFAULT_COMPARATOR.compare(RECEIVE, INSERT));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(INSERT, COMPACT));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(COMPACT, INSERT));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(RECEIVE, COMPACT));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(COMPACT, RECEIVE));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(COMPACT, GC));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(GC, COMPACT));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(GC, GC_REST));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(GC_REST, GC));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(GC_REST, GC_TXN));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(GC_TXN, GC_REST));
+
+ assertEquals(-1, DEFAULT_COMPARATOR.compare(GC_TXN, UNREACHABLE_GARBAGE));
+ assertEquals(1, DEFAULT_COMPARATOR.compare(UNREACHABLE_GARBAGE, GC_TXN));
+ }
+}
package org.eclipse.jgit.internal.storage.dfs;
+import static java.util.stream.Collectors.joining;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
}
};
- /** Sources for a pack file. */
+ /**
+ * Sources for a pack file.
+ * <p>
+ * <strong>Note:</strong> When sorting packs by source, do not use the default
+ * comparator based on {@link Enum#compareTo}. Prefer {@link
+ * #DEFAULT_COMPARATOR} or your own {@link ComparatorBuilder}.
+ */
public static enum PackSource {
/** The pack is created by ObjectInserter due to local activity. */
- INSERT(0),
+ INSERT,
/**
* The pack is created by PackParser due to a network event.
* storage layout preferred by this version. Received packs are likely
* to be either compacted or garbage collected in the future.
*/
- RECEIVE(0),
+ RECEIVE,
/**
* The pack was created by compacting multiple packs together.
*
* @see DfsPackCompactor
*/
- COMPACT(1),
+ COMPACT,
/**
* Pack was created by Git garbage collection by this implementation.
*
* @see DfsGarbageCollector
*/
- GC(2),
+ GC,
/** Created from non-heads by {@link DfsGarbageCollector}. */
- GC_REST(3),
+ GC_REST,
/**
* RefTreeGraph pack was created by Git garbage collection.
*
* @see DfsGarbageCollector
*/
- GC_TXN(4),
+ GC_TXN,
/**
* Pack was created by Git garbage collection.
* last GC pass. It is retained in a new pack until it is safe to prune
* these objects from the repository.
*/
- UNREACHABLE_GARBAGE(5);
+ UNREACHABLE_GARBAGE;
+
+ /**
+ * Default comparator for sources.
+ * <p>
+ * Sorts generally newer, smaller types such as {@code INSERT} and {@code
+ * RECEIVE} earlier; older, larger types such as {@code GC} later; and
+ * {@code UNREACHABLE_GARBAGE} at the end.
+ */
+ public static final Comparator<PackSource> DEFAULT_COMPARATOR =
+ new ComparatorBuilder()
+ .add(INSERT, RECEIVE)
+ .add(COMPACT)
+ .add(GC)
+ .add(GC_REST)
+ .add(GC_TXN)
+ .add(UNREACHABLE_GARBAGE)
+ .build();
+
+ /**
+ * Builder for describing {@link PackSource} ordering where some values are
+ * explicitly considered equal to others.
+ */
+ public static class ComparatorBuilder {
+ private final Map<PackSource, Integer> ranks = new HashMap<>();
+ private int counter;
+
+ /**
+ * Add a collection of sources that should sort as equal.
+ * <p>
+ * Sources in the input will sort after sources listed in previous calls
+ * to this method.
+ *
+ * @param sources
+ * sources in this equivalence class.
+ * @return this.
+ */
+ public ComparatorBuilder add(PackSource... sources) {
+ for (PackSource s : sources) {
+ ranks.put(s, Integer.valueOf(counter));
+ }
+ counter++;
+ return this;
+ }
+
+ /**
+ * Build the comparator.
+ *
+ * @return new comparator instance.
+ * @throws IllegalArgumentException
+ * not all {@link PackSource} instances were explicitly assigned
+ * an equivalence class.
+ */
+ public Comparator<PackSource> build() {
+ return new PackSourceComparator(ranks);
+ }
+ }
- final int category;
+ private static class PackSourceComparator implements Comparator<PackSource> {
+ private final Map<PackSource, Integer> ranks;
- PackSource(int category) {
- this.category = category;
+ private PackSourceComparator(Map<PackSource, Integer> ranks) {
+ if (!ranks.keySet().equals(
+ new HashSet<>(Arrays.asList(PackSource.values())))) {
+ throw new IllegalArgumentException();
+ }
+ this.ranks = new HashMap<>(ranks);
+ }
+
+ @Override
+ public int compare(PackSource a, PackSource b) {
+ return ranks.get(a).compareTo(ranks.get(b));
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.stream(PackSource.values())
+ .map(s -> s + "=" + ranks.get(s)) //$NON-NLS-1$
+ .collect(joining(", ", getClass().getSimpleName() + "{", "}")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
}
}
DfsPackDescription a = fa.getPackDescription();
DfsPackDescription b = fb.getPackDescription();
- // GC, COMPACT reftables first by higher category.
- int c = b.getPackSource().category - a.getPackSource().category;
+ // GC, COMPACT reftables first by reversing default order.
+ int c = PackSource.DEFAULT_COMPARATOR.reversed()
+ .compare(a.getPackSource(), b.getPackSource());
if (c != 0) {
return c;
}