| /* |
| * Copyright (C) 2022, Tencent. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Distribution License v. 1.0 which is available at |
| * https://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| package org.eclipse.jgit.internal.storage.commitgraph; |
| |
| import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraphConstants.COMMIT_DATA_WIDTH; |
| import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraphConstants.GRAPH_EDGE_LAST_MASK; |
| import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraphConstants.GRAPH_EXTRA_EDGES_NEEDED; |
| import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraphConstants.GRAPH_LAST_EDGE; |
| import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraphConstants.GRAPH_NO_PARENT; |
| |
| import java.text.MessageFormat; |
| import java.util.Arrays; |
| |
| import org.eclipse.jgit.annotations.NonNull; |
| import org.eclipse.jgit.internal.JGitText; |
| import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph.CommitData; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.util.NB; |
| |
| /** |
| * Represent the collection of {@link CommitData}. |
| */ |
| class GraphCommitData { |
| |
| private static final int[] NO_PARENTS = {}; |
| |
| private final byte[] data; |
| |
| private final byte[] extraList; |
| |
| private final int hashLength; |
| |
| private final int commitDataLength; |
| |
| /** |
| * Initialize the GraphCommitData. |
| * |
| * @param hashLength |
| * length of object hash. |
| * @param commitData |
| * content of CommitData Chunk. |
| * @param extraList |
| * content of Extra Edge List Chunk. |
| */ |
| GraphCommitData(int hashLength, @NonNull byte[] commitData, |
| byte[] extraList) { |
| this.data = commitData; |
| this.extraList = extraList; |
| this.hashLength = hashLength; |
| this.commitDataLength = hashLength + COMMIT_DATA_WIDTH; |
| } |
| |
| /** |
| * Get the metadata of a commit。 |
| * |
| * @param graphPos |
| * the position in the commit-graph of the object. |
| * @return the metadata of a commit or null if not found. |
| */ |
| CommitData getCommitData(int graphPos) { |
| int dataIdx = commitDataLength * graphPos; |
| |
| // parse tree |
| ObjectId tree = ObjectId.fromRaw(data, dataIdx); |
| |
| // parse date |
| long dateHigh = NB.decodeUInt32(data, dataIdx + hashLength + 8) & 0x3; |
| long dateLow = NB.decodeUInt32(data, dataIdx + hashLength + 12); |
| long commitTime = dateHigh << 32 | dateLow; |
| |
| // parse generation |
| int generation = NB.decodeInt32(data, dataIdx + hashLength + 8) >> 2; |
| |
| // parse first parent |
| int parent1 = NB.decodeInt32(data, dataIdx + hashLength); |
| if (parent1 == GRAPH_NO_PARENT) { |
| return new CommitDataImpl(tree, NO_PARENTS, commitTime, generation); |
| } |
| |
| // parse second parent |
| int parent2 = NB.decodeInt32(data, dataIdx + hashLength + 4); |
| if (parent2 == GRAPH_NO_PARENT) { |
| return new CommitDataImpl(tree, new int[] { parent1 }, commitTime, |
| generation); |
| } |
| |
| if ((parent2 & GRAPH_EXTRA_EDGES_NEEDED) == 0) { |
| return new CommitDataImpl(tree, new int[] { parent1, parent2 }, |
| commitTime, generation); |
| } |
| |
| // parse parents for octopus merge |
| return new CommitDataImpl(tree, |
| findParentsForOctopusMerge(parent1, |
| parent2 & GRAPH_EDGE_LAST_MASK), |
| commitTime, generation); |
| } |
| |
| private int[] findParentsForOctopusMerge(int parent1, int extraEdgePos) { |
| int maxOffset = extraList.length - 4; |
| int offset = extraEdgePos * 4; |
| if (offset < 0 || offset > maxOffset) { |
| throw new IllegalArgumentException(MessageFormat.format( |
| JGitText.get().invalidExtraEdgeListPosition, |
| Integer.valueOf(extraEdgePos))); |
| } |
| int[] pList = new int[32]; |
| pList[0] = parent1; |
| int count = 1; |
| int parentPosition; |
| for (; offset <= maxOffset; offset += 4) { |
| if (count >= pList.length) { |
| // expand the pList |
| pList = Arrays.copyOf(pList, pList.length + 32); |
| } |
| parentPosition = NB.decodeInt32(extraList, offset); |
| if ((parentPosition & GRAPH_LAST_EDGE) != 0) { |
| pList[count++] = parentPosition & GRAPH_EDGE_LAST_MASK; |
| break; |
| } |
| pList[count++] = parentPosition; |
| } |
| return Arrays.copyOf(pList, count); |
| } |
| |
| private static class CommitDataImpl implements CommitData { |
| |
| private final ObjectId tree; |
| |
| private final int[] parents; |
| |
| private final long commitTime; |
| |
| private final int generation; |
| |
| public CommitDataImpl(ObjectId tree, int[] parents, long commitTime, |
| int generation) { |
| this.tree = tree; |
| this.parents = parents; |
| this.commitTime = commitTime; |
| this.generation = generation; |
| } |
| |
| @Override |
| public ObjectId getTree() { |
| return tree; |
| } |
| |
| @Override |
| public int[] getParents() { |
| return parents; |
| } |
| |
| @Override |
| public long getCommitTime() { |
| return commitTime; |
| } |
| |
| @Override |
| public int getGeneration() { |
| return generation; |
| } |
| } |
| } |