You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VerifyReftable.java 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright (C) 2017, 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. package org.eclipse.jgit.pgm.debug;
  11. import java.io.FileInputStream;
  12. import java.io.IOException;
  13. import java.util.ArrayList;
  14. import java.util.Collections;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. import java.util.Map;
  18. import java.util.Random;
  19. import org.eclipse.jgit.internal.storage.io.BlockSource;
  20. import org.eclipse.jgit.internal.storage.reftable.RefCursor;
  21. import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
  22. import org.eclipse.jgit.lib.AnyObjectId;
  23. import org.eclipse.jgit.lib.ObjectId;
  24. import org.eclipse.jgit.lib.Ref;
  25. import org.eclipse.jgit.lib.RefComparator;
  26. import org.eclipse.jgit.lib.TextProgressMonitor;
  27. import org.eclipse.jgit.pgm.Command;
  28. import org.eclipse.jgit.pgm.TextBuiltin;
  29. import org.kohsuke.args4j.Argument;
  30. @Command
  31. class VerifyReftable extends TextBuiltin {
  32. private static final long SEED1 = 0xaba8bb4de4caf86cL;
  33. private static final long SEED2 = 0x28bb5c25ad43ecb5L;
  34. @Argument(index = 0)
  35. private String lsRemotePath;
  36. @Argument(index = 1)
  37. private String reftablePath;
  38. /** {@inheritDoc} */
  39. @Override
  40. protected void run() throws Exception {
  41. List<Ref> refs = WriteReftable.readRefs(lsRemotePath);
  42. try (FileInputStream in = new FileInputStream(reftablePath);
  43. BlockSource src = BlockSource.from(in);
  44. ReftableReader reader = new ReftableReader(src)) {
  45. scan(refs, reader);
  46. seek(refs, reader);
  47. byId(refs, reader);
  48. }
  49. }
  50. @SuppressWarnings("nls")
  51. private void scan(List<Ref> refs, ReftableReader reader)
  52. throws IOException {
  53. errw.print(String.format("%-20s", "sequential scan..."));
  54. errw.flush();
  55. try (RefCursor rc = reader.allRefs()) {
  56. for (Ref exp : refs) {
  57. verify(exp, rc);
  58. }
  59. if (rc.next()) {
  60. throw die("expected end of table");
  61. }
  62. }
  63. errw.println(" OK");
  64. }
  65. @SuppressWarnings("nls")
  66. private void seek(List<Ref> refs, ReftableReader reader)
  67. throws IOException {
  68. List<Ref> rnd = new ArrayList<>(refs);
  69. Collections.shuffle(rnd, new Random(SEED1));
  70. TextProgressMonitor pm = new TextProgressMonitor(errw);
  71. pm.beginTask("random seek", rnd.size());
  72. for (Ref exp : rnd) {
  73. try (RefCursor rc = reader.seekRef(exp.getName())) {
  74. verify(exp, rc);
  75. if (rc.next()) {
  76. throw die("should not have ref after " + exp.getName());
  77. }
  78. }
  79. pm.update(1);
  80. }
  81. pm.endTask();
  82. }
  83. @SuppressWarnings("nls")
  84. private void byId(List<Ref> refs, ReftableReader reader)
  85. throws IOException {
  86. Map<ObjectId, List<Ref>> want = groupById(refs);
  87. List<List<Ref>> rnd = new ArrayList<>(want.values());
  88. Collections.shuffle(rnd, new Random(SEED2));
  89. TextProgressMonitor pm = new TextProgressMonitor(errw);
  90. pm.beginTask("byObjectId", rnd.size());
  91. for (List<Ref> exp : rnd) {
  92. Collections.sort(exp, RefComparator.INSTANCE);
  93. ObjectId id = exp.get(0).getObjectId();
  94. try (RefCursor rc = reader.byObjectId(id)) {
  95. for (Ref r : exp) {
  96. verify(r, rc);
  97. }
  98. }
  99. pm.update(1);
  100. }
  101. pm.endTask();
  102. }
  103. private static Map<ObjectId, List<Ref>> groupById(List<Ref> refs) {
  104. Map<ObjectId, List<Ref>> m = new HashMap<>();
  105. for (Ref r : refs) {
  106. ObjectId id = r.getObjectId();
  107. if (id != null) {
  108. List<Ref> c = m.get(id);
  109. if (c == null) {
  110. c = new ArrayList<>(2);
  111. m.put(id, c);
  112. }
  113. c.add(r);
  114. }
  115. }
  116. return m;
  117. }
  118. @SuppressWarnings("nls")
  119. private void verify(Ref exp, RefCursor rc) throws IOException {
  120. if (!rc.next()) {
  121. throw die("ended before " + exp.getName());
  122. }
  123. Ref act = rc.getRef();
  124. if (!exp.getName().equals(act.getName())) {
  125. throw die(String.format("expected %s, found %s",
  126. exp.getName(),
  127. act.getName()));
  128. }
  129. if (exp.isSymbolic()) {
  130. if (!act.isSymbolic()) {
  131. throw die("expected " + act.getName() + " to be symbolic");
  132. }
  133. if (!exp.getTarget().getName().equals(act.getTarget().getName())) {
  134. throw die(String.format("expected %s to be %s, found %s",
  135. exp.getName(),
  136. exp.getLeaf().getName(),
  137. act.getLeaf().getName()));
  138. }
  139. return;
  140. }
  141. if (!AnyObjectId.isEqual(exp.getObjectId(), act.getObjectId())) {
  142. throw die(String.format("expected %s to be %s, found %s",
  143. exp.getName(),
  144. id(exp.getObjectId()),
  145. id(act.getObjectId())));
  146. }
  147. if (exp.getPeeledObjectId() != null
  148. && !AnyObjectId.isEqual(exp.getPeeledObjectId(),
  149. act.getPeeledObjectId())) {
  150. throw die(String.format("expected %s to be %s, found %s",
  151. exp.getName(),
  152. id(exp.getPeeledObjectId()),
  153. id(act.getPeeledObjectId())));
  154. }
  155. }
  156. @SuppressWarnings("nls")
  157. private static String id(ObjectId id) {
  158. return id != null ? id.name() : "<null>";
  159. }
  160. }