ShardedCounter { public boolean counterHasSpareCapacity(String resourceId) throws IOException { try { final CounterSnapshot counterSnapshot = getCounterSnapshot(resourceId); counterSnapshot.pickShardWithSpareCapacity(1); return true; } catch (CounterCapacityException e) { return false; } } ShardedCounter(Stats stats, CounterSnapshotFactory counterSnapshotFactory); boolean counterHasSpareCapacity(String resourceId); void updateCounter(StorageTransaction transaction, String counterId, long delta); static final int NUM_SHARDS; static final String KIND_COUNTER_LIMIT; static final String PROPERTY_LIMIT; static final String KIND_COUNTER_SHARD; static final String PROPERTY_SHARD_VALUE; static final String PROPERTY_SHARD_INDEX; static final String PROPERTY_COUNTER_ID; }
@Test public void testCounterHasSpareCapacity() throws IOException { assertEquals(0L, shardedCounter.getCounter(COUNTER_ID1)); storage.runInTransactionWithRetries(transaction -> { shardedCounter.updateLimit(transaction, COUNTER_ID1, 2); return null; }); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(true)); updateCounterInTransaction(COUNTER_ID1, 1L); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(true)); updateCounterInTransaction(COUNTER_ID1, 1L); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(false)); storage.runInTransactionWithRetries(transaction -> { shardedCounter.updateLimit(transaction, COUNTER_ID1, 3); return null; }); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(true)); updateCounterInTransaction(COUNTER_ID1, 1L); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(false)); storage.runInTransactionWithRetries(transaction -> { shardedCounter.updateLimit(transaction, COUNTER_ID1, 2); return null; }); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(false)); updateCounterInTransaction(COUNTER_ID1, -1L); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(false)); updateCounterInTransaction(COUNTER_ID1, -1L); shardedCounter.inMemSnapshot.invalidate(COUNTER_ID1); assertThat(shardedCounter.counterHasSpareCapacity(COUNTER_ID1), is(true)); }