class LearnerSnapshotThrottler {

    public LearnerSnapshot beginSnapshot(boolean essential)
            throws SnapshotThrottleException, InterruptedException {
        int snapshotNumber;

        synchronized (snapCountSyncObject) {
            if (!essential
                && timeoutMillis > 0
                && snapsInProgress >= maxConcurrentSnapshots) {
                long timestamp = Time.currentElapsedTime();
                do {
                    snapCountSyncObject.wait(timeoutMillis);
                } while (snapsInProgress >= maxConcurrentSnapshots
                         && timestamp + timeoutMillis < Time.currentElapsedTime());
            }

            if (essential || snapsInProgress < maxConcurrentSnapshots) {
                snapsInProgress++;
                snapshotNumber = snapsInProgress;
            } else {
                throw new SnapshotThrottleException(snapsInProgress + 1,
                                                    maxConcurrentSnapshots);
            }
        }

        return new LearnerSnapshot(this, snapshotNumber, essential);
    }

    public  LearnerSnapshotThrottler(int maxConcurrentSnapshots,
                                    long timeoutMillis);
    public  LearnerSnapshotThrottler(int maxConcurrentSnapshots);

}