com.bazaarvoice.emodb.databus.db.generic.CachingSubscriptionDAO Maven / Gradle / Ivy
package com.bazaarvoice.emodb.databus.db.generic;
import com.bazaarvoice.emodb.cachemgr.api.CacheHandle;
import com.bazaarvoice.emodb.cachemgr.api.CacheRegistry;
import com.bazaarvoice.emodb.cachemgr.api.InvalidationScope;
import com.bazaarvoice.emodb.databus.api.Subscription;
import com.bazaarvoice.emodb.databus.db.SubscriptionDAO;
import com.bazaarvoice.emodb.sor.condition.Condition;
import com.google.common.base.Function;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import org.joda.time.Duration;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Wraps a {@link SubscriptionDAO} with a cache that makes it fast and efficient to lookup subscription metadata. The
* downside is that servers must globally coordinate changes to subscriptions because the consequences of using
* out-of-date cached subscription metadata are pretty severe.
*/
public class CachingSubscriptionDAO implements SubscriptionDAO {
private static final String SUBSCRIPTIONS = "subscriptions";
private final SubscriptionDAO _delegate;
private final LoadingCache> _cache;
private final CacheHandle _cacheHandle;
@Inject
public CachingSubscriptionDAO(@CachingSubscriptionDAODelegate SubscriptionDAO delegate,
@CachingSubscriptionDAORegistry CacheRegistry cacheRegistry) {
_delegate = checkNotNull(delegate, "delegate");
// The subscription cache has only a single value. Use it for (a) expiration, (b) dropwizard cache clearing.
_cache = CacheBuilder.newBuilder().
expireAfterAccess(10, TimeUnit.MINUTES).
recordStats().
build(new CacheLoader>() {
@Override
public Map load(String ignored) throws Exception {
return indexByName(_delegate.getAllSubscriptions());
}
});
_cacheHandle = cacheRegistry.register("subscriptions", _cache, true);
}
private Map indexByName(Collection subscriptions) {
return Maps.uniqueIndex(subscriptions, new Function() {
@Override
public String apply(Subscription subscription) {
return subscription.getName();
}
});
}
@Override
public void insertSubscription(String subscription, Condition tableFilter, Duration subscriptionTtl, Duration eventTtl) {
_delegate.insertSubscription(subscription, tableFilter, subscriptionTtl, eventTtl);
// Synchronously tell every other server in the cluster to forget what it has cached about subscriptions.
_cacheHandle.invalidate(InvalidationScope.DATA_CENTER, SUBSCRIPTIONS);
}
@Override
public void deleteSubscription(String subscription) {
_delegate.deleteSubscription(subscription);
// Synchronously tell every other server in the cluster to forget what it has cached about subscriptions.
_cacheHandle.invalidate(InvalidationScope.DATA_CENTER, SUBSCRIPTIONS);
}
@Override
public Subscription getSubscription(String subscription) {
return _cache.getUnchecked(SUBSCRIPTIONS).get(subscription);
}
@Override
public Collection getAllSubscriptions() {
return _cache.getUnchecked(SUBSCRIPTIONS).values();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy