package com.rubiconproject.oss.kv.backends; import java.io.IOException; import java.util.List; import java.util.Map; import com.rubiconproject.oss.kv.BaseManagedKeyValueStore; import com.rubiconproject.oss.kv.KeyValueStore; import com.rubiconproject.oss.kv.KeyValueStoreException; import com.rubiconproject.oss.kv.KeyValueStoreUnavailable; import com.rubiconproject.oss.kv.transcoder.Transcoder; import com.rubiconproject.oss.kv.util.RateLimiter; public class RateLimitingKeyValueStore extends BaseManagedKeyValueStore implements KeyValueStore { public static final String IDENTIFIER = "ratelimiting"; private KeyValueStore master; private RateLimiter readLimiter; private RateLimiter writeLimiter; public RateLimitingKeyValueStore() { } public RateLimitingKeyValueStore(KeyValueStore master, RateLimiter readLimiter, RateLimiter writeLimiter) { this.master = master; this.readLimiter = readLimiter; this.writeLimiter = writeLimiter; } public String getIdentifier() { return IDENTIFIER; } public void setMaster(KeyValueStore master) { this.master = master; } public void setReadRateLimiter(RateLimiter limiter) { this.readLimiter = limiter; } public void setWriteRateLimiter(RateLimiter limiter) { this.writeLimiter = limiter; } @Override public void start() throws IOException { super.start(); } @Override public void stop() { super.stop(); } public boolean exists(String key) throws KeyValueStoreException, IOException { assertReadable(); return master.exists(key); } public Object get(String key) throws KeyValueStoreException, IOException { assertReadable(); return master.get(key); } public Object get(String key, Transcoder transcoder) throws KeyValueStoreException, IOException { assertReadable(); return master.get(key, transcoder); } public Map<String, Object> getBulk(String... keys) throws KeyValueStoreException, IOException { assertReadable(); return master.getBulk(keys); } public Map<String, Object> getBulk(List<String> keys) throws KeyValueStoreException, IOException { assertReadable(); return master.getBulk(keys); } public Map<String, Object> getBulk(List<String> keys, Transcoder transcoder) throws KeyValueStoreException, IOException { assertReadable(); return master.getBulk(keys, transcoder); } public void set(String key, Object value) throws KeyValueStoreException, IOException { assertWriteable(); master.set(key, value); } public void set(String key, Object value, Transcoder transcoder) throws KeyValueStoreException, IOException { assertWriteable(); master.set(key, value, transcoder); } public void delete(String key) throws KeyValueStoreException, IOException { assertWriteable(); master.delete(key); } protected void assertWriteable() throws KeyValueStoreUnavailable { if (writeLimiter != null) { if (writeLimiter.allowNextEvent()) writeLimiter.nextEvent(); else throw new KeyValueStoreUnavailable(); } super.assertWriteable(); } protected void assertReadable() throws KeyValueStoreUnavailable { if (readLimiter != null) { if (readLimiter.allowNextEvent()) readLimiter.nextEvent(); else throw new KeyValueStoreUnavailable(); } super.assertReadable(); } }