18
18
*/
19
19
package io .hops .metadata .ndb ;
20
20
21
+ import com .mysql .clusterj .ClusterJDatastoreException ;
21
22
import com .mysql .clusterj .ClusterJException ;
22
23
import com .mysql .clusterj .ClusterJHelper ;
24
+ import com .mysql .clusterj .ClusterJUserException ;
23
25
import com .mysql .clusterj .Constants ;
24
26
import com .mysql .clusterj .LockMode ;
25
27
import io .hops .exception .StorageException ;
34
36
import java .util .NoSuchElementException ;
35
37
import java .util .Properties ;
36
38
import java .util .Random ;
39
+ import java .util .UUID ;
37
40
import java .util .concurrent .ConcurrentLinkedQueue ;
38
41
import java .util .concurrent .atomic .AtomicInteger ;
39
42
@@ -54,6 +57,8 @@ public class DBSessionProvider implements Runnable {
54
57
private boolean automaticRefresh = false ;
55
58
private Thread thread ;
56
59
private final ClusterJCaching clusterJCaching ;
60
+ private UUID currentConnectionID ;
61
+ private final int initialPoolSize ;
57
62
58
63
public DBSessionProvider (Properties conf )
59
64
throws StorageException {
@@ -65,7 +70,7 @@ public DBSessionProvider(Properties conf)
65
70
(String ) conf .get ("io.hops.enable.clusterj.session.cache" ));
66
71
clusterJCaching = new ClusterJCaching (useClusterjDtoCache , useClusterjSessionCache );
67
72
68
- int initialPoolSize = Integer .parseInt (
73
+ initialPoolSize = Integer .parseInt (
69
74
(String ) conf .get ("io.hops.session.pool.size" ));
70
75
int reuseCount = Integer .parseInt (
71
76
(String ) conf .get ("io.hops.session.reuse.count" ));
@@ -88,6 +93,8 @@ private void start(int initialPoolSize) throws StorageException {
88
93
"Database name: " + conf .get (Constants .PROPERTY_CLUSTER_DATABASE ));
89
94
LOG .info ("Max Transactions: " +
90
95
conf .get (Constants .PROPERTY_CLUSTER_MAX_TRANSACTIONS ));
96
+ LOG .info ("Reconnect Timeout: " +
97
+ conf .get (Constants .PROPERTY_CONNECTION_RECONNECT_TIMEOUT ));
91
98
LOG .info ("Using ClusterJ Session Cache: " +clusterJCaching .useClusterjSessionCache ());
92
99
LOG .info ("Using ClusterJ DTO Cache: " +clusterJCaching .useClusterjDtoCache ());
93
100
try {
@@ -97,9 +104,7 @@ private void start(int initialPoolSize) throws StorageException {
97
104
throw HopsExceptionHelper .wrap (ex );
98
105
}
99
106
100
- for (int i = 0 ; i < initialPoolSize ; i ++) {
101
- sessionPool .add (initSession ());
102
- }
107
+ createNewSessions ();
103
108
104
109
thread = new Thread (this , "Session Pool Refresh Daemon" );
105
110
thread .setDaemon (true );
@@ -115,7 +120,7 @@ private DBSession initSession() throws StorageException {
115
120
sessionCreationTime ;
116
121
117
122
int reuseCount = rand .nextInt (MAX_REUSE_COUNT ) + 1 ;
118
- DBSession dbSession = new DBSession (session , reuseCount );
123
+ DBSession dbSession = new DBSession (session , reuseCount , currentConnectionID );
119
124
sessionsCreated .incrementAndGet ();
120
125
return dbSession ;
121
126
}
@@ -141,20 +146,38 @@ public DBSession getSession() throws StorageException {
141
146
DBSession session = sessionPool .remove ();
142
147
return session ;
143
148
} catch (NoSuchElementException e ) {
144
- LOG .warn (
145
- "DB Sessino provider cant keep up with the demand for new sessions" );
149
+ LOG .warn ("DB session provider cant keep up with the demand for new sessions" );
146
150
return initSession ();
147
151
}
148
152
}
149
153
150
- public void returnSession (DBSession returnedSession , boolean forceClose ) throws StorageException {
154
+ public void returnSession (DBSession returnedSession , Exception ... exceptions ) throws StorageException {
155
+ boolean forceClose = false ;
156
+ if (sessionFactory .isOpen ()){
157
+ for (Exception e : exceptions ){
158
+ if (e == null ) continue ;
159
+ Throwable cause = e .getCause ();
160
+ if (cause instanceof ClusterJDatastoreException ) {
161
+ forceClose = true ;
162
+ } else if (cause instanceof ClusterJUserException ){
163
+ if (cause .getMessage ().contains ("No more operations can be performed while this Db is " +
164
+ "closing" )){
165
+ forceClose = true ;
166
+ }
167
+ } else if (returnedSession .getConnectionID () != currentConnectionID ) {
168
+ forceClose = true ;
169
+ }
170
+ }
171
+ }
172
+
151
173
//session has been used, increment the use counter
152
174
returnedSession
153
175
.setSessionUseCount (returnedSession .getSessionUseCount () + 1 );
154
176
155
- if ((returnedSession .getSessionUseCount () >=
177
+ if (sessionFactory . isOpen () && ( (returnedSession .getSessionUseCount () >=
156
178
returnedSession .getMaxReuseCount ()) ||
157
- forceClose ) { // session can be closed even before the reuse count has expired. Close the session incase of database errors.
179
+ forceClose )) { // session can be closed even before the reuse count has expired. Close
180
+ // the session incase of database errors.
158
181
toGC .add (returnedSession );
159
182
} else { // increment the count and return it to the pool
160
183
returnedSession .getSession ().setLockMode (LockMode .READ_COMMITTED );
@@ -179,24 +202,29 @@ public int getAvailableSessions() {
179
202
return sessionPool .size ();
180
203
}
181
204
205
+ boolean reconnecting = false ;
182
206
@ Override
183
207
public void run () {
184
208
while (automaticRefresh ) {
185
209
try {
186
- int toGCSize = toGC .size ();
187
-
188
- if (toGCSize > 0 ) {
189
- LOG .debug ("Renewing a session(s) " + toGCSize );
190
- for (int i = 0 ; i < toGCSize ; i ++) {
191
- DBSession session = toGC .remove ();
192
- session .getSession ().close ();
193
- }
210
+ if (!sessionFactory .isOpen ()) {
211
+ reconnecting = true ;
212
+ sessionFactory .reconnect ();
213
+ }
194
214
195
- for (int i = 0 ; i < toGCSize ; i ++) {
196
- sessionPool .add (initSession ());
197
- }
215
+ if ( sessionFactory .isOpen () && reconnecting ){
216
+ // reconnected after network failure
217
+ // close all old sessions and start new sessions
218
+ reconnecting = false ;
219
+ currentConnectionID = UUID .randomUUID ();
220
+ renewAllSessions ();
221
+ gcSessions (false );
222
+ } else {
223
+ // do normal gc
224
+ gcSessions (true );
198
225
}
199
- Thread .sleep (5 );
226
+
227
+ Thread .sleep (50 );
200
228
} catch (NoSuchElementException e ) {
201
229
for (int i = 0 ; i < 100 ; i ++) {
202
230
try {
@@ -214,6 +242,40 @@ public void run() {
214
242
}
215
243
}
216
244
245
+ public void renewAllSessions () throws StorageException {
246
+ while (!sessionPool .isEmpty ()) {
247
+ DBSession session = sessionPool .poll ();
248
+ if (session != null ) {
249
+ closeSession (session );
250
+ }
251
+ }
252
+ createNewSessions ();
253
+ }
254
+
255
+ public void gcSessions (boolean createNewSessions ) throws StorageException {
256
+ int toGCSize = toGC .size ();
257
+
258
+ if (toGCSize > 0 ) {
259
+ LOG .debug ("Renewing a session(s) " + toGCSize );
260
+ for (int i = 0 ; i < toGCSize ; i ++) {
261
+ DBSession session = toGC .remove ();
262
+ closeSession (session );
263
+ }
264
+
265
+ if (createNewSessions ){
266
+ for (int i = 0 ; i < toGCSize ; i ++) {
267
+ sessionPool .add (initSession ());
268
+ }
269
+ }
270
+ }
271
+ }
272
+
273
+ public void createNewSessions () throws StorageException {
274
+ for (int i = 0 ; i < initialPoolSize ; i ++) {
275
+ sessionPool .add (initSession ());
276
+ }
277
+ }
278
+
217
279
public void clearCache () throws StorageException {
218
280
Iterator <DBSession > itr = sessionPool .iterator ();
219
281
while (itr .hasNext ()){
0 commit comments