package com.atlassian.bitbucket.mesh.git.gc;

import com.atlassian.bitbucket.mesh.repository.Repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;

public interface GarbageCollectionManager {

    /**
     * Performs garbage collection.
     * <p>
     * There are two specific and separate garbage collections that can occur here which are:
     * <ul>
     *     <li>Pruning stale objects</li>
     *     <li>Ref changes</li>
     * </ul>
     * Pruning stale objects can occur due to a tmp_pack_* file that may be left in the objects/pack directory of the
     * mirror from sync issues. To avoid a buildup of these files, we try to cleanup stale tmp_pack_* files after every
     * failed fetch.
     * <p>
     * With regard to garbage collection on ref changes we perform a number of operations such as:
     * <ul>
     *     <li>pack-refs</li>
     *     <li>repack</li>
     *     <li>prune</li>
     *     <li>commit-graph</li>
     * </ul>
     * all of which are dependent on various time intervals.
     *
     * @param parameters parameters describing garbage collection state
     */
    void collectGarbage(@Nonnull GarbageCollectionParameters parameters);

    /**
     * Pauses garbage collection for the provided repository. The caller <i>must</i> {@link GcPause#close close} the
     * return {@link GcPause} handle to resume garbage collection; {@link #resume} will not do so.
     *
     * @param repository the repository
     * @param timeout    the maximum amount of time to block while acquiring the GC lock for the repository in question
     * @return a {@link GcPause} handle, which can be used to resume GC, or {@code null} if GC could not be paused
     *         (most likely indicating GC processing is currently running)
     */
    @Nullable
    GcPause pause(@Nonnull Repository repository, @Nonnull Duration timeout);

    /**
     * Pauses garbage collection for the provided repository until it is {@link #resume resumed}.
     *
     * @param repository the repository
     * @param timeout    the maximum amount of time to block while acquiring the GC lock for the repository in question
     * @return {@code true} if garbage collection is paused; otherwise, {@code false} if GC could not be paused (most
     *         likely indicating GC processing is currently running)
     */
    boolean pauseIndefinitely(@Nonnull Repository repository, @Nonnull Duration timeout);

    /**
     * Resumes garbage collection for the provided repository after an {@link #pauseIndefinitely indefinite pause}.
     *
     * @param repository the repository
     * @return {@code true} if garbage collection is enabled after the method returns; otherwise, {@code false} if
     *         the GC lock could not be released
     */
    boolean resume(@Nonnull Repository repository);
}
