class ThresholdBasedPruneStrategy implements LogPruneStrategy {

    @Override
    public synchronized LongStream findLogVersionsToDelete( long upToVersion )
    {
        if ( upToVersion == INITIAL_LOG_VERSION )
        {
            return LongStream.empty();
        }

        threshold.init();
        long upper = upToVersion - 1;
        boolean exceeded = false;
        while ( upper >= 0 )
        {
            File file = files.getLogFileForVersion( upper );
            if ( !fileSystem.fileExists( file ) )
            {
                // There aren't logs to prune anything. Just return
                return LongStream.empty();
            }

            if ( fileSystem.getFileSize( file ) > LOG_HEADER_SIZE &&
                    threshold.reached( file, upper, logFileInformation ) )
            {
                exceeded = true;
                break;
            }
            upper--;
        }

        if ( !exceeded )
        {
            return LongStream.empty();
        }

        // Find out which log is the earliest existing (lower bound to prune)
        long lower = upper;
        while ( fileSystem.fileExists( files.getLogFileForVersion( lower - 1 ) ) )
        {
            lower--;
        }

        /*
         * Here we make sure that at least one historical log remains behind, in addition of course to the
         * current one. This is in order to make sure that at least one transaction remains always available for
         * serving to whomever asks for it.
         * To illustrate, imagine that there is a threshold in place configured so that it enforces pruning of the
         * log file that was just rotated out (for example, a file size threshold that is misconfigured to be smaller
         * than the smallest log). In such a case, until the database commits a transaction there will be no
         * transactions present on disk, making impossible to serve any to whichever client might ask, leading to
         * errors on both sides of the conversation.
         * This if statement does nothing more complicated than checking if the next-to-last log would be pruned
         * and simply skipping it if so.
         */
        if ( upper == upToVersion - 1 )
        {
            upper--;
        }

        // The reason we delete from lower to upper is that if it crashes in the middle we can be sure that no holes
        // are created.
        // We create a closed range because we want to include the 'upper' log version as well. The check above ensures
        // we don't accidentally leave the database without any logs.
        return LongStream.rangeClosed( lower, upper );
    }

      ThresholdBasedPruneStrategy( FileSystemAbstraction fileSystem, LogFiles logFiles, Threshold threshold );

}