blob: a15602a168cac48b40709a6287142bd35787434d [file] [log] [blame]
/*
* 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 org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.NB;
/**
* The index which are used by the commit-graph to:
* <ul>
* <li>Get the object in commit-graph by using a specific position.</li>
* <li>Get the position of a specific object in commit-graph.</li>
* </ul>
*/
class GraphObjectIndex {
private static final int FANOUT = 256;
private final int hashLength;
private final int[] fanoutTable;
private final byte[] oidLookup;
private final long commitCnt;
/**
* Initialize the GraphObjectIndex.
*
* @param hashLength
* length of object hash.
* @param oidFanout
* content of OID Fanout Chunk.
* @param oidLookup
* content of OID Lookup Chunk.
* @throws CommitGraphFormatException
* commit-graph file's format is different from we expected.
*/
GraphObjectIndex(int hashLength, @NonNull byte[] oidFanout,
@NonNull byte[] oidLookup) throws CommitGraphFormatException {
this.hashLength = hashLength;
this.oidLookup = oidLookup;
int[] table = new int[FANOUT];
long uint32;
for (int k = 0; k < table.length; k++) {
uint32 = NB.decodeUInt32(oidFanout, k * 4);
if (uint32 > Integer.MAX_VALUE) {
throw new CommitGraphFormatException(
JGitText.get().commitGraphFileIsTooLargeForJgit);
}
table[k] = (int) uint32;
}
this.fanoutTable = table;
this.commitCnt = table[FANOUT - 1];
}
/**
* Find the position in the commit-graph of the specified id.
*
* @param id
* the id for which the commit-graph position will be found.
* @return the commit-graph position or -1 if the object was not found.
*/
int findGraphPosition(AnyObjectId id) {
int levelOne = id.getFirstByte();
int high = fanoutTable[levelOne];
int low = 0;
if (levelOne > 0) {
low = fanoutTable[levelOne - 1];
}
while (low < high) {
int mid = (low + high) >>> 1;
int pos = objIdOffset(mid);
int cmp = id.compareTo(oidLookup, pos);
if (cmp < 0) {
high = mid;
} else if (cmp == 0) {
return mid;
} else {
low = mid + 1;
}
}
return -1;
}
/**
* Get the object at the commit-graph position.
*
* @param graphPos
* the position in the commit-graph of the object.
* @return the ObjectId or null if it's not found.
*/
ObjectId getObjectId(int graphPos) {
if (graphPos < 0 || graphPos >= commitCnt) {
return null;
}
return ObjectId.fromRaw(oidLookup, objIdOffset(graphPos));
}
long getCommitCnt() {
return commitCnt;
}
private int objIdOffset(int pos) {
return hashLength * pos;
}
}