/**
 * Copyright 2016 Palantir Technologies
 *
 * Licensed under the BSD-3 License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/BSD-3-Clause
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.palantir.timestamp;

import static java.util.concurrent.TimeUnit.MINUTES;

import static com.google.common.base.Preconditions.checkArgument;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.palantir.common.remoting.ServiceNotAvailableException;
import com.palantir.exception.PalantirInterruptedException;

public class AvailableTimestamps {
    static final long ALLOCATION_BUFFER_SIZE = 1000 * 1000;
    private static final long MINIMUM_BUFFER = ALLOCATION_BUFFER_SIZE / 2;
    private static final long MAX_TIMESTAMPS_TO_HAND_OUT = 10 * 1000;

    private static final Logger log = LoggerFactory.getLogger(AvailableTimestamps.class);

    private final LastReturnedTimestamp lastReturnedTimestamp;
    private final PersistentUpperLimit upperLimit;
    private Throwable previousAllocationFailure;

    public AvailableTimestamps(LastReturnedTimestamp lastReturnedTimestamp, PersistentUpperLimit upperLimit) {
        this.lastReturnedTimestamp = lastReturnedTimestamp;
        this.upperLimit = upperLimit;
    }

    public synchronized TimestampRange handOut(long numberToHandOut) {
        checkArgument(
                numberToHandOut <= MAX_TIMESTAMPS_TO_HAND_OUT,
                "Can only hand out %s timestamps at a time, but %s were requested",
                MAX_TIMESTAMPS_TO_HAND_OUT, numberToHandOut);

        return handOutTimestamp(lastHandedOut() + numberToHandOut);
    }

    private synchronized TimestampRange handOutTimestamp(long targetTimestamp) {
        checkArgument(
                targetTimestamp > lastHandedOut(),
                "Could not hand out timestamp '%s' as it was earlier than the last handed out timestamp: %s",
                targetTimestamp, lastHandedOut());

        TimestampRange rangeToHandOut = TimestampRange.createInclusiveRange(lastReturnedTimestamp.get() + 1, targetTimestamp);

        allocateEnoughTimestampsToHandOut(targetTimestamp);
        lastReturnedTimestamp.increaseToAtLeast(targetTimestamp);

        return rangeToHandOut;
    }

    private long lastHandedOut() {
        return lastReturnedTimestamp.get();
    }

    public synchronized void refreshBuffer() {
        long buffer = upperLimit.get() - lastReturnedTimestamp.get();

        if (buffer < MINIMUM_BUFFER || !upperLimit.hasIncreasedWithin(1, MINUTES)) {
            allocateEnoughTimestampsToHandOut(lastHandedOut() + ALLOCATION_BUFFER_SIZE);
        }
    }

    public synchronized void fastForwardTo(long newMinimum) {
        lastReturnedTimestamp.increaseToAtLeast(newMinimum);
        upperLimit.increaseToAtLeast(newMinimum + ALLOCATION_BUFFER_SIZE);
    }

    private void allocateEnoughTimestampsToHandOut(long timestamp) {
        try {
            upperLimit.increaseToAtLeast(timestamp);
        } catch(Throwable e) {
            handleAllocationFailure(e);
        }
    }

    private synchronized void handleAllocationFailure(Throwable newFailure) {
        Throwable oldFailure = previousAllocationFailure;
        previousAllocationFailure = newFailure;

        if (newFailure instanceof MultipleRunningTimestampServiceError) {
            throw new ServiceNotAvailableException("This server is no longer valid because another is running.", newFailure);
        }

        if (newFailure != null) {
            throw new RuntimeException("failed to allocate more timestamps", newFailure);
        }

        if (Thread.interrupted()) {
            Thread.currentThread().interrupt();
            throw new PalantirInterruptedException("Interrupted while waiting for timestamp allocation.");
        }

        if (oldFailure != null
                && newFailure.getClass().equals(oldFailure.getClass())) {
            // QA-75825: don't keep logging error if we keep failing to allocate.
            log.info("Throwable while allocating timestamps.", newFailure);
        } else {
            log.error("Throwable while allocating timestamps.", newFailure);
        }
    }
}

@@ -2800,36 +2800,24 @@
 ) - last
-ReturnedTimestamp.ge
+HandedOu
 t();%0A%0A  

Use private method consistently