/* * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2008, Marek Zawirski 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.storage.pack; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BIGFILE_THRESHOLD; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_CONTIGUOUS_COMMIT_COUNT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_EXCESSIVE_BRANCH_COUNT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_INACTIVE_BRANCH_AGE_INDAYS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BITMAP_RECENT_COMMIT_COUNT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BUILD_BITMAPS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_COMPRESSION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CUT_DELTACHAINS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DELTA_CACHE_LIMIT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DELTA_CACHE_SIZE; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DELTA_COMPRESSION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DEPTH; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_INDEXVERSION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_MIN_SIZE_PREVENT_RACYPACK; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_REUSE_DELTAS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_REUSE_OBJECTS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_SEARCH_FOR_REUSE_TIMEOUT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_SINGLE_PACK; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_THREADS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WAIT_PREVENT_RACYPACK; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WINDOW; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WINDOW_MEMORY; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION; import java.time.Duration; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; import org.eclipse.jgit.internal.storage.file.PackIndexWriter; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Repository; /** * Configuration used by a pack writer when constructing the stream. * * A configuration may be modified once created, but should not be modified * while it is being used by a PackWriter. If a configuration is not modified it * is safe to share the same configuration instance between multiple concurrent * threads executing different PackWriters. */ public class PackConfig { /** * Default value of deltas reuse option: {@value} * * @see #setReuseDeltas(boolean) */ public static final boolean DEFAULT_REUSE_DELTAS = true; /** * Default value of objects reuse option: {@value} * * @see #setReuseObjects(boolean) */ public static final boolean DEFAULT_REUSE_OBJECTS = true; /** * Default value of keep old packs option: {@value} * @see #setPreserveOldPacks(boolean) * @since 4.7 */ public static final boolean DEFAULT_PRESERVE_OLD_PACKS = false; /** * Default value of prune old packs option: {@value} * @see #setPrunePreserved(boolean) * @since 4.7 */ public static final boolean DEFAULT_PRUNE_PRESERVED = false; /** * Default value of delta compress option: {@value} * * @see #setDeltaCompress(boolean) */ public static final boolean DEFAULT_DELTA_COMPRESS = true; /** * Default value of delta base as offset option: {@value} * * @see #setDeltaBaseAsOffset(boolean) */ public static final boolean DEFAULT_DELTA_BASE_AS_OFFSET = false; /** * Default value of maximum delta chain depth: {@value} * * @see #setMaxDeltaDepth(int) */ public static final int DEFAULT_MAX_DELTA_DEPTH = 50; /** * Default window size during packing: {@value} * * @see #setDeltaSearchWindowSize(int) */ public static final int DEFAULT_DELTA_SEARCH_WINDOW_SIZE = 10; private static final int MB = 1 << 20; /** * Default big file threshold: {@value} * * @see #setBigFileThreshold(int) */ public static final int DEFAULT_BIG_FILE_THRESHOLD = 50 * MB; /** * Default if we wait before opening a newly written pack to prevent its * lastModified timestamp could be racy * * @since 5.1.8 */ public static final boolean DEFAULT_WAIT_PREVENT_RACY_PACK = false; /** * Default if we wait before opening a newly written pack to prevent its * lastModified timestamp could be racy * * @since 5.1.8 */ public static final long DEFAULT_MINSIZE_PREVENT_RACY_PACK = 100 * MB; /** * Default delta cache size: {@value} * * @see #setDeltaCacheSize(long) */ public static final long DEFAULT_DELTA_CACHE_SIZE = 50 * 1024 * 1024; /** * Default delta cache limit: {@value} * * @see #setDeltaCacheLimit(int) */ public static final int DEFAULT_DELTA_CACHE_LIMIT = 100; /** * Default index version: {@value} * * @see #setIndexVersion(int) */ public static final int DEFAULT_INDEX_VERSION = 2; /** * Default value of the build bitmaps option: {@value} * * @see #setBuildBitmaps(boolean) * @since 3.0 */ public static final boolean DEFAULT_BUILD_BITMAPS = true; /** * Default count of most recent commits to select for bitmaps. Only applies * when bitmaps are enabled: {@value} * * @see #setBitmapContiguousCommitCount(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT = 100; /** * Count at which the span between selected commits changes from * "bitmapRecentCommitSpan" to "bitmapDistantCommitSpan". Only applies when * bitmaps are enabled: {@value} * * @see #setBitmapRecentCommitCount(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_RECENT_COMMIT_COUNT = 20000; /** * Default spacing between commits in recent history when selecting commits * for bitmaps. Only applies when bitmaps are enabled: {@value} * * @see #setBitmapRecentCommitSpan(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_RECENT_COMMIT_SPAN = 100; /** * Default spacing between commits in distant history when selecting commits * for bitmaps. Only applies when bitmaps are enabled: {@value} * * @see #setBitmapDistantCommitSpan(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_DISTANT_COMMIT_SPAN = 5000; /** * Default count of branches required to activate inactive branch commit * selection. If the number of branches is less than this then bitmaps for * the entire commit history of all branches will be created, otherwise * branches marked as "inactive" will have coverage for only partial * history: {@value} * * @see #setBitmapExcessiveBranchCount(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT = 100; /** * Default age at which a branch is considered inactive. Age is taken as the * number of days ago that the most recent commit was made to a branch. Only * affects bitmap processing if bitmaps are enabled and the * "excessive branch count" has been exceeded: {@value} * * @see #setBitmapInactiveBranchAgeInDays(int) * @since 4.2 */ public static final int DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS = 90; /** * Default max time to spend during the search for reuse phase. This * optimization is disabled by default: {@value} * * @see #setSearchForReuseTimeout(Duration) * @since 5.13 */ public static final Duration DEFAULT_SEARCH_FOR_REUSE_TIMEOUT = Duration .ofSeconds(Integer.MAX_VALUE); private int compressionLevel = Deflater.DEFAULT_COMPRESSION; private boolean reuseDeltas = DEFAULT_REUSE_DELTAS; private boolean reuseObjects = DEFAULT_REUSE_OBJECTS; private boolean preserveOldPacks = DEFAULT_PRESERVE_OLD_PACKS; private boolean prunePreserved = DEFAULT_PRUNE_PRESERVED; private boolean deltaBaseAsOffset = DEFAULT_DELTA_BASE_AS_OFFSET; private boolean deltaCompress = DEFAULT_DELTA_COMPRESS; private int maxDeltaDepth = DEFAULT_MAX_DELTA_DEPTH; private int deltaSearchWindowSize = DEFAULT_DELTA_SEARCH_WINDOW_SIZE; private long deltaSearchMemoryLimit; private long deltaCacheSize = DEFAULT_DELTA_CACHE_SIZE; private int deltaCacheLimit = DEFAULT_DELTA_CACHE_LIMIT; private int bigFileThreshold = DEFAULT_BIG_FILE_THRESHOLD; private boolean waitPreventRacyPack = DEFAULT_WAIT_PREVENT_RACY_PACK; private long minSizePreventRacyPack = DEFAULT_MINSIZE_PREVENT_RACY_PACK; private int threads; private Executor executor; private int indexVersion = DEFAULT_INDEX_VERSION; private boolean buildBitmaps = DEFAULT_BUILD_BITMAPS; private int bitmapContiguousCommitCount = DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT; private int bitmapRecentCommitCount = DEFAULT_BITMAP_RECENT_COMMIT_COUNT; private int bitmapRecentCommitSpan = DEFAULT_BITMAP_RECENT_COMMIT_SPAN; private int bitmapDistantCommitSpan = DEFAULT_BITMAP_DISTANT_COMMIT_SPAN; private int bitmapExcessiveBranchCount = DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT; private int bitmapInactiveBranchAgeInDays = DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS; private Duration searchForReuseTimeout = DEFAULT_SEARCH_FOR_REUSE_TIMEOUT; private boolean cutDeltaChains; private boolean singlePack; /** * Create a default configuration. */ public PackConfig() { // Fields are initialized to defaults. } /** * Create a configuration honoring the repository's settings. * * @param db * the repository to read settings from. The repository is not * retained by the new configuration, instead its settings are * copied during the constructor. */ public PackConfig(Repository db) { fromConfig(db.getConfig()); } /** * Create a configuration honoring settings in a * {@link org.eclipse.jgit.lib.Config}. * * @param cfg * the source to read settings from. The source is not retained * by the new configuration, instead its settings are copied * during the constructor. */ public PackConfig(Config cfg) { fromConfig(cfg); } /** * Copy an existing configuration to a new instance. * * @param cfg * the source configuration to copy from. */ public PackConfig(PackConfig cfg) { this.compressionLevel = cfg.compressionLevel; this.reuseDeltas = cfg.reuseDeltas; this.reuseObjects = cfg.reuseObjects; this.preserveOldPacks = cfg.preserveOldPacks; this.prunePreserved = cfg.prunePreserved; this.deltaBaseAsOffset = cfg.deltaBaseAsOffset; this.deltaCompress = cfg.deltaCompress; this.maxDeltaDepth = cfg.maxDeltaDepth; this.deltaSearchWindowSize = cfg.deltaSearchWindowSize; this.deltaSearchMemoryLimit = cfg.deltaSearchMemoryLimit; this.deltaCacheSize = cfg.deltaCacheSize; this.deltaCacheLimit = cfg.deltaCacheLimit; this.bigFileThreshold = cfg.bigFileThreshold; this.waitPreventRacyPack = cfg.waitPreventRacyPack; this.minSizePreventRacyPack = cfg.minSizePreventRacyPack; this.threads = cfg.threads; this.executor = cfg.executor; this.indexVersion = cfg.indexVersion; this.buildBitmaps = cfg.buildBitmaps; this.bitmapContiguousCommitCount = cfg.bitmapContiguousCommitCount; this.bitmapRecentCommitCount = cfg.bitmapRecentCommitCount; this.bitmapRecentCommitSpan = cfg.bitmapRecentCommitSpan; this.bitmapDistantCommitSpan = cfg.bitmapDistantCommitSpan; this.bitmapExcessiveBranchCount = cfg.bitmapExcessiveBranchCount; this.bitmapInactiveBranchAgeInDays = cfg.bitmapInactiveBranchAgeInDays; this.cutDeltaChains = cfg.cutDeltaChains; this.singlePack = cfg.singlePack; this.searchForReuseTimeout = cfg.searchForReuseTimeout; } /** * Check whether to reuse deltas existing in repository. * * Default setting: {@value #DEFAULT_REUSE_DELTAS} * * @return true if object is configured to reuse deltas; false otherwise. */ public boolean isReuseDeltas() { return reuseDeltas; } /** * Set reuse deltas configuration option for the writer. * * When enabled, writer will search for delta representation of object in * repository and use it if possible. Normally, only deltas with base to * another object existing in set of objects to pack will be used. The * exception however is thin-packs where the base object may exist on the * other side. * * When raw delta data is directly copied from a pack file, its checksum is * computed to verify the data is not corrupt. * * Default setting: {@value #DEFAULT_REUSE_DELTAS} * * @param reuseDeltas * boolean indicating whether or not try to reuse deltas. */ public void setReuseDeltas(boolean reuseDeltas) { this.reuseDeltas = reuseDeltas; } /** * Checks whether to reuse existing objects representation in repository. * * Default setting: {@value #DEFAULT_REUSE_OBJECTS} * * @return true if writer is configured to reuse objects representation from * pack; false otherwise. */ public boolean isReuseObjects() { return reuseObjects; } /** * Set reuse objects configuration option for the writer. * * If enabled, writer searches for compressed representation in a pack file. * If possible, compressed data is directly copied from such a pack file. * Data checksum is verified. * * Default setting: {@value #DEFAULT_REUSE_OBJECTS} * * @param reuseObjects * boolean indicating whether or not writer should reuse existing * objects representation. */ public void setReuseObjects(boolean reuseObjects) { this.reuseObjects = reuseObjects; } /** * Checks whether to preserve old packs in a preserved directory * * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} * * @return true if repacking will preserve old pack files. * @since 4.7 */ public boolean isPreserveOldPacks() { return preserveOldPacks; } /** * Set preserve old packs configuration option for repacking. * * If enabled, old pack files are moved into a preserved subdirectory instead * of being deleted * * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} * * @param preserveOldPacks * boolean indicating whether or not preserve old pack files * @since 4.7 */ public void setPreserveOldPacks(boolean preserveOldPacks) { this.preserveOldPacks = preserveOldPacks; } /** * Checks whether to remove preserved pack files in a preserved directory * * Default setting: {@value #DEFAULT_PRUNE_PRESERVED} * * @return true if repacking will remove preserved pack files. * @since 4.7 */ public boolean isPrunePreserved() { return prunePreserved; } /** * Set prune preserved configuration option for repacking. * * If enabled, preserved pack files are removed from a preserved subdirectory * * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} * * @param prunePreserved * boolean indicating whether or not preserve old pack files * @since 4.7 */ public void setPrunePreserved(boolean prunePreserved) { this.prunePreserved = prunePreserved; } /** * True if writer can use offsets to point to a delta base. * * If true the writer may choose to use an offset to point to a delta base * in the same pack, this is a newer style of reference that saves space. * False if the writer has to use the older (and more compatible style) of * storing the full ObjectId of the delta base. * * Default setting: {@value #DEFAULT_DELTA_BASE_AS_OFFSET} * * @return true if delta base is stored as an offset; false if it is stored * as an ObjectId. */ public boolean isDeltaBaseAsOffset() { return deltaBaseAsOffset; } /** * Set writer delta base format. * * Delta base can be written as an offset in a pack file (new approach * reducing file size) or as an object id (legacy approach, compatible with * old readers). * * Default setting: {@value #DEFAULT_DELTA_BASE_AS_OFFSET} * * @param deltaBaseAsOffset * boolean indicating whether delta base can be stored as an * offset. */ public void setDeltaBaseAsOffset(boolean deltaBaseAsOffset) { this.deltaBaseAsOffset = deltaBaseAsOffset; } /** * Check whether the writer will create new deltas on the fly. * * Default setting: {@value #DEFAULT_DELTA_COMPRESS} * * @return true if the writer will create a new delta when either * {@link #isReuseDeltas()} is false, or no suitable delta is * available for reuse. */ public boolean isDeltaCompress() { return deltaCompress; } /** * Set whether or not the writer will create new deltas on the fly. * * Default setting: {@value #DEFAULT_DELTA_COMPRESS} * * @param deltaCompress * true to create deltas when {@link #isReuseDeltas()} is false, * or when a suitable delta isn't available for reuse. Set to * false to write whole objects instead. */ public void setDeltaCompress(boolean deltaCompress) { this.deltaCompress = deltaCompress; } /** * Get maximum depth of delta chain set up for the writer. * * Generated chains are not longer than this value. * * Default setting: {@value #DEFAULT_MAX_DELTA_DEPTH} * * @return maximum delta chain depth. */ public int getMaxDeltaDepth() { return maxDeltaDepth; } /** * Set up maximum depth of delta chain for the writer. * * Generated chains are not longer than this value. Too low value causes low * compression level, while too big makes unpacking (reading) longer. * * Default setting: {@value #DEFAULT_MAX_DELTA_DEPTH} * * @param maxDeltaDepth * maximum delta chain depth. */ public void setMaxDeltaDepth(int maxDeltaDepth) { this.maxDeltaDepth = maxDeltaDepth; } /** * Whether existing delta chains should be cut at * {@link #getMaxDeltaDepth()}. * * @return true if existing delta chains should be cut at * {@link #getMaxDeltaDepth()}. Default is false, allowing existing * chains to be of any length. * @since 3.0 */ public boolean getCutDeltaChains() { return cutDeltaChains; } /** * Enable cutting existing delta chains at {@link #getMaxDeltaDepth()}. * * By default this is disabled and existing chains are kept at whatever * length a prior packer was configured to create. This allows objects to be * packed one with a large depth (for example 250), and later to quickly * repack the repository with a shorter depth (such as 50), but reusing the * complete delta chains created by the earlier 250 depth. * * @param cut * true to cut existing chains. * @since 3.0 */ public void setCutDeltaChains(boolean cut) { cutDeltaChains = cut; } /** * Whether all of refs/* should be packed in a single pack. * * @return true if all of refs/* should be packed in a single pack. Default * is false, packing a separate GC_REST pack for references outside * of refs/heads/* and refs/tags/*. * @since 4.9 */ public boolean getSinglePack() { return singlePack; } /** * If {@code true}, packs a single GC pack for all objects reachable from * refs/*. Otherwise packs the GC pack with objects reachable from * refs/heads/* and refs/tags/*, and a GC_REST pack with the remaining * reachable objects. Disabled by default, packing GC and GC_REST. * * @param single * true to pack a single GC pack rather than GC and GC_REST packs * @since 4.9 */ public void setSinglePack(boolean single) { singlePack = single; } /** * Get the number of objects to try when looking for a delta base. * * This limit is per thread, if 4 threads are used the actual memory used * will be 4 times this value. * * Default setting: {@value #DEFAULT_DELTA_SEARCH_WINDOW_SIZE} * * @return the object count to be searched. */ public int getDeltaSearchWindowSize() { return deltaSearchWindowSize; } /** * Set the number of objects considered when searching for a delta base. * * Default setting: {@value #DEFAULT_DELTA_SEARCH_WINDOW_SIZE} * * @param objectCount * number of objects to search at once. Must be at least 2. */ public void setDeltaSearchWindowSize(int objectCount) { if (objectCount <= 2) setDeltaCompress(false); else deltaSearchWindowSize = objectCount; } /** * Get maximum number of bytes to put into the delta search window. * * Default setting is 0, for an unlimited amount of memory usage. Actual * memory used is the lower limit of either this setting, or the sum of * space used by at most {@link #getDeltaSearchWindowSize()} objects. * * This limit is per thread, if 4 threads are used the actual memory limit * will be 4 times this value. * * @return the memory limit. */ public long getDeltaSearchMemoryLimit() { return deltaSearchMemoryLimit; } /** * Set the maximum number of bytes to put into the delta search window. * * Default setting is 0, for an unlimited amount of memory usage. If the * memory limit is reached before {@link #getDeltaSearchWindowSize()} the * window size is temporarily lowered. * * @param memoryLimit * Maximum number of bytes to load at once, 0 for unlimited. */ public void setDeltaSearchMemoryLimit(long memoryLimit) { deltaSearchMemoryLimit = memoryLimit; } /** * Get the size of the in-memory delta cache. * * This limit is for the entire writer, even if multiple threads are used. * * Default setting: {@value #DEFAULT_DELTA_CACHE_SIZE} * * @return maximum number of bytes worth of delta data to cache in memory. * If 0 the cache is infinite in size (up to the JVM heap limit * anyway). A very tiny size such as 1 indicates the cache is * effectively disabled. */ public long getDeltaCacheSize() { return deltaCacheSize; } /** * Set the maximum number of bytes of delta data to cache. * * During delta search, up to this many bytes worth of small or hard to * compute deltas will be stored in memory. This cache speeds up writing by * allowing the cached entry to simply be dumped to the output stream. * * Default setting: {@value #DEFAULT_DELTA_CACHE_SIZE} * * @param size * number of bytes to cache. Set to 0 to enable an infinite * cache, set to 1 (an impossible size for any delta) to disable * the cache. */ public void setDeltaCacheSize(long size) { deltaCacheSize = size; } /** * Maximum size in bytes of a delta to cache. * * Default setting: {@value #DEFAULT_DELTA_CACHE_LIMIT} * * @return maximum size (in bytes) of a delta that should be cached. */ public int getDeltaCacheLimit() { return deltaCacheLimit; } /** * Set the maximum size of a delta that should be cached. * * During delta search, any delta smaller than this size will be cached, up * to the {@link #getDeltaCacheSize()} maximum limit. This speeds up writing * by allowing these cached deltas to be output as-is. * * Default setting: {@value #DEFAULT_DELTA_CACHE_LIMIT} * * @param size * maximum size (in bytes) of a delta to be cached. */ public void setDeltaCacheLimit(int size) { deltaCacheLimit = size; } /** * Get the maximum file size that will be delta compressed. * * Files bigger than this setting will not be delta compressed, as they are * more than likely already highly compressed binary data files that do not * delta compress well, such as MPEG videos. * * Default setting: {@value #DEFAULT_BIG_FILE_THRESHOLD} * * @return the configured big file threshold. */ public int getBigFileThreshold() { return bigFileThreshold; } /** * Set the maximum file size that should be considered for deltas. * * Default setting: {@value #DEFAULT_BIG_FILE_THRESHOLD} * * @param bigFileThreshold * the limit, in bytes. */ public void setBigFileThreshold(int bigFileThreshold) { this.bigFileThreshold = bigFileThreshold; } /** * Get whether we wait before opening a newly written pack to prevent its * lastModified timestamp could be racy * * @return whether we wait before opening a newly written pack to prevent * its lastModified timestamp could be racy * @since 5.1.8 */ public boolean isWaitPreventRacyPack() { return waitPreventRacyPack; } /** * Get whether we wait before opening a newly written pack to prevent its * lastModified timestamp could be racy. Returns {@code true} if * {@code waitToPreventRacyPack = true} and * {@code packSize > minSizePreventRacyPack}, {@code false} otherwise. * * @param packSize * size of the pack file * * @return whether we wait before opening a newly written pack to prevent * its lastModified timestamp could be racy * @since 5.1.8 */ public boolean doWaitPreventRacyPack(long packSize) { return isWaitPreventRacyPack() && packSize > getMinSizePreventRacyPack(); } /** * Set whether we wait before opening a newly written pack to prevent its * lastModified timestamp could be racy * * @param waitPreventRacyPack * whether we wait before opening a newly written pack to prevent * its lastModified timestamp could be racy * @since 5.1.8 */ public void setWaitPreventRacyPack(boolean waitPreventRacyPack) { this.waitPreventRacyPack = waitPreventRacyPack; } /** * Get minimum packfile size for which we wait before opening a newly * written pack to prevent its lastModified timestamp could be racy if * {@code isWaitToPreventRacyPack} is {@code true}. * * @return minimum packfile size, default is 100 MiB * * @since 5.1.8 */ public long getMinSizePreventRacyPack() { return minSizePreventRacyPack; } /** * Set minimum packfile size for which we wait before opening a newly * written pack to prevent its lastModified timestamp could be racy if * {@code isWaitToPreventRacyPack} is {@code true}. * * @param minSizePreventRacyPack * minimum packfile size, default is 100 MiB * * @since 5.1.8 */ public void setMinSizePreventRacyPack(long minSizePreventRacyPack) { this.minSizePreventRacyPack = minSizePreventRacyPack; } /** * Get the compression level applied to objects in the pack. * * Default setting: {@value java.util.zip.Deflater#DEFAULT_COMPRESSION} * * @return current compression level, see {@link java.util.zip.Deflater}. */ public int getCompressionLevel() { return compressionLevel; } /** * Set the compression level applied to objects in the pack. * * Default setting: {@value java.util.zip.Deflater#DEFAULT_COMPRESSION} * * @param level * compression level, must be a valid level recognized by the * {@link java.util.zip.Deflater} class. */ public void setCompressionLevel(int level) { compressionLevel = level; } /** * Get the number of threads used during delta compression. * * Default setting: 0 (auto-detect processors) * * @return number of threads used for delta compression. 0 will auto-detect * the threads to the number of available processors. */ public int getThreads() { return threads; } /** * Set the number of threads to use for delta compression. * * During delta compression, if there are enough objects to be considered * the writer will start up concurrent threads and allow them to compress * different sections of the repository concurrently. * * An application thread pool can be set by {@link #setExecutor(Executor)}. * If not set a temporary pool will be created by the writer, and torn down * automatically when compression is over. * * Default setting: 0 (auto-detect processors) * * @param threads * number of threads to use. If <= 0 the number of available * processors for this JVM is used. */ public void setThreads(int threads) { this.threads = threads; } /** * Get the preferred thread pool to execute delta search on. * * @return the preferred thread pool to execute delta search on. */ public Executor getExecutor() { return executor; } /** * Set the executor to use when using threads. * * During delta compression if the executor is non-null jobs will be queued * up on it to perform delta compression in parallel. Aside from setting the * executor, the caller must set {@link #setThreads(int)} to enable threaded * delta search. * * @param executor * executor to use for threads. Set to null to create a temporary * executor just for the writer. */ public void setExecutor(Executor executor) { this.executor = executor; } /** * Get the pack index file format version this instance creates. * * Default setting: {@value #DEFAULT_INDEX_VERSION} * * @return the index version, the special version 0 designates the oldest * (most compatible) format available for the objects. * @see PackIndexWriter */ public int getIndexVersion() { return indexVersion; } /** * Set the pack index file format version this instance will create. * * Default setting: {@value #DEFAULT_INDEX_VERSION} * * @param version * the version to write. The special version 0 designates the * oldest (most compatible) format available for the objects. * @see PackIndexWriter */ public void setIndexVersion(int version) { indexVersion = version; } /** * True if writer is allowed to build bitmaps for indexes. * * Default setting: {@value #DEFAULT_BUILD_BITMAPS} * * @return true if delta base is the writer can choose to output an index * with bitmaps. * @since 3.0 */ public boolean isBuildBitmaps() { return buildBitmaps; } /** * Set writer to allow building bitmaps for supported pack files. * * Index files can include bitmaps to speed up future ObjectWalks. * * Default setting: {@value #DEFAULT_BUILD_BITMAPS} * * @param buildBitmaps * boolean indicating whether bitmaps may be included in the * index. * @since 3.0 */ public void setBuildBitmaps(boolean buildBitmaps) { this.buildBitmaps = buildBitmaps; } /** * Get the count of most recent commits for which to build bitmaps. * * Default setting: {@value #DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT} * * @return the count of most recent commits for which to build bitmaps * @since 4.2 */ public int getBitmapContiguousCommitCount() { return bitmapContiguousCommitCount; } /** * Set the count of most recent commits for which to build bitmaps. * * Default setting: {@value #DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT} * * @param count * the count of most recent commits for which to build bitmaps * @since 4.2 */ public void setBitmapContiguousCommitCount(int count) { bitmapContiguousCommitCount = count; } /** * Get the count at which to switch from "bitmapRecentCommitSpan" to * "bitmapDistantCommitSpan". * * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_COUNT} * * @return the count for switching between recent and distant spans * @since 4.2 */ public int getBitmapRecentCommitCount() { return bitmapRecentCommitCount; } /** * Set the count at which to switch from "bitmapRecentCommitSpan" to * "bitmapDistantCommitSpan". * * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_COUNT} * * @param count * the count for switching between recent and distant spans * @since 4.2 */ public void setBitmapRecentCommitCount(int count) { bitmapRecentCommitCount = count; } /** * Get the span of commits when building bitmaps for recent history. * * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_SPAN} * * @return the span of commits when building bitmaps for recent history * @since 4.2 */ public int getBitmapRecentCommitSpan() { return bitmapRecentCommitSpan; } /** * Set the span of commits when building bitmaps for recent history. * * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_SPAN} * * @param span * the span of commits when building bitmaps for recent history * @since 4.2 */ public void setBitmapRecentCommitSpan(int span) { bitmapRecentCommitSpan = span; } /** * Get the span of commits when building bitmaps for distant history. * * Default setting: {@value #DEFAULT_BITMAP_DISTANT_COMMIT_SPAN} * * @return the span of commits when building bitmaps for distant history * @since 4.2 */ public int getBitmapDistantCommitSpan() { return bitmapDistantCommitSpan; } /** * Set the span of commits when building bitmaps for distant history. * * Default setting: {@value #DEFAULT_BITMAP_DISTANT_COMMIT_SPAN} * * @param span * the span of commits when building bitmaps for distant history * @since 4.2 */ public void setBitmapDistantCommitSpan(int span) { bitmapDistantCommitSpan = span; } /** * Get the count of branches deemed "excessive". If the count of branches in * a repository exceeds this number and bitmaps are enabled, "inactive" * branches will have fewer bitmaps than "active" branches. * * Default setting: {@value #DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT} * * @return the count of branches deemed "excessive" * @since 4.2 */ public int getBitmapExcessiveBranchCount() { return bitmapExcessiveBranchCount; } /** * Set the count of branches deemed "excessive". If the count of branches in * a repository exceeds this number and bitmaps are enabled, "inactive" * branches will have fewer bitmaps than "active" branches. * * Default setting: {@value #DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT} * * @param count * the count of branches deemed "excessive" * @since 4.2 */ public void setBitmapExcessiveBranchCount(int count) { bitmapExcessiveBranchCount = count; } /** * Get the age in days that marks a branch as "inactive". * * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS} * * @return the age in days that marks a branch as "inactive" * @since 4.2 */ public int getBitmapInactiveBranchAgeInDays() { return bitmapInactiveBranchAgeInDays; } /** * Get the max time to spend during the search for reuse phase. * * Default setting: {@value #DEFAULT_SEARCH_FOR_REUSE_TIMEOUT} * * @return the maximum time to spend during the search for reuse phase. * @since 5.13 */ public Duration getSearchForReuseTimeout() { return searchForReuseTimeout; } /** * Set the age in days that marks a branch as "inactive". * * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS} * * @param ageInDays * the age in days that marks a branch as "inactive" * @since 4.2 */ public void setBitmapInactiveBranchAgeInDays(int ageInDays) { bitmapInactiveBranchAgeInDays = ageInDays; } /** * Set the max time to spend during the search for reuse phase. * * @param timeout * max time allowed during the search for reuse phase * * Default setting: {@value #DEFAULT_SEARCH_FOR_REUSE_TIMEOUT} * @since 5.13 */ public void setSearchForReuseTimeout(Duration timeout) { searchForReuseTimeout = timeout; } /** * Update properties by setting fields from the configuration. * * If a property's corresponding variable is not defined in the supplied * configuration, then it is left unmodified. * * @param rc * configuration to read properties from. */ public void fromConfig(Config rc) { setMaxDeltaDepth(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_DEPTH, getMaxDeltaDepth())); setDeltaSearchWindowSize(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_WINDOW, getDeltaSearchWindowSize())); setDeltaSearchMemoryLimit(rc.getLong(CONFIG_PACK_SECTION, CONFIG_KEY_WINDOW_MEMORY, getDeltaSearchMemoryLimit())); setDeltaCacheSize(rc.getLong(CONFIG_PACK_SECTION, CONFIG_KEY_DELTA_CACHE_SIZE, getDeltaCacheSize())); setDeltaCacheLimit(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_DELTA_CACHE_LIMIT, getDeltaCacheLimit())); setCompressionLevel(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_COMPRESSION, rc.getInt(CONFIG_CORE_SECTION, CONFIG_KEY_COMPRESSION, getCompressionLevel()))); setIndexVersion(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_INDEXVERSION, getIndexVersion())); setBigFileThreshold(rc.getInt(CONFIG_CORE_SECTION, CONFIG_KEY_BIGFILE_THRESHOLD, getBigFileThreshold())); setThreads(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_THREADS, getThreads())); // These variables aren't standardized setReuseDeltas(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_REUSE_DELTAS, isReuseDeltas())); setReuseObjects(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_REUSE_OBJECTS, isReuseObjects())); setDeltaCompress(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_DELTA_COMPRESSION, isDeltaCompress())); setCutDeltaChains(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_CUT_DELTACHAINS, getCutDeltaChains())); setSinglePack(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_SINGLE_PACK, getSinglePack())); setBuildBitmaps(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_BUILD_BITMAPS, isBuildBitmaps())); setBitmapContiguousCommitCount(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_CONTIGUOUS_COMMIT_COUNT, getBitmapContiguousCommitCount())); setBitmapRecentCommitCount(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_RECENT_COMMIT_COUNT, getBitmapRecentCommitCount())); setBitmapRecentCommitSpan(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_RECENT_COMMIT_COUNT, getBitmapRecentCommitSpan())); setBitmapDistantCommitSpan(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_DISTANT_COMMIT_SPAN, getBitmapDistantCommitSpan())); setBitmapExcessiveBranchCount(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_EXCESSIVE_BRANCH_COUNT, getBitmapExcessiveBranchCount())); setBitmapInactiveBranchAgeInDays(rc.getInt(CONFIG_PACK_SECTION, CONFIG_KEY_BITMAP_INACTIVE_BRANCH_AGE_INDAYS, getBitmapInactiveBranchAgeInDays())); setSearchForReuseTimeout(Duration.ofSeconds(rc.getTimeUnit( CONFIG_PACK_SECTION, null, CONFIG_KEY_SEARCH_FOR_REUSE_TIMEOUT, getSearchForReuseTimeout().getSeconds(), TimeUnit.SECONDS))); setWaitPreventRacyPack(rc.getBoolean(CONFIG_PACK_SECTION, CONFIG_KEY_WAIT_PREVENT_RACYPACK, isWaitPreventRacyPack())); setMinSizePreventRacyPack(rc.getLong(CONFIG_PACK_SECTION, CONFIG_KEY_MIN_SIZE_PREVENT_RACYPACK, getMinSizePreventRacyPack())); } /** {@inheritDoc} */ @Override public String toString() { final StringBuilder b = new StringBuilder(); b.append("maxDeltaDepth=").append(getMaxDeltaDepth()); //$NON-NLS-1$ b.append(", deltaSearchWindowSize=").append(getDeltaSearchWindowSize()); //$NON-NLS-1$ b.append(", deltaSearchMemoryLimit=") //$NON-NLS-1$ .append(getDeltaSearchMemoryLimit()); b.append(", deltaCacheSize=").append(getDeltaCacheSize()); //$NON-NLS-1$ b.append(", deltaCacheLimit=").append(getDeltaCacheLimit()); //$NON-NLS-1$ b.append(", compressionLevel=").append(getCompressionLevel()); //$NON-NLS-1$ b.append(", indexVersion=").append(getIndexVersion()); //$NON-NLS-1$ b.append(", bigFileThreshold=").append(getBigFileThreshold()); //$NON-NLS-1$ b.append(", threads=").append(getThreads()); //$NON-NLS-1$ b.append(", reuseDeltas=").append(isReuseDeltas()); //$NON-NLS-1$ b.append(", reuseObjects=").append(isReuseObjects()); //$NON-NLS-1$ b.append(", deltaCompress=").append(isDeltaCompress()); //$NON-NLS-1$ b.append(", buildBitmaps=").append(isBuildBitmaps()); //$NON-NLS-1$ b.append(", bitmapContiguousCommitCount=") //$NON-NLS-1$ .append(getBitmapContiguousCommitCount()); b.append(", bitmapRecentCommitCount=") //$NON-NLS-1$ .append(getBitmapRecentCommitCount()); b.append(", bitmapRecentCommitSpan=") //$NON-NLS-1$ .append(getBitmapRecentCommitSpan()); b.append(", bitmapDistantCommitSpan=") //$NON-NLS-1$ .append(getBitmapDistantCommitSpan()); b.append(", bitmapExcessiveBranchCount=") //$NON-NLS-1$ .append(getBitmapExcessiveBranchCount()); b.append(", bitmapInactiveBranchAge=") //$NON-NLS-1$ .append(getBitmapInactiveBranchAgeInDays()); b.append(", searchForReuseTimeout") //$NON-NLS-1$ .append(getSearchForReuseTimeout()); b.append(", singlePack=").append(getSinglePack()); //$NON-NLS-1$ return b.toString(); } }