package com.rubiconproject.oss.kv.util; import java.io.IOException; import java.util.Random; import java.util.concurrent.TimeUnit; import com.rubiconproject.oss.kv.KeyValueStoreException; import com.rubiconproject.oss.kv.backends.MemcachedKeyValueStore; public class MemcachedRateLimiter implements RateLimiter { private MemcachedKeyValueStore mcc; private String counterKey; private long exp; private long maxEvents; private boolean throwExceptionOnErrors = false; public MemcachedRateLimiter() { // create a psuedo-random string for the counter key Random r = new Random(); this.counterKey = "rate-limit-" + r.nextInt(Integer.MAX_VALUE); } public MemcachedRateLimiter(MemcachedKeyValueStore mcc) { this(); this.mcc = mcc; } public MemcachedRateLimiter(MemcachedKeyValueStore mcc, String counterKey) { this(); this.mcc = mcc; this.counterKey = counterKey; } public void setMemcached(MemcachedKeyValueStore mcc) { this.mcc = mcc; } public void setLimit(TimeUnit timeUnit, long count, long maxEvents) { // convert units * count to # of seconds for our expire time this.exp = TimeUnit.SECONDS.convert(count, timeUnit); this.maxEvents = maxEvents; } public boolean allowNextEvent() { return (getCounter() < maxEvents); } public void nextEvent() { try { long count = mcc.incr(counterKey, 1, 1, (int) exp); } catch (KeyValueStoreException e) { if (throwExceptionOnErrors) throw new RuntimeException(e); } } public long getCounter() { long count = 0; try { String s = (String) mcc.get(counterKey); if (s != null) { count = Long.parseLong(s); } } catch (KeyValueStoreException e) { if (throwExceptionOnErrors) throw new RuntimeException(e); } catch (IOException e) { if (throwExceptionOnErrors) throw new RuntimeException(e); } return count; } }