2
2
3
3
import io .agroal .api .AgroalDataSource ;
4
4
import io .apicurio .registry .storage .error .RegistryStorageException ;
5
- import io .apicurio .registry .storage .impl .sql .jdb .Handle ;
6
5
import io .apicurio .registry .storage .impl .sql .jdb .HandleAction ;
7
6
import io .apicurio .registry .storage .impl .sql .jdb .HandleCallback ;
8
7
import io .apicurio .registry .storage .impl .sql .jdb .HandleImpl ;
9
8
import org .slf4j .Logger ;
10
9
11
- import java .io .IOException ;
12
10
import java .sql .SQLException ;
13
11
import java .util .HashMap ;
14
12
import java .util .Map ;
@@ -32,35 +30,56 @@ protected void initialize(AgroalDataSource dataSource, String dataSourceId, Logg
32
30
33
31
@ Override
34
32
public <R , X extends Exception > R withHandle (HandleCallback <R , X > callback ) throws X {
35
- /*
36
- * Handles are cached and reused if calls to this method are nested. Make sure that all nested uses of
37
- * a handle are either within a transaction context, or without one. Starting a transaction with a
38
- * nested handle will cause an exception.
39
- */
33
+ LocalState state = state ();
40
34
try {
41
- if (get ().handle == null ) {
42
- get ().handle = new HandleImpl (dataSource .getConnection ());
35
+ // Create a new handle, or throw if one already exists (only one handle allowed at a time)
36
+ if (state .handle == null ) {
37
+ state .handle = new HandleImpl (dataSource .getConnection ());
43
38
} else {
44
- get (). level ++ ;
39
+ throw new RegistryStorageException ( "Attempt to acquire a nested DB Handle." ) ;
45
40
}
46
- return callback .withHandle (get ().handle );
41
+
42
+ // Invoke the callback with the handle. This will either return a value (success)
43
+ // or throw some sort of exception.
44
+ return callback .withHandle (state .handle );
47
45
} catch (SQLException e ) {
46
+ // If a SQL exception is thrown, set the handle to rollback.
47
+ state .handle .setRollback (true );
48
+ // Wrap the SQL exception.
48
49
throw new RegistryStorageException (e );
50
+ } catch (Exception e ) {
51
+ // If any other exception is thrown, also set the handle to rollback.
52
+ if (state .handle != null ) {
53
+ state .handle .setRollback (true );
54
+ }
55
+ throw e ;
49
56
} finally {
50
- if (get ().level > 0 ) {
51
- get ().level --;
52
- } else {
53
- try {
54
- LocalState partialState = get ();
55
- if (partialState .handle != null ) {
56
- partialState .handle .close ();
57
+ // Commit or rollback the transaction
58
+ try {
59
+ if (state .handle != null ) {
60
+ if (state .handle .isRollback ()) {
61
+ log .trace ("Rollback: {} #{}" , state .handle .getConnection (),
62
+ state .handle .getConnection ().hashCode ());
63
+ state .handle .getConnection ().rollback ();
64
+ } else {
65
+ log .trace ("Commit: {} #{}" , state .handle .getConnection (),
66
+ state .handle .getConnection ().hashCode ());
67
+ state ().handle .getConnection ().commit ();
57
68
}
58
- } catch (IOException ex ) {
59
- // Nothing we can do
60
- log .error ("Could not close a database handle" , ex );
61
- } finally {
62
- local .get ().remove (dataSourceId );
63
69
}
70
+ } catch (Exception e ) {
71
+ log .error ("Could not release database connection/transaction" , e );
72
+ }
73
+
74
+ // Close the connection
75
+ try {
76
+ if (state .handle != null ) {
77
+ state .handle .close ();
78
+ state .handle = null ;
79
+ }
80
+ } catch (Exception ex ) {
81
+ // Nothing we can do
82
+ log .error ("Could not close a database connection." , ex );
64
83
}
65
84
}
66
85
}
@@ -84,14 +103,11 @@ public <X extends Exception> void withHandleNoException(HandleAction<X> action)
84
103
});
85
104
}
86
105
87
- private LocalState get () {
106
+ private LocalState state () {
88
107
return local .get ().computeIfAbsent (dataSourceId , k -> new LocalState ());
89
108
}
90
109
91
110
private static class LocalState {
92
-
93
- Handle handle ;
94
-
95
- int level ;
111
+ HandleImpl handle ;
96
112
}
97
113
}
0 commit comments