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.

BaseSearch.java 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (C) 2011, 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.internal.storage.pack;
  11. import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
  12. import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
  13. import java.io.IOException;
  14. import java.util.List;
  15. import java.util.Set;
  16. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  17. import org.eclipse.jgit.errors.MissingObjectException;
  18. import org.eclipse.jgit.lib.AnyObjectId;
  19. import org.eclipse.jgit.lib.FileMode;
  20. import org.eclipse.jgit.lib.MutableObjectId;
  21. import org.eclipse.jgit.lib.ObjectId;
  22. import org.eclipse.jgit.lib.ObjectIdOwnerMap;
  23. import org.eclipse.jgit.lib.ObjectLoader;
  24. import org.eclipse.jgit.lib.ObjectReader;
  25. import org.eclipse.jgit.lib.ProgressMonitor;
  26. import org.eclipse.jgit.revwalk.RevTree;
  27. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  28. class BaseSearch {
  29. private static final int M_BLOB = FileMode.REGULAR_FILE.getBits();
  30. private static final int M_TREE = FileMode.TREE.getBits();
  31. private final ProgressMonitor progress;
  32. private final ObjectReader reader;
  33. private final ObjectId[] baseTrees;
  34. private final ObjectIdOwnerMap<ObjectToPack> objectsMap;
  35. private final List<ObjectToPack> edgeObjects;
  36. private final IntSet alreadyProcessed;
  37. private final ObjectIdOwnerMap<TreeWithData> treeCache;
  38. private final CanonicalTreeParser parser;
  39. private final MutableObjectId idBuf;
  40. BaseSearch(ProgressMonitor countingMonitor, Set<RevTree> bases,
  41. ObjectIdOwnerMap<ObjectToPack> objects,
  42. List<ObjectToPack> edges, ObjectReader or) {
  43. progress = countingMonitor;
  44. reader = or;
  45. baseTrees = bases.toArray(new ObjectId[0]);
  46. objectsMap = objects;
  47. edgeObjects = edges;
  48. alreadyProcessed = new IntSet();
  49. treeCache = new ObjectIdOwnerMap<>();
  50. parser = new CanonicalTreeParser();
  51. idBuf = new MutableObjectId();
  52. }
  53. void addBase(int objectType, byte[] pathBuf, int pathLen, int pathHash)
  54. throws IOException {
  55. final int tailMode = modeForType(objectType);
  56. if (tailMode == 0)
  57. return;
  58. if (!alreadyProcessed.add(pathHash))
  59. return;
  60. if (pathLen == 0) {
  61. for (ObjectId root : baseTrees)
  62. add(root, OBJ_TREE, pathHash);
  63. return;
  64. }
  65. final int firstSlash = nextSlash(pathBuf, 0, pathLen);
  66. CHECK_BASE: for (ObjectId root : baseTrees) {
  67. int ptr = 0;
  68. int end = firstSlash;
  69. int mode = end != pathLen ? M_TREE : tailMode;
  70. parser.reset(readTree(root));
  71. while (!parser.eof()) {
  72. int cmp = parser.pathCompare(pathBuf, ptr, end, mode);
  73. if (cmp < 0) {
  74. parser.next();
  75. continue;
  76. }
  77. if (cmp > 0)
  78. continue CHECK_BASE;
  79. if (end == pathLen) {
  80. if (parser.getEntryFileMode().getObjectType() == objectType) {
  81. idBuf.fromRaw(parser.idBuffer(), parser.idOffset());
  82. add(idBuf, objectType, pathHash);
  83. }
  84. continue CHECK_BASE;
  85. }
  86. if (!FileMode.TREE.equals(parser.getEntryRawMode()))
  87. continue CHECK_BASE;
  88. ptr = end + 1;
  89. end = nextSlash(pathBuf, ptr, pathLen);
  90. mode = end != pathLen ? M_TREE : tailMode;
  91. idBuf.fromRaw(parser.idBuffer(), parser.idOffset());
  92. parser.reset(readTree(idBuf));
  93. }
  94. }
  95. }
  96. private static int modeForType(int typeCode) {
  97. switch (typeCode) {
  98. case OBJ_TREE:
  99. return M_TREE;
  100. case OBJ_BLOB:
  101. return M_BLOB;
  102. default:
  103. return 0;
  104. }
  105. }
  106. private static int nextSlash(byte[] pathBuf, int ptr, int end) {
  107. while (ptr < end && pathBuf[ptr] != '/')
  108. ptr++;
  109. return ptr;
  110. }
  111. private void add(AnyObjectId id, int objectType, int pathHash) {
  112. ObjectToPack obj = new ObjectToPack(id, objectType);
  113. obj.setEdge();
  114. obj.setPathHash(pathHash);
  115. if (objectsMap.addIfAbsent(obj) == obj) {
  116. edgeObjects.add(obj);
  117. progress.update(1);
  118. }
  119. }
  120. private byte[] readTree(AnyObjectId id) throws MissingObjectException,
  121. IncorrectObjectTypeException, IOException {
  122. TreeWithData tree = treeCache.get(id);
  123. if (tree != null)
  124. return tree.buf;
  125. ObjectLoader ldr = reader.open(id, OBJ_TREE);
  126. byte[] buf = ldr.getCachedBytes(Integer.MAX_VALUE);
  127. treeCache.add(new TreeWithData(id, buf));
  128. return buf;
  129. }
  130. private static class TreeWithData extends ObjectIdOwnerMap.Entry {
  131. final byte[] buf;
  132. TreeWithData(AnyObjectId id, byte[] buf) {
  133. super(id);
  134. this.buf = buf;
  135. }
  136. }
  137. }