-
-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2638 from ebean-orm/feature/TenantAwareCache
Refactor L2 cache tenant awareness - add TenantAwareCache
- Loading branch information
Showing
14 changed files
with
314 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
ebean-api/src/main/java/io/ebean/cache/TenantAwareCache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package io.ebean.cache; | ||
|
||
import io.ebean.meta.MetricVisitor; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* A ServerCache proxy that is tenant aware. | ||
*/ | ||
public final class TenantAwareCache implements ServerCache { | ||
|
||
private final ServerCache delegate; | ||
private final TenantAwareKey tenantAwareKey; | ||
|
||
/** | ||
* Create given the TenantAwareKey and delegate cache to proxy to. | ||
* | ||
* @param delegate The cache to proxy to | ||
* @param tenantAwareKey Provides tenant aware keys to use in the cache | ||
*/ | ||
public TenantAwareCache(ServerCache delegate, TenantAwareKey tenantAwareKey) { | ||
this.delegate = delegate; | ||
this.tenantAwareKey = tenantAwareKey; | ||
} | ||
|
||
/** | ||
* Return the underlying ServerCache that is being delegated to. | ||
*/ | ||
@Override | ||
public <T> T unwrap(Class<T> cls) { | ||
return (T)delegate; | ||
} | ||
|
||
@Override | ||
public void visit(MetricVisitor visitor) { | ||
delegate.visit(visitor); | ||
} | ||
|
||
private Object key(Object key) { | ||
return tenantAwareKey.key(key); | ||
} | ||
|
||
@Override | ||
public Object get(Object id) { | ||
return delegate.get(key(id)); | ||
} | ||
|
||
@Override | ||
public void put(Object id, Object value) { | ||
delegate.put(key(id), value); | ||
} | ||
|
||
@Override | ||
public void remove(Object id) { | ||
delegate.remove(key(id)); | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
delegate.clear(); | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return delegate.size(); | ||
} | ||
|
||
@Override | ||
public int getHitRatio() { | ||
return delegate.getHitRatio(); | ||
} | ||
|
||
@Override | ||
public ServerCacheStatistics getStatistics(boolean reset) { | ||
return delegate.getStatistics(reset); | ||
} | ||
|
||
@Override | ||
public Map<Object, Object> getAll(Set<Object> keys) { | ||
Map<Object, Object> keyMapping = new HashMap<>(keys.size()); | ||
keys.forEach(k -> keyMapping.put(key(k), k)); | ||
Map<Object, Object> tmp = delegate.getAll(keyMapping.keySet()); | ||
Map<Object, Object> ret = new HashMap<>(keys.size()); | ||
// unwrap tenant info here | ||
tmp.forEach((k,v)-> ret.put(((TenantAwareKey.CacheKey) k).key, v)); | ||
return ret; | ||
} | ||
|
||
@Override | ||
public void putAll(Map<Object, Object> keyValues) { | ||
Map<Object, Object> tmp = new HashMap<>(); | ||
keyValues.forEach((k, v) -> tmp.put(key(k), v)); | ||
delegate.putAll(tmp); | ||
} | ||
|
||
@Override | ||
public void removeAll(Set<Object> keys) { | ||
delegate.removeAll(keys.stream().map(this::key).collect(Collectors.toSet())); | ||
} | ||
|
||
} |
122 changes: 122 additions & 0 deletions
122
ebean-api/src/test/java/io/ebean/cache/TenantAwareCacheTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package io.ebean.cache; | ||
|
||
import io.ebean.cache.TenantAwareKey.CacheKey; | ||
import io.ebean.config.CurrentTenantProvider; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
class TenantAwareCacheTest { | ||
|
||
ServerCache serverCache; | ||
TenantAwareCache cache; | ||
|
||
TenantAwareCacheTest() { | ||
TenantAwareKey key = new TenantAwareKey(new TenantProv()); | ||
this.serverCache = new Cache(); | ||
this.cache = new TenantAwareCache(serverCache, key); | ||
} | ||
|
||
@Test | ||
void put_get_remove() { | ||
cache.put("A", "a"); | ||
Object val = cache.get("A"); | ||
assertThat(val).isEqualTo("a"); | ||
|
||
CacheKey cacheKey = new CacheKey("A", 42); | ||
Object val2 = serverCache.get(cacheKey); | ||
assertThat(val2).isEqualTo("a"); | ||
|
||
cache.put("B", "bb"); | ||
assertThat(cache.size()).isEqualTo(2); | ||
cache.remove("A"); | ||
assertThat(cache.get("A")).isNull(); | ||
assertThat(cache.size()).isEqualTo(1); | ||
|
||
cache.clear(); | ||
assertThat(cache.size()).isEqualTo(0); | ||
assertThat(cache.get("B")).isNull(); | ||
} | ||
|
||
@Test | ||
void putAll_getAll_removeAll() { | ||
Map<Object,Object> map = new HashMap<>(); | ||
map.put("A", "a"); | ||
map.put("B", "b"); | ||
map.put("C", "c"); | ||
|
||
cache.putAll(map); | ||
assertThat(cache.size()).isEqualTo(3); | ||
assertThat(cache.get("A")).isEqualTo("a"); | ||
assertThat(serverCache.get(new CacheKey("A", 42))).isEqualTo("a"); | ||
|
||
|
||
Map<Object, Object> result = cache.getAll(Set.of("A", "B", "C", "D")); | ||
assertThat(result).hasSize(3); | ||
assertThat(result).containsOnlyKeys("A", "B", "C"); | ||
assertThat(result.values()).containsOnly("a", "b", "c"); | ||
|
||
cache.removeAll(Set.of("A", "C", "D")); | ||
assertThat(cache.size()).isEqualTo(1); | ||
|
||
assertThat(cache.get("B")).isEqualTo("b"); | ||
assertThat(serverCache.get(new CacheKey("B", 42))).isEqualTo("b"); | ||
|
||
cache.remove("B"); | ||
assertThat(cache.size()).isEqualTo(0); | ||
} | ||
|
||
|
||
static class TenantProv implements CurrentTenantProvider { | ||
|
||
@Override | ||
public Object currentId() { | ||
return 42; | ||
} | ||
} | ||
|
||
static class Cache implements ServerCache { | ||
|
||
Map<Object, Object> map = new ConcurrentHashMap<>(); | ||
|
||
@Override | ||
public Object get(Object id) { | ||
return map.get(id); | ||
} | ||
|
||
@Override | ||
public void put(Object id, Object value) { | ||
map.put(id, value); | ||
} | ||
|
||
@Override | ||
public void remove(Object id) { | ||
map.remove(id); | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
map.clear(); | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return map.size(); | ||
} | ||
|
||
@Override | ||
public int getHitRatio() { | ||
return 0; | ||
} | ||
|
||
@Override | ||
public ServerCacheStatistics getStatistics(boolean reset) { | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.