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.RedisSlotBasedConnectionHandler;
13 
14 import hunt.redis.RedisClusterConnectionHandler;
15 
16 import hunt.redis.Exceptions;
17 import hunt.redis.HostAndPort;
18 import hunt.redis.Redis;
19 import hunt.redis.RedisPool;
20 
21 import hunt.text.Common;
22 
23 import hunt.collection.List;
24 import hunt.collection.Set;
25 import hunt.pool.impl.GenericObjectPoolConfig;
26 
27 
28 class RedisSlotBasedConnectionHandler : RedisClusterConnectionHandler {
29 
30   this(Set!(HostAndPort) nodes,
31       GenericObjectPoolConfig poolConfig, int timeout) {
32     this(nodes, poolConfig, timeout, timeout);
33   }
34 
35   this(Set!(HostAndPort) nodes,
36       GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout) {
37     super(nodes, poolConfig, connectionTimeout, soTimeout, null);
38   }
39 
40   this(Set!(HostAndPort) nodes, GenericObjectPoolConfig poolConfig, 
41       int connectionTimeout, int soTimeout, string password) {
42     super(nodes, poolConfig, connectionTimeout, soTimeout, password);
43   }
44 
45   this(Set!(HostAndPort) nodes, GenericObjectPoolConfig poolConfig, 
46       int connectionTimeout, int soTimeout, string password, string clientName) {
47     super(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName);
48   }
49 
50   // this(Set!(HostAndPort) nodes, GenericObjectPoolConfig poolConfig, int connectionTimeout, 
51   //       int soTimeout, string password, string clientName, 
52   //       bool ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 
53   //       HostnameVerifier hostnameVerifier, RedisClusterHostAndPortMap portMap) {
54           
55   //   super(nodes, poolConfig, connectionTimeout, soTimeout, password, clientName, ssl, 
56   //       sslSocketFactory, sslParameters, hostnameVerifier, portMap);
57   // }
58 
59   override
60   Redis getConnection() {
61     // In antirez's redis-rb-cluster implementation,
62     // getRandomConnection always return valid connection (able to
63     // ping-pong)
64     // or exception if all connections are invalid
65 
66     List!(RedisPool) pools = cache.getShuffledNodesPool();
67 
68     foreach(RedisPool pool ; pools) {
69       Redis redis = null;
70       try {
71         redis = pool.getResource();
72 
73         if (redis is null) {
74           continue;
75         }
76 
77         string result = redis.ping();
78 
79         if (result.equalsIgnoreCase("pong")) return redis;
80 
81         redis.close();
82       } catch (RedisException ex) {
83         if (redis !is null) {
84           redis.close();
85         }
86       }
87     }
88 
89     throw new RedisNoReachableClusterNodeException("No reachable node in cluster");
90   }
91 
92   override
93   Redis getConnectionFromSlot(int slot) {
94     RedisPool connectionPool = cache.getSlotPool(slot);
95     if (connectionPool !is null) {
96       // It can't guaranteed to get valid connection because of node
97       // assignment
98       return connectionPool.getResource();
99     } else {
100       renewSlotCache(); //It's abnormal situation for cluster mode, that we have just nothing for slot, try to rediscover state
101       connectionPool = cache.getSlotPool(slot);
102       if (connectionPool !is null) {
103         return connectionPool.getResource();
104       } else {
105         //no choice, fallback to new connection to random node
106         return getConnection();
107       }
108     }
109   }
110 }