1 /*
2  *  Copyright (c) 2010, 2021, Oracle and/or its affiliates.
3  *  All rights reserved. Use is subject to license terms.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License, version 2.0,
7  *  as published by the Free Software Foundation.
8  *
9  *  This program is also distributed with certain software (including
10  *  but not limited to OpenSSL) that is licensed under separate terms,
11  *  as designated in a particular file or component or in included license
12  *  documentation.  The authors of MySQL hereby grant you an additional
13  *  permission to link the program and your derivative works with the
14  *  separately licensed software that they have included with MySQL.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License, version 2.0, for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24  */
25 
26 package com.mysql.clusterj.bindings;
27 
28 import com.mysql.cluster.ndbj.NdbApiException;
29 import com.mysql.cluster.ndbj.NdbOperation.AbortOption;
30 import com.mysql.cluster.ndbj.NdbOperation;
31 import com.mysql.cluster.ndbj.NdbScanOperation;
32 import com.mysql.cluster.ndbj.NdbTransaction;
33 import com.mysql.clusterj.ClusterJDatastoreException;
34 import com.mysql.clusterj.core.store.ClusterTransaction;
35 import com.mysql.clusterj.core.store.Index;
36 import com.mysql.clusterj.core.store.IndexOperation;
37 import com.mysql.clusterj.core.store.IndexScanOperation;
38 import com.mysql.clusterj.core.store.Operation;
39 import com.mysql.clusterj.core.store.ScanOperation;
40 import com.mysql.clusterj.core.store.Table;
41 import com.mysql.clusterj.core.util.I18NHelper;
42 import com.mysql.clusterj.core.util.Logger;
43 import com.mysql.clusterj.core.util.LoggerFactoryService;
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  *
49  */
50 class ClusterTransactionImpl implements ClusterTransaction {
51 
52     /** My message translator */
53     static final I18NHelper local = I18NHelper
54             .getInstance(ClusterTransactionImpl.class);
55 
56     /** My logger */
57     static final Logger logger = LoggerFactoryService.getFactory()
58             .getInstance(ClusterTransactionImpl.class);
59 
60     protected NdbTransaction ndbTransaction;
61     private List<Runnable> postExecuteCallbacks = new ArrayList<Runnable>();
62 
ClusterTransactionImpl(NdbTransaction ndbTransaction)63     public ClusterTransactionImpl(NdbTransaction ndbTransaction) {
64         this.ndbTransaction = ndbTransaction;
65     }
66 
close()67     public void close() {
68         ndbTransaction.close();
69     }
70 
executeCommit()71     public void executeCommit() {
72         handlePendingPostExecuteCallbacks();
73         try {
74             ndbTransaction.executeCommit();
75         } catch (NdbApiException ndbApiException) {
76             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
77                     ndbApiException);
78         }
79     }
80 
executeCommit(boolean abort, boolean force)81     public void executeCommit(boolean abort, boolean force) {
82         handlePendingPostExecuteCallbacks();
83         AbortOption abortOption = abort?AbortOption.AbortOnError:AbortOption.AO_IgnoreError;
84         try {
85             ndbTransaction.execute(NdbTransaction.ExecType.Commit,
86                     abortOption, force);
87         } catch (NdbApiException ndbApiException) {
88             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
89                     ndbApiException);
90         }
91     }
92 
executeNoCommit(boolean abort, boolean force)93     public void executeNoCommit(boolean abort, boolean force) {
94         AbortOption abortOption = abort?AbortOption.AbortOnError:AbortOption.AO_IgnoreError;
95         try {
96             ndbTransaction.execute(NdbTransaction.ExecType.NoCommit,
97                     abortOption, force);
98             performPostExecuteCallbacks();
99         } catch (NdbApiException ndbApiException) {
100             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
101                     ndbApiException);
102         }
103     }
104 
executeNoCommit()105     public void executeNoCommit() {
106         try {
107             ndbTransaction.executeNoCommit();
108             performPostExecuteCallbacks();
109         } catch (NdbApiException ndbApiException) {
110             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
111                     ndbApiException);
112         }
113     }
114 
executeRollback()115     public void executeRollback() {
116         try {
117             clearPostExecuteCallbacks();
118             ndbTransaction.executeRollback();
119         } catch (NdbApiException ndbApiException) {
120             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
121                     ndbApiException);
122         }
123     }
124 
getDeleteOperation(Table storeTable)125     public Operation getDeleteOperation(Table storeTable) {
126         try {
127             return new OperationImpl(ndbTransaction.getDeleteOperation(storeTable.getName()), this);
128         } catch (NdbApiException ndbApiException) {
129             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
130                     ndbApiException);
131         }
132     }
133 
getInsertOperation(Table storeTable)134     public Operation getInsertOperation(Table storeTable) {
135         try {
136             return new OperationImpl(ndbTransaction.getInsertOperation(storeTable.getName()), this);
137         } catch (NdbApiException ndbApiException) {
138             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
139                     ndbApiException);
140         }
141     }
142 
getSelectIndexScanOperation(Index storeIndex, Table storeTable)143     public IndexScanOperation getSelectIndexScanOperation(Index storeIndex, Table storeTable) {
144         try {
145             return new IndexScanOperationImpl(
146                     ndbTransaction.getSelectIndexScanOperation(storeIndex.getName(), storeTable.getName()), this);
147         } catch (NdbApiException ndbApiException) {
148             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
149                     ndbApiException);
150         }
151     }
152 
getSelectOperation(Table storeTable)153     public Operation getSelectOperation(Table storeTable) {
154         try {
155             return new OperationImpl(ndbTransaction.getSelectOperation(storeTable.getName()), this);
156         } catch (NdbApiException ndbApiException) {
157             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
158                     ndbApiException);
159         }
160     }
161 
getSelectScanOperation(Table storeTable)162     public ScanOperation getSelectScanOperation(Table storeTable) {
163         try {
164             return new ScanOperationImpl(
165                     ndbTransaction.getSelectScanOperation(storeTable.getName()), this);
166         } catch (NdbApiException ndbApiException) {
167             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
168                     ndbApiException);
169         }
170     }
171 
getSelectScanOperationLockModeExclusiveScanFlagKeyInfo(Table storeTable)172     public ScanOperation getSelectScanOperationLockModeExclusiveScanFlagKeyInfo(Table storeTable) {
173         try {
174             return new ScanOperationImpl(
175                     ndbTransaction.getSelectScanOperation(storeTable.getName(),
176                     NdbOperation.LockMode.LM_Exclusive,
177                     NdbScanOperation.ScanFlag.KEY_INFO, 0,0), this);
178         } catch (NdbApiException ndbApiException) {
179             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
180                     ndbApiException);
181         }
182     }
183 
getSelectUniqueOperation(Index storeIndex, Table storeTable)184     public IndexOperation getSelectUniqueOperation(Index storeIndex, Table storeTable) {
185         try {
186             return new IndexOperationImpl(
187                     ndbTransaction.getSelectUniqueOperation(storeIndex.getName(), storeTable.getName()), this);
188         } catch (NdbApiException ndbApiException) {
189             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
190                     ndbApiException);
191         }
192     }
193 
getUpdateOperation(Table storeTable)194     public Operation getUpdateOperation(Table storeTable) {
195         try {
196             return new OperationImpl(ndbTransaction.getUpdateOperation(storeTable.getName()), this);
197         } catch (NdbApiException ndbApiException) {
198             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
199                     ndbApiException);
200         }
201     }
202 
getWriteOperation(Table storeTable)203     public Operation getWriteOperation(Table storeTable) {
204         try {
205             return new OperationImpl(ndbTransaction.getWriteOperation(storeTable.getName()), this);
206         } catch (NdbApiException ndbApiException) {
207             throw new ClusterJDatastoreException(local.message("ERR_Datastore"),
208                     ndbApiException);
209         }
210     }
211 
postExecuteCallback(Runnable callback)212     public void postExecuteCallback(Runnable callback) {
213         postExecuteCallbacks.add(callback);
214     }
215 
clearPostExecuteCallbacks()216     private void clearPostExecuteCallbacks() {
217         postExecuteCallbacks.clear();
218     }
219 
handlePendingPostExecuteCallbacks()220     private void handlePendingPostExecuteCallbacks() {
221         // if any pending postExecuteCallbacks, flush via executeNoCommit
222         if (!postExecuteCallbacks.isEmpty()) {
223             executeNoCommit();
224         }
225     }
226 
performPostExecuteCallbacks()227     private void performPostExecuteCallbacks() {
228         try {
229             for (Runnable runnable: postExecuteCallbacks) {
230                 try {
231                     runnable.run();
232                 } catch (Throwable t) {
233                     throw new ClusterJDatastoreException(
234                             local.message("ERR_Datastore"), t);
235                 }
236             }
237         } finally {
238             clearPostExecuteCallbacks();
239         }
240     }
241 
242 }