diff options
Diffstat (limited to 'org.eclipse.jgit/src')
3 files changed, 225 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 28634cbc4d..518e0b7d9b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -868,6 +868,7 @@ public class JGitText extends TranslationBundle { /***/ public String unsupportedMark; /***/ public String unsupportedOperationNotAddAtEnd; /***/ public String unsupportedPackIndexVersion; + /***/ public String unsupportedPackReverseIndexVersion; /***/ public String unsupportedPackVersion; /***/ public String unsupportedReftableVersion; /***/ public String unsupportedRepositoryDescription; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriter.java new file mode 100644 index 0000000000..4c8417b115 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriter.java @@ -0,0 +1,149 @@ +/* + * 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 java.io.BufferedOutputStream; +import java.io.DataOutput; +import java.io.IOException; +import java.io.OutputStream; +import java.security.DigestOutputStream; +import java.text.MessageFormat; +import java.util.List; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.transport.PackedObjectInfo; + +/** + * Writes reverse index files conforming to the requested version. + * <p> + * The reverse index file format is specified at + * https://git-scm.com/docs/pack-format#_pack_rev_files_have_the_format. + */ +public abstract class PackReverseIndexWriter { + /** + * Magic bytes that uniquely identify git reverse index files. + */ + protected static byte[] MAGIC = { 'R', 'I', 'D', 'X' }; + + /** + * The first reverse index file version. + */ + protected static final int VERSION_1 = 1; + + /** + * Stream to write contents to while maintaining a checksum. + */ + protected final DigestOutputStream out; + + /** + * Stream to write primitive type contents to while maintaining a checksum. + */ + protected final DataOutput dataOutput; + + private static final int DEFAULT_VERSION = VERSION_1; + + /** + * Construct the components of a PackReverseIndexWriter that are shared + * between subclasses. + * + * @param dst + * the OutputStream that the instance will write contents to + */ + protected PackReverseIndexWriter(OutputStream dst) { + out = new DigestOutputStream( + dst instanceof BufferedOutputStream ? dst + : new BufferedOutputStream(dst), + Constants.newMessageDigest()); + dataOutput = new SimpleDataOutput(out); + } + + /** + * Create a writer instance for the default file format version. + * + * @param dst + * the OutputStream that contents will be written to + * @return the new writer instance + */ + public static PackReverseIndexWriter createWriter(OutputStream dst) { + return createWriter(dst, DEFAULT_VERSION); + } + + /** + * Create a writer instance for the specified file format version. + * + * @param dst + * the OutputStream that contents will be written to + * @param version + * the reverse index format version to write contents as + * @return the new writer instance + */ + public static PackReverseIndexWriter createWriter(OutputStream dst, + int version) { + if (version == VERSION_1) { + return new PackReverseIndexWriterV1(dst); + } + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().unsupportedPackReverseIndexVersion, + Integer.toString(version))); + } + + /** + * Write the contents of a reverse index file for the given objects. + * + * @param objectsByIndexPos + * the objects whose forward index file positions should be + * written, sorted by forward index file position (currently SHA1 + * ordering) + * @param packChecksum + * the checksum of the corresponding pack file + * @throws IOException + * if writing the output fails + */ + public void write( + List<? extends PackedObjectInfo> objectsByIndexPos, + byte[] packChecksum) throws IOException { + writeHeader(); + writeBody(objectsByIndexPos); + writeFooter(packChecksum); + out.flush(); + } + + /** + * Write the header of a reverse index file, usually the magic bytes and the + * file format version. + * + * @throws IOException + * if writing the output fails + */ + protected abstract void writeHeader() throws IOException; + + /** + * Write the body of a reverse index file, usually the forward index + * positions of the given objects, sorted by those objects' pack file + * offsets. + * + * @param objectsSortedByIndexPosition + * the objects whose forward index file positions should be + * written, sorted by forward index file position; not modified + * during method + * @throws IOException + * if writing the output fails + */ + protected abstract void writeBody( + List<? extends PackedObjectInfo> objectsSortedByIndexPosition) + throws IOException; + + private void writeFooter(byte[] packChecksum) throws IOException { + out.write(packChecksum); + byte[] selfChecksum = out.getMessageDigest().digest(); + out.write(selfChecksum); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriterV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriterV1.java new file mode 100644 index 0000000000..7630724d09 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexWriterV1.java @@ -0,0 +1,75 @@ +/* + * 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 java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.eclipse.jgit.transport.PackedObjectInfo; +import org.eclipse.jgit.util.IntList; +import org.eclipse.jgit.util.IntList.IntComparator; + +/** + * Writes reverse index files following the version 1 format. + * <p> + * The file format is specified at + * https://git-scm.com/docs/pack-format#_pack_rev_files_have_the_format. + */ +final class PackReverseIndexWriterV1 extends PackReverseIndexWriter { + private static final int OID_VERSION_SHA1 = 1; + + private static final int DEFAULT_OID_VERSION = OID_VERSION_SHA1; + + PackReverseIndexWriterV1(final OutputStream dst) { + super(dst); + } + + @Override + protected void writeHeader() throws IOException { + out.write(MAGIC); + dataOutput.writeInt(VERSION_1); + dataOutput.writeInt(DEFAULT_OID_VERSION); + } + + @Override + protected void writeBody(List<? extends PackedObjectInfo> objectsByIndexPos) + throws IOException { + IntList positionsByOffset = IntList.filledWithRange(0, + objectsByIndexPos.size()); + positionsByOffset + .sort(new IndexPositionsByOffsetComparator(objectsByIndexPos)); + + for (int i = 0; i < positionsByOffset.size(); i++) { + int indexPosition = positionsByOffset.get(i); + dataOutput.writeInt(indexPosition); + } + } + + private static class IndexPositionsByOffsetComparator + implements IntComparator { + private List<? extends PackedObjectInfo> objectsByIndexPos; + + private IndexPositionsByOffsetComparator( + List<? extends PackedObjectInfo> objectsByIndexPos) { + this.objectsByIndexPos = objectsByIndexPos; + } + + @Override + public int compare(int firstIndexPosition, int secondIndexPosition) { + return Long.compare(getOffset(firstIndexPosition), + getOffset(secondIndexPosition)); + } + + private long getOffset(int indexPosition) { + return objectsByIndexPos.get(indexPosition).getOffset(); + } + } +} |