Skip to content

Commit

Permalink
merged SavedKey shared between Inmemory and Hazelcast ratelimiters
Browse files Browse the repository at this point in the history
  • Loading branch information
mokies committed Apr 16, 2017
1 parent a067155 commit bb22832
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 54 deletions.
1 change: 1 addition & 0 deletions ratelimitj-hazelcast/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {

implementation(
project(':ratelimitj-core'),
project(':ratelimitj-inmemory'),
'com.hazelcast:hazelcast:3.6.3',
libraries.slf4j,
libraries.findbugs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import es.moki.ratelimitj.core.api.RateLimiter;
import es.moki.ratelimitj.core.time.SystemTimeSupplier;
import es.moki.ratelimitj.core.time.TimeSupplier;
import es.moki.ratelimitj.inmemory.SavedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.concurrent.ThreadSafe;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;

import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -136,23 +136,4 @@ private IMap<String, Long> getMap(String key, int longestDuration) {
return hz.getMap(key);
}

private static class SavedKey {
final long blockId;
final long blocks;
final long trimBefore;
final String countKey;
final String tsKey;

SavedKey(long now, int duration, OptionalInt precisionOpt) {

int precision = precisionOpt.orElse(duration);
precision = Math.min(precision, duration);

this.blocks = (long) Math.ceil(duration / (double) precision);
this.blockId = (long) Math.floor(now / (double) precision);
this.trimBefore = blockId - blocks + 1;
this.countKey = "" + duration + ':' + precision + ':';
this.tsKey = countKey + 'o';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

import javax.annotation.concurrent.ThreadSafe;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

import static es.moki.ratelimitj.core.RateLimitUtils.coalesce;
Expand All @@ -28,7 +28,7 @@ public class InMemorySlidingWindowRateLimiter implements RateLimiter {

private final Set<LimitRule> rules;
private final TimeSupplier timeSupplier;
private final ExpiringMap<String, Map<String, Long>> expiryingKeyMap;
private final ExpiringMap<String, ConcurrentMap<String, Long>> expiryingKeyMap;

public InMemorySlidingWindowRateLimiter(Set<LimitRule> rules) {
this(rules, new SystemTimeSupplier());
Expand All @@ -40,7 +40,7 @@ public InMemorySlidingWindowRateLimiter(Set<LimitRule> rules, TimeSupplier timeS
this.expiryingKeyMap = ExpiringMap.builder().variableExpiration().build();
}

InMemorySlidingWindowRateLimiter(ExpiringMap<String, Map<String, Long>> expiryingKeyMap, Set<LimitRule> rules, TimeSupplier timeSupplier) {
InMemorySlidingWindowRateLimiter(ExpiringMap<String, ConcurrentMap<String, Long>> expiryingKeyMap, Set<LimitRule> rules, TimeSupplier timeSupplier) {
this.expiryingKeyMap = expiryingKeyMap;
this.rules = rules;
this.timeSupplier = timeSupplier;
Expand Down Expand Up @@ -119,8 +119,9 @@ public boolean overLimit(String key, int weight) {
for (SavedKey savedKey : savedKeys) {
//update the current timestamp, count, and bucket count
keyMap.put(savedKey.tsKey, savedKey.trimBefore);
// TODO should this ben just compute

Long computedCountKeyValue = keyMap.compute(savedKey.countKey, (k, v) -> coalesce(v, 0L) + weight);

Long computedCountKeyBlockIdValue = keyMap.compute(savedKey.countKey + savedKey.blockId, (k, v) -> coalesce(v, 0L)+ weight);

if (LOG.isDebugEnabled()) {
Expand All @@ -137,33 +138,15 @@ public boolean resetLimit(String key) {
throw new RuntimeException("Not implemented");
}

private Map<String, Long> getMap(String key, int longestDuration) {
Map<String, Long> keyMap = expiryingKeyMap.get(key);
// FIXME we have some threading issues to deal with
if (keyMap == null) {
keyMap = new HashMap<>();
expiryingKeyMap.put(key, keyMap, ExpirationPolicy.CREATED, longestDuration, TimeUnit.SECONDS);
private ConcurrentMap<String, Long> getMap(String key, int longestDuration) {
synchronized (key) {
ConcurrentMap<String, Long> keyMap = expiryingKeyMap.get(key);
if (keyMap == null) {
keyMap = new ConcurrentHashMap<>();
expiryingKeyMap.put(key, keyMap, ExpirationPolicy.CREATED, longestDuration, TimeUnit.SECONDS);
}
return keyMap;
}
return keyMap;
}

private static class SavedKey {
final long blockId;
final long blocks;
final long trimBefore;
final String countKey;
final String tsKey;

SavedKey(long now, int duration, OptionalInt precisionOpt) {

int precision = precisionOpt.orElse(duration);
precision = Math.min(precision, duration);

this.blocks = (long) Math.ceil(duration / (double) precision);
this.blockId = (long) Math.floor(now / (double) precision);
this.trimBefore = blockId - blocks + 1;
this.countKey = "" + duration + ':' + precision + ':';
this.tsKey = countKey + 'o';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package es.moki.ratelimitj.inmemory;

import java.util.OptionalInt;

public class SavedKey {

public final long blockId;
public final long blocks;
public final long trimBefore;
public final String countKey;
public final String tsKey;

public SavedKey(long now, int duration, OptionalInt precisionOpt) {

int precision = precisionOpt.orElse(duration);
precision = Math.min(precision, duration);

this.blocks = (long) Math.ceil(duration / (double) precision);
this.blockId = (long) Math.floor(now / (double) precision);
this.trimBefore = blockId - blocks + 1;
this.countKey = "" + duration + ':' + precision + ':';
this.tsKey = countKey + 'o';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

public class InMemorySlidingWindowSyncRateLimiterTest extends AbstractSyncRateLimiterTest {


@BeforeAll
public static void before() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import com.google.common.collect.ImmutableSet;
import es.moki.ratelimitj.core.api.LimitRule;
import es.moki.ratelimitj.core.api.RateLimiter;
import es.moki.ratelimitj.test.time.TimeBanditSupplier;
import es.moki.ratelimitj.core.time.TimeSupplier;
import es.moki.ratelimitj.test.time.TimeBanditSupplier;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.NumberFormat;
import java.util.Locale;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -41,7 +43,8 @@ public void shouldLimitDualWindowSyncTimed() throws Exception {
});

double transactionsPerSecond = Math.ceil((double) total / watch.elapsed(TimeUnit.MILLISECONDS) * 1000);
log.info("total time {} checks {}/sec", watch.stop(), transactionsPerSecond);

log.info("total time {} checks {}/sec", watch.stop(), NumberFormat.getNumberInstance(Locale.US).format(transactionsPerSecond));
}

}

0 comments on commit bb22832

Please sign in to comment.