1 /* 2 * Hunt - A redis client library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.redis.RedisPool; 13 14 import hunt.redis.Exceptions; 15 import hunt.redis.Redis; 16 import hunt.redis.RedisPoolOptions; 17 import hunt.redis.Protocol; 18 19 // import hunt.pool.impl.GenericObjectPool; 20 // import hunt.util.pool; 21 22 // import hunt.redis.util.RedisURIHelper; 23 // import hunt.net.util.HttpURI; 24 25 import hunt.logging.ConsoleLogger; 26 import hunt.util.pool; 27 28 import core.atomic; 29 30 import std.conv; 31 import std.range; 32 33 alias RedisPool = ObjectPool!Redis; 34 35 /** 36 * 37 */ 38 class RedisFactory : ObjectFactory!(Redis) { 39 private RedisPool _pool; 40 private shared int counter = 0; 41 private RedisPoolOptions _options; 42 43 this(RedisPoolOptions options) { 44 _options = options; 45 _pool = new RedisPool(this, options); 46 } 47 48 RedisPool pool() { 49 return _pool; 50 } 51 52 override Redis makeObject() { 53 int c = atomicOp!("+=")(counter, 1); 54 string name = "RedisObject-" ~ c.to!string(); 55 version(HUNT_DEBUG) { 56 tracef("Making a Redis: %s", name); 57 } 58 59 Redis redis = new PooledRedis(_options); 60 61 version(HUNT_DEBUG) { 62 infof("Redis making finished: %s", name); 63 } 64 65 try { 66 redis.connect(); 67 68 if (!_options.password.empty) { 69 redis.auth(_options.password); 70 } 71 72 if (_options.database != 0) { 73 redis.select(_options.database); 74 } 75 if (_options.clientName !is null) { 76 redis.clientSetname(_options.clientName); 77 } 78 } catch (RedisException je) { 79 debug warning(je.msg); 80 version(HUNT_DEBUG) warning(je); 81 redis.close(); 82 throw je; 83 } 84 85 return redis; 86 } 87 88 override void destroyObject(Redis redis) { 89 if(redis is null) { 90 warning("The Redis is null"); 91 return; 92 } 93 version(HUNT_DEBUG) { 94 tracef("Redis [%s] destroying.", redis.toString()); 95 } 96 97 if (!redis.isConnected()) return; 98 99 try { 100 try { 101 redis.quit(); 102 } catch (Exception e) { 103 warning(e); 104 } 105 // redis.disconnect(); 106 // redis.close(); 107 } catch (Exception e) { 108 warning(e); 109 } 110 } 111 112 override bool isValid(Redis p) { 113 if(p is null) { 114 return false; 115 } else { 116 return p.isConnected(); 117 } 118 } 119 120 /** 121 * 122 */ 123 class PooledRedis : Redis { 124 125 this(RedisPoolOptions options) { 126 super(options.host, options.port, 127 options.connectionTimeout, options.soTimeout, options.ssl); 128 } 129 130 override string quit() { 131 ObjectPoolState state = _pool.state(); 132 version(HUNT_DEBUG) { 133 tracef("Quiting Redis, Pool state: %s", state); 134 } 135 136 if(state == ObjectPoolState.Open) { 137 _pool.returnObject(this); 138 return "Rejected by Pool"; 139 } else { 140 return super.quit(); 141 } 142 } 143 144 override void close() { 145 ObjectPoolState state = _pool.state(); 146 version(HUNT_POOL_DEBUG) { 147 tracef("Closing Redis, Pool state: %s", state); 148 } 149 150 if(state == ObjectPoolState.Open) { 151 _pool.returnObject(this); 152 } else { 153 super.close(); 154 } 155 } 156 } 157 } 158 159 160 @property RedisPool defaultRedisPool() @trusted { 161 import std.concurrency : initOnce; 162 163 __gshared RedisPool pool; 164 return initOnce!pool({ 165 RedisPoolOptions config = defalutPoolConfig(); 166 RedisFactory factory = new RedisFactory(config); 167 return factory.pool(); 168 }()); 169 } 170 171 private __gshared RedisPoolOptions _defalutPoolConfig; 172 173 RedisPoolOptions defalutPoolConfig() { 174 if(_defalutPoolConfig is null) { 175 _defalutPoolConfig = new RedisPoolOptions(); 176 } 177 return _defalutPoolConfig; 178 } 179 180 181 void defalutPoolConfig(RedisPoolOptions config) { 182 _defalutPoolConfig = config; 183 }