@Override
    public long reservePermission(final int permits) {
        long timeoutInNanos = state.get().config.getTimeoutDuration().toNanos();
        State modifiedState = updateStateWithBackOff(permits, timeoutInNanos);

        boolean canAcquireImmediately = modifiedState.nanosToWait <= 0;
        if (canAcquireImmediately) {
            publishRateLimiterAcquisitionEvent(true, permits);
            return 0;
        }

        boolean canAcquireInTime = timeoutInNanos >= modifiedState.nanosToWait;
        if (canAcquireInTime) {
            publishRateLimiterAcquisitionEvent(true, permits);
            return modifiedState.nanosToWait;
        }

        publishRateLimiterAcquisitionEvent(false, permits);
        return -1;
    }
@Test
    public void reservePermissionsUpfront() throws Exception {
        final int limitForPeriod = 3;
        final int tasksNum = 9;
        Duration limitRefreshPeriod = Duration.ofMillis(10);
        Duration timeoutDuration = Duration.ofMillis(12);
        long cycleInNanos = limitRefreshPeriod.toNanos();

        setup(limitRefreshPeriod, timeoutDuration, limitForPeriod);
        setTimeOnNanos(cycleInNanos);

        ArrayList<Long> timesToWait = new ArrayList<>();
        for (int i = 0; i < tasksNum; i++) {
            setTimeOnNanos(cycleInNanos + i + 1);
            long timeToWait = rateLimiter.reservePermission(1);
            timesToWait.add(timeToWait);
        }
        then(timesToWait).containsExactly(
            0L, 0L, 0L,
            cycleInNanos - 4, cycleInNanos - 5, cycleInNanos - 6,
            -1L, -1L, -1L
        );
    }