Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 8bfeecf

Browse files
committed
Fix possible deadlock due to blocking on pool waits
1 parent 28c1cc5 commit 8bfeecf

File tree

1 file changed

+81
-34
lines changed

1 file changed

+81
-34
lines changed

src/main/java/com/launchdarkly/client/RedisFeatureStore.java

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.google.common.cache.LoadingCache;
66
import com.google.gson.Gson;
77
import com.google.gson.reflect.TypeToken;
8-
import org.apache.http.util.EntityUtils;
98
import redis.clients.jedis.Jedis;
109
import redis.clients.jedis.JedisPool;
1110
import redis.clients.jedis.JedisPoolConfig;
@@ -39,7 +38,7 @@ public class RedisFeatureStore implements FeatureStore {
3938
* @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
4039
*/
4140
public RedisFeatureStore(String host, int port, String prefix, long cacheTimeSecs) {
42-
pool = new JedisPool(new JedisPoolConfig(), host, port);
41+
pool = new JedisPool(getPoolConfig(), host, port);
4342
setPrefix(prefix);
4443
createCache(cacheTimeSecs);
4544
createInitCache(cacheTimeSecs);
@@ -53,7 +52,7 @@ public RedisFeatureStore(String host, int port, String prefix, long cacheTimeSec
5352
* @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
5453
*/
5554
public RedisFeatureStore(URI uri, String prefix, long cacheTimeSecs) {
56-
pool = new JedisPool(new JedisPoolConfig(), uri);
55+
pool = new JedisPool(getPoolConfig(), uri);
5756
setPrefix(prefix);
5857
createCache(cacheTimeSecs);
5958
createInitCache(cacheTimeSecs);
@@ -64,7 +63,7 @@ public RedisFeatureStore(URI uri, String prefix, long cacheTimeSecs) {
6463
*
6564
*/
6665
public RedisFeatureStore() {
67-
pool = new JedisPool(new JedisPoolConfig(), "localhost");
66+
pool = new JedisPool(getPoolConfig(), "localhost");
6867
this.prefix = DEFAULT_PREFIX;
6968
}
7069

@@ -131,18 +130,26 @@ public FeatureRep<?> get(String key) {
131130
*/
132131
@Override
133132
public Map<String, FeatureRep<?>> all() {
134-
Map<String,String> featuresJson = jedis().hgetAll(featuresKey());
135-
Map<String, FeatureRep<?>> result = new HashMap<String, FeatureRep<?>>();
136-
Gson gson = new Gson();
133+
Jedis jedis = null;
134+
try {
135+
jedis = getJedis();
136+
Map<String,String> featuresJson = getJedis().hgetAll(featuresKey());
137+
Map<String, FeatureRep<?>> result = new HashMap<String, FeatureRep<?>>();
138+
Gson gson = new Gson();
137139

138-
Type type = new TypeToken<FeatureRep<?>>() {}.getType();
140+
Type type = new TypeToken<FeatureRep<?>>() {}.getType();
139141

140-
for (Map.Entry<String, String> entry : featuresJson.entrySet()) {
141-
FeatureRep<?> rep = gson.fromJson(entry.getValue(), type);
142-
result.put(entry.getKey(), rep);
142+
for (Map.Entry<String, String> entry : featuresJson.entrySet()) {
143+
FeatureRep<?> rep = gson.fromJson(entry.getValue(), type);
144+
result.put(entry.getKey(), rep);
145+
}
146+
return result;
147+
} finally {
148+
if (jedis != null) {
149+
jedis.close();
150+
}
143151
}
144152

145-
return result;
146153
}
147154
/**
148155
* Initializes (or re-initializes) the store with the specified set of features. Any existing entries
@@ -152,17 +159,25 @@ public Map<String, FeatureRep<?>> all() {
152159
*/
153160
@Override
154161
public void init(Map<String, FeatureRep<?>> features) {
155-
Jedis jedis = jedis();
156-
Gson gson = new Gson();
157-
Transaction t = jedis.multi();
162+
Jedis jedis = null;
158163

159-
t.del(featuresKey());
164+
try {
165+
jedis = getJedis();
166+
Gson gson = new Gson();
167+
Transaction t = jedis.multi();
160168

161-
for (FeatureRep<?> f: features.values()) {
162-
t.hset(featuresKey(), f.key, gson.toJson(f));
163-
}
169+
t.del(featuresKey());
164170

165-
t.exec();
171+
for (FeatureRep<?> f: features.values()) {
172+
t.hset(featuresKey(), f.key, gson.toJson(f));
173+
}
174+
175+
t.exec();
176+
} finally {
177+
if (jedis != null) {
178+
jedis.close();
179+
}
180+
}
166181
}
167182

168183

@@ -176,8 +191,9 @@ public void init(Map<String, FeatureRep<?>> features) {
176191
*/
177192
@Override
178193
public void delete(String key, int version) {
179-
Jedis jedis = jedis();
194+
Jedis jedis = null;
180195
try {
196+
jedis = getJedis();
181197
Gson gson = new Gson();
182198
jedis.watch(featuresKey());
183199

@@ -197,7 +213,10 @@ public void delete(String key, int version) {
197213
}
198214
}
199215
finally {
200-
jedis.unwatch();
216+
if (jedis != null) {
217+
jedis.unwatch();
218+
jedis.close();
219+
}
201220
}
202221

203222
}
@@ -211,8 +230,9 @@ public void delete(String key, int version) {
211230
*/
212231
@Override
213232
public void upsert(String key, FeatureRep<?> feature) {
214-
Jedis jedis = jedis();
233+
Jedis jedis = null;
215234
try {
235+
jedis = getJedis();
216236
Gson gson = new Gson();
217237
jedis.watch(featuresKey());
218238

@@ -229,7 +249,10 @@ public void upsert(String key, FeatureRep<?> feature) {
229249
}
230250
}
231251
finally {
232-
jedis.unwatch();
252+
if (jedis != null) {
253+
jedis.unwatch();
254+
jedis.close();
255+
}
233256
}
234257
}
235258

@@ -267,24 +290,48 @@ private String featuresKey() {
267290
}
268291

269292
private Boolean getInit() {
270-
return jedis().exists(featuresKey());
293+
Jedis jedis = null;
294+
295+
try {
296+
jedis = getJedis();
297+
return jedis.exists(featuresKey());
298+
} finally {
299+
if (jedis != null) {
300+
jedis.close();
301+
}
302+
}
271303
}
272304

273305
private FeatureRep<?> getRedis(String key) {
274-
Gson gson = new Gson();
275-
String featureJson = jedis().hget(featuresKey(), key);
306+
Jedis jedis = null;
307+
try {
308+
jedis = getJedis();
309+
Gson gson = new Gson();
310+
String featureJson = getJedis().hget(featuresKey(), key);
276311

277-
if (featureJson == null) {
278-
return null;
279-
}
312+
if (featureJson == null) {
313+
return null;
314+
}
280315

281-
Type type = new TypeToken<FeatureRep<?>>() {}.getType();
282-
FeatureRep<?> f = gson.fromJson(featureJson, type);
316+
Type type = new TypeToken<FeatureRep<?>>() {}.getType();
317+
FeatureRep<?> f = gson.fromJson(featureJson, type);
283318

284-
return f.deleted ? null : f;
319+
return f.deleted ? null : f;
320+
} finally {
321+
if (jedis != null) {
322+
jedis.close();
323+
}
324+
}
285325
}
286326

287-
private final Jedis jedis() {
327+
private final Jedis getJedis() {
288328
return pool.getResource();
289329
}
330+
331+
private final JedisPoolConfig getPoolConfig() {
332+
JedisPoolConfig config = new JedisPoolConfig();
333+
config.setMaxTotal(256);
334+
config.setBlockWhenExhausted(false);
335+
return config;
336+
}
290337
}

0 commit comments

Comments
 (0)