BaseSearch.java

  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.     @SuppressWarnings("ReferenceEquality")
  112.     private void add(AnyObjectId id, int objectType, int pathHash) {
  113.         ObjectToPack obj = new ObjectToPack(id, objectType);
  114.         obj.setEdge();
  115.         obj.setPathHash(pathHash);

  116.         if (objectsMap.addIfAbsent(obj) == obj) {
  117.             edgeObjects.add(obj);
  118.             progress.update(1);
  119.         }
  120.     }

  121.     private byte[] readTree(AnyObjectId id) throws MissingObjectException,
  122.             IncorrectObjectTypeException, IOException {
  123.         TreeWithData tree = treeCache.get(id);
  124.         if (tree != null)
  125.             return tree.buf;

  126.         ObjectLoader ldr = reader.open(id, OBJ_TREE);
  127.         byte[] buf = ldr.getCachedBytes(Integer.MAX_VALUE);
  128.         treeCache.add(new TreeWithData(id, buf));
  129.         return buf;
  130.     }

  131.     private static class TreeWithData extends ObjectIdOwnerMap.Entry {
  132.         final byte[] buf;

  133.         TreeWithData(AnyObjectId id, byte[] buf) {
  134.             super(id);
  135.             this.buf = buf;
  136.         }
  137.     }
  138. }