aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2017-07-12 12:44:03 -0700
committerShawn Pearce <spearce@spearce.org>2017-08-17 15:06:51 -0700
commit0398f3dd6e347713da0a27f1bf3a6a88d3c8e869 (patch)
treeb7a4192533030be3e92ae2fa58c0628d25771046 /org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
parent0a26dcf4a34db30a9aae93becaf5db1c3dba2c7b (diff)
downloadjgit-0398f3dd6e347713da0a27f1bf3a6a88d3c8e869.tar.gz
jgit-0398f3dd6e347713da0a27f1bf3a6a88d3c8e869.zip
reftable: debug tools
Simple debug programs to experiment with the reftable file format: debug-read-reftable debug-write-reftable debug-verify-reftable debug-benchmark-reftable Change-Id: I79db351d86900f1e58b17e922e195dff06ee71f1
Diffstat (limited to 'org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java')
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java211
1 files changed, 211 insertions, 0 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
new file mode 100644
index 0000000000..dffb579895
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/VerifyReftable.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2017, Google Inc.
+ * 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.pgm.debug;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.eclipse.jgit.internal.storage.io.BlockSource;
+import org.eclipse.jgit.internal.storage.reftable.RefCursor;
+import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefComparator;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.pgm.Command;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.kohsuke.args4j.Argument;
+
+@Command
+class VerifyReftable extends TextBuiltin {
+ private static final long SEED1 = 0xaba8bb4de4caf86cL;
+ private static final long SEED2 = 0x28bb5c25ad43ecb5L;
+
+ @Argument(index = 0)
+ private String lsRemotePath;
+
+ @Argument(index = 1)
+ private String reftablePath;
+
+ @Override
+ protected void run() throws Exception {
+ List<Ref> refs = WriteReftable.readRefs(lsRemotePath);
+
+ try (FileInputStream in = new FileInputStream(reftablePath);
+ BlockSource src = BlockSource.from(in);
+ ReftableReader reader = new ReftableReader(src)) {
+ scan(refs, reader);
+ seek(refs, reader);
+ byId(refs, reader);
+ }
+ }
+
+ @SuppressWarnings("nls")
+ private void scan(List<Ref> refs, ReftableReader reader)
+ throws IOException {
+ errw.print(String.format("%-20s", "sequential scan..."));
+ errw.flush();
+ try (RefCursor rc = reader.allRefs()) {
+ for (Ref exp : refs) {
+ verify(exp, rc);
+ }
+ if (rc.next()) {
+ throw die("expected end of table");
+ }
+ }
+ errw.println(" OK");
+ }
+
+ @SuppressWarnings("nls")
+ private void seek(List<Ref> refs, ReftableReader reader)
+ throws IOException {
+ List<Ref> rnd = new ArrayList<>(refs);
+ Collections.shuffle(rnd, new Random(SEED1));
+
+ TextProgressMonitor pm = new TextProgressMonitor(errw);
+ pm.beginTask("random seek", rnd.size());
+ for (Ref exp : rnd) {
+ try (RefCursor rc = reader.seekRef(exp.getName())) {
+ verify(exp, rc);
+ if (rc.next()) {
+ throw die("should not have ref after " + exp.getName());
+ }
+ }
+ pm.update(1);
+ }
+ pm.endTask();
+ }
+
+ @SuppressWarnings("nls")
+ private void byId(List<Ref> refs, ReftableReader reader)
+ throws IOException {
+ Map<ObjectId, List<Ref>> want = groupById(refs);
+ List<List<Ref>> rnd = new ArrayList<>(want.values());
+ Collections.shuffle(rnd, new Random(SEED2));
+
+ TextProgressMonitor pm = new TextProgressMonitor(errw);
+ pm.beginTask("byObjectId", rnd.size());
+ for (List<Ref> exp : rnd) {
+ Collections.sort(exp, RefComparator.INSTANCE);
+ ObjectId id = exp.get(0).getObjectId();
+ try (RefCursor rc = reader.byObjectId(id)) {
+ for (Ref r : exp) {
+ verify(r, rc);
+ }
+ }
+ pm.update(1);
+ }
+ pm.endTask();
+ }
+
+ private static Map<ObjectId, List<Ref>> groupById(List<Ref> refs) {
+ Map<ObjectId, List<Ref>> m = new HashMap<>();
+ for (Ref r : refs) {
+ ObjectId id = r.getObjectId();
+ if (id != null) {
+ List<Ref> c = m.get(id);
+ if (c == null) {
+ c = new ArrayList<>(2);
+ m.put(id, c);
+ }
+ c.add(r);
+ }
+ }
+ return m;
+ }
+
+ @SuppressWarnings("nls")
+ private void verify(Ref exp, RefCursor rc) throws IOException {
+ if (!rc.next()) {
+ throw die("ended before " + exp.getName());
+ }
+
+ Ref act = rc.getRef();
+ if (!exp.getName().equals(act.getName())) {
+ throw die(String.format("expected %s, found %s",
+ exp.getName(),
+ act.getName()));
+ }
+
+ if (exp.isSymbolic()) {
+ if (!act.isSymbolic()) {
+ throw die("expected " + act.getName() + " to be symbolic");
+ }
+ if (!exp.getTarget().getName().equals(act.getTarget().getName())) {
+ throw die(String.format("expected %s to be %s, found %s",
+ exp.getName(),
+ exp.getLeaf().getName(),
+ act.getLeaf().getName()));
+ }
+ return;
+ }
+
+ if (!AnyObjectId.equals(exp.getObjectId(), act.getObjectId())) {
+ throw die(String.format("expected %s to be %s, found %s",
+ exp.getName(),
+ id(exp.getObjectId()),
+ id(act.getObjectId())));
+ }
+
+ if (exp.getPeeledObjectId() != null
+ && !AnyObjectId.equals(exp.getPeeledObjectId(), act.getPeeledObjectId())) {
+ throw die(String.format("expected %s to be %s, found %s",
+ exp.getName(),
+ id(exp.getPeeledObjectId()),
+ id(act.getPeeledObjectId())));
+ }
+ }
+
+ @SuppressWarnings("nls")
+ private static String id(ObjectId id) {
+ return id != null ? id.name() : "<null>";
+ }
+}