
com.launchdarkly.client.integrations.RedisDataStoreImpl Maven / Gradle / Ivy
package com.launchdarkly.client.integrations;
import com.google.common.annotations.VisibleForTesting;
import com.launchdarkly.client.VersionedData;
import com.launchdarkly.client.VersionedDataKind;
import com.launchdarkly.client.utils.FeatureStoreCore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.launchdarkly.client.utils.FeatureStoreHelpers.marshalJson;
import static com.launchdarkly.client.utils.FeatureStoreHelpers.unmarshalJson;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction;
import redis.clients.util.JedisURIHelper;
final class RedisDataStoreImpl implements FeatureStoreCore {
private static final Logger logger = LoggerFactory.getLogger(RedisDataStoreImpl.class);
private final JedisPool pool;
private final String prefix;
private UpdateListener updateListener;
RedisDataStoreImpl(RedisDataStoreBuilder builder) {
// There is no builder for JedisPool, just a large number of constructor overloads. Unfortunately,
// the overloads that accept a URI do not accept the other parameters we need to set, so we need
// to decompose the URI.
String host = builder.uri.getHost();
int port = builder.uri.getPort();
String password = builder.password == null ? JedisURIHelper.getPassword(builder.uri) : builder.password;
int database = builder.database == null ? JedisURIHelper.getDBIndex(builder.uri): builder.database.intValue();
boolean tls = builder.tls || builder.uri.getScheme().equals("rediss");
String extra = tls ? " with TLS" : "";
if (password != null) {
extra = extra + (extra.isEmpty() ? " with" : " and") + " password";
}
logger.info(String.format("Connecting to Redis feature store at %s:%d/%d%s", host, port, database, extra));
JedisPoolConfig poolConfig = (builder.poolConfig != null) ? builder.poolConfig : new JedisPoolConfig();
JedisPool pool = new JedisPool(poolConfig,
host,
port,
builder.connectTimeout,
builder.socketTimeout,
password,
database,
null, // clientName
tls,
null, // sslSocketFactory
null, // sslParameters
null // hostnameVerifier
);
String prefix = (builder.prefix == null || builder.prefix.isEmpty()) ?
RedisDataStoreBuilder.DEFAULT_PREFIX :
builder.prefix;
this.pool = pool;
this.prefix = prefix;
}
@Override
public VersionedData getInternal(VersionedDataKind> kind, String key) {
try (Jedis jedis = pool.getResource()) {
VersionedData item = getRedis(kind, key, jedis);
if (item != null) {
logger.debug("[get] Key: {} with version: {} found in \"{}\".", key, item.getVersion(), kind.getNamespace());
}
return item;
}
}
@Override
public Map getAllInternal(VersionedDataKind> kind) {
try (Jedis jedis = pool.getResource()) {
Map allJson = jedis.hgetAll(itemsKey(kind));
Map result = new HashMap<>();
for (Map.Entry entry : allJson.entrySet()) {
VersionedData item = unmarshalJson(kind, entry.getValue());
result.put(entry.getKey(), item);
}
return result;
}
}
@Override
public void initInternal(Map, Map> allData) {
try (Jedis jedis = pool.getResource()) {
Transaction t = jedis.multi();
for (Map.Entry, Map> entry: allData.entrySet()) {
String baseKey = itemsKey(entry.getKey());
t.del(baseKey);
for (VersionedData item: entry.getValue().values()) {
t.hset(baseKey, item.getKey(), marshalJson(item));
}
}
t.set(initedKey(), "");
t.exec();
}
}
@Override
public VersionedData upsertInternal(VersionedDataKind> kind, VersionedData newItem) {
while (true) {
Jedis jedis = null;
try {
jedis = pool.getResource();
String baseKey = itemsKey(kind);
jedis.watch(baseKey);
if (updateListener != null) {
updateListener.aboutToUpdate(baseKey, newItem.getKey());
}
VersionedData oldItem = getRedis(kind, newItem.getKey(), jedis);
if (oldItem != null && oldItem.getVersion() >= newItem.getVersion()) {
logger.debug("Attempted to {} key: {} version: {}" +
" with a version that is the same or older: {} in \"{}\"",
newItem.isDeleted() ? "delete" : "update",
newItem.getKey(), oldItem.getVersion(), newItem.getVersion(), kind.getNamespace());
return oldItem;
}
Transaction tx = jedis.multi();
tx.hset(baseKey, newItem.getKey(), marshalJson(newItem));
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy