55import com .google .common .cache .LoadingCache ;
66import com .google .gson .Gson ;
77import com .google .gson .reflect .TypeToken ;
8- import org .apache .http .util .EntityUtils ;
98import redis .clients .jedis .Jedis ;
9+ import redis .clients .jedis .JedisPool ;
10+ import redis .clients .jedis .JedisPoolConfig ;
1011import redis .clients .jedis .Transaction ;
1112
13+ import java .io .IOException ;
1214import java .lang .reflect .Type ;
1315import java .net .URI ;
1416import java .util .HashMap ;
2224 */
2325public class RedisFeatureStore implements FeatureStore {
2426 private static final String DEFAULT_PREFIX = "launchdarkly" ;
25- private final Jedis jedis ;
27+ private final JedisPool pool ;
2628 private LoadingCache <String , FeatureRep <?>> cache ;
2729 private LoadingCache <String , Boolean > initCache ;
2830 private String prefix ;
@@ -36,7 +38,7 @@ public class RedisFeatureStore implements FeatureStore {
3638 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
3739 */
3840 public RedisFeatureStore (String host , int port , String prefix , long cacheTimeSecs ) {
39- jedis = new Jedis ( host , port );
41+ pool = new JedisPool ( getPoolConfig (), host , port );
4042 setPrefix (prefix );
4143 createCache (cacheTimeSecs );
4244 createInitCache (cacheTimeSecs );
@@ -50,7 +52,7 @@ public RedisFeatureStore(String host, int port, String prefix, long cacheTimeSec
5052 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
5153 */
5254 public RedisFeatureStore (URI uri , String prefix , long cacheTimeSecs ) {
53- jedis = new Jedis ( uri );
55+ pool = new JedisPool ( getPoolConfig (), uri );
5456 setPrefix (prefix );
5557 createCache (cacheTimeSecs );
5658 createInitCache (cacheTimeSecs );
@@ -61,7 +63,7 @@ public RedisFeatureStore(URI uri, String prefix, long cacheTimeSecs) {
6163 *
6264 */
6365 public RedisFeatureStore () {
64- jedis = new Jedis ( "localhost" );
66+ pool = new JedisPool ( getPoolConfig (), "localhost" );
6567 this .prefix = DEFAULT_PREFIX ;
6668 }
6769
@@ -128,18 +130,26 @@ public FeatureRep<?> get(String key) {
128130 */
129131 @ Override
130132 public Map <String , FeatureRep <?>> all () {
131- Map <String ,String > featuresJson = jedis .hgetAll (featuresKey ());
132- Map <String , FeatureRep <?>> result = new HashMap <String , FeatureRep <?>>();
133- 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 ();
134139
135- Type type = new TypeToken <FeatureRep <?>>() {}.getType ();
140+ Type type = new TypeToken <FeatureRep <?>>() {}.getType ();
136141
137- for (Map .Entry <String , String > entry : featuresJson .entrySet ()) {
138- FeatureRep <?> rep = gson .fromJson (entry .getValue (), type );
139- 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+ }
140151 }
141152
142- return result ;
143153 }
144154 /**
145155 * Initializes (or re-initializes) the store with the specified set of features. Any existing entries
@@ -149,16 +159,25 @@ public Map<String, FeatureRep<?>> all() {
149159 */
150160 @ Override
151161 public void init (Map <String , FeatureRep <?>> features ) {
152- Gson gson = new Gson ();
153- Transaction t = jedis .multi ();
162+ Jedis jedis = null ;
154163
155- t .del (featuresKey ());
164+ try {
165+ jedis = getJedis ();
166+ Gson gson = new Gson ();
167+ Transaction t = jedis .multi ();
156168
157- for (FeatureRep <?> f : features .values ()) {
158- t .hset (featuresKey (), f .key , gson .toJson (f ));
159- }
169+ t .del (featuresKey ());
160170
161- 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+ }
162181 }
163182
164183
@@ -172,7 +191,9 @@ public void init(Map<String, FeatureRep<?>> features) {
172191 */
173192 @ Override
174193 public void delete (String key , int version ) {
194+ Jedis jedis = null ;
175195 try {
196+ jedis = getJedis ();
176197 Gson gson = new Gson ();
177198 jedis .watch (featuresKey ());
178199
@@ -192,7 +213,10 @@ public void delete(String key, int version) {
192213 }
193214 }
194215 finally {
195- jedis .unwatch ();
216+ if (jedis != null ) {
217+ jedis .unwatch ();
218+ jedis .close ();
219+ }
196220 }
197221
198222 }
@@ -206,7 +230,9 @@ public void delete(String key, int version) {
206230 */
207231 @ Override
208232 public void upsert (String key , FeatureRep <?> feature ) {
233+ Jedis jedis = null ;
209234 try {
235+ jedis = getJedis ();
210236 Gson gson = new Gson ();
211237 jedis .watch (featuresKey ());
212238
@@ -223,7 +249,10 @@ public void upsert(String key, FeatureRep<?> feature) {
223249 }
224250 }
225251 finally {
226- jedis .unwatch ();
252+ if (jedis != null ) {
253+ jedis .unwatch ();
254+ jedis .close ();
255+ }
227256 }
228257 }
229258
@@ -245,26 +274,64 @@ public boolean initialized() {
245274 return getInit ();
246275 }
247276
277+ /**
278+ * Releases all resources associated with the store. The store must no longer be used once closed.
279+ * @throws IOException
280+ */
281+ public void close () throws IOException
282+ {
283+ pool .destroy ();
284+ }
285+
286+
248287
249288 private String featuresKey () {
250289 return prefix + ":features" ;
251290 }
252291
253292 private Boolean getInit () {
254- 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+ }
255303 }
256304
257305 private FeatureRep <?> getRedis (String key ) {
258- Gson gson = new Gson ();
259- 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 );
311+
312+ if (featureJson == null ) {
313+ return null ;
314+ }
315+
316+ Type type = new TypeToken <FeatureRep <?>>() {}.getType ();
317+ FeatureRep <?> f = gson .fromJson (featureJson , type );
260318
261- if (featureJson == null ) {
262- return null ;
319+ return f .deleted ? null : f ;
320+ } finally {
321+ if (jedis != null ) {
322+ jedis .close ();
323+ }
263324 }
325+ }
264326
265- Type type = new TypeToken <FeatureRep <?>>() {}.getType ();
266- FeatureRep <?> f = gson .fromJson (featureJson , type );
327+ private final Jedis getJedis () {
328+ return pool .getResource ();
329+ }
267330
268- return f .deleted ? null : f ;
331+ private final JedisPoolConfig getPoolConfig () {
332+ JedisPoolConfig config = new JedisPoolConfig ();
333+ config .setMaxTotal (256 );
334+ config .setBlockWhenExhausted (false );
335+ return config ;
269336 }
270337}
0 commit comments