blob: 32830c3cf02ca8069ebcc8edc04a99718b16be17 [file] [log] [blame]
/*
* Copyright (C) 2023, Google LLC and others
*
* 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.file;
import static org.eclipse.jgit.internal.storage.file.PackReverseIndex.MAGIC;
import static org.eclipse.jgit.internal.storage.file.PackReverseIndex.VERSION_1;
import java.io.DataInput;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.text.MessageFormat;
import java.util.Arrays;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.io.SilentFileInputStream;
/**
* Factory for creating instances of {@link PackReverseIndex}.
*/
public final class PackReverseIndexFactory {
/**
* Create an in-memory pack reverse index by reading it from the given file
* if the file exists, or computing it from the given pack index if the file
* doesn't exist.
*
* @param idxFile
* the file to read the pack file from, if it exists
* @param objectCount
* the number of objects in the corresponding pack
* @param packIndexSupplier
* a function to lazily get the corresponding forward index
* @return the reverse index instance
* @throws IOException
* if reading from the file fails
*/
static PackReverseIndex openOrCompute(File idxFile, long objectCount,
PackBitmapIndex.SupplierWithIOException<PackIndex> packIndexSupplier)
throws IOException {
try (SilentFileInputStream fd = new SilentFileInputStream(idxFile)) {
return readFromFile(fd, objectCount, packIndexSupplier);
} catch (FileNotFoundException e) {
return computeFromIndex(packIndexSupplier.get());
} catch (IOException e) {
throw new IOException(
MessageFormat.format(JGitText.get().unreadablePackIndex,
idxFile.getAbsolutePath()),
e);
}
}
/**
* Compute an in-memory pack reverse index from the in-memory pack forward
* index. This computation uses insertion sort, which has a quadratic
* runtime on average.
*
* @param packIndex
* the forward index to compute from
* @return the reverse index instance
*/
public static PackReverseIndex computeFromIndex(PackIndex packIndex) {
return new PackReverseIndexComputed(packIndex);
}
/**
* Read an in-memory pack reverse index from the given input stream. This
* has a linear runtime.
*
* @param src
* the input stream to read the contents from
* @param objectCount
* the number of objects in the corresponding pack
* @param packIndexSupplier
* a function to lazily get the corresponding forward index
* @return the reverse index instance
* @throws IOException
* if reading from the input stream fails
*/
static PackReverseIndex readFromFile(InputStream src, long objectCount,
PackBitmapIndex.SupplierWithIOException<PackIndex> packIndexSupplier)
throws IOException {
final DigestInputStream digestIn = new DigestInputStream(src,
Constants.newMessageDigest());
final byte[] magic = new byte[MAGIC.length];
IO.readFully(digestIn, magic);
if (!Arrays.equals(magic, MAGIC)) {
throw new IOException(
MessageFormat.format(JGitText.get().expectedGot,
Arrays.toString(MAGIC), Arrays.toString(magic)));
}
DataInput dataIn = new SimpleDataInput(digestIn);
int version = dataIn.readInt();
switch (version) {
case VERSION_1:
return new PackReverseIndexV1(digestIn, objectCount,
packIndexSupplier);
default:
throw new IOException(MessageFormat.format(
JGitText.get().unsupportedPackReverseIndexVersion,
String.valueOf(version)));
}
}
}