1 /*
2 Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <NdbApi.hpp>
26
27 #include "adapter_global.h"
28 #include "AsyncNdbContext.h"
29 #include "SessionImpl.h"
30 #include "NdbWrappers.h"
31 #include "TransactionImpl.h"
32 #include "BatchImpl.h"
33
34 extern void setJsWrapper(TransactionImpl *);
35 extern Local<Object> getWrappedObject(BatchImpl *set);
36
37 const char * modes[4] = { "Prepare ","NoCommit","Commit ","Rollback" };
38
39 // TODO: verify that caller has HandleScope
TransactionImpl(SessionImpl * impl)40 TransactionImpl::TransactionImpl(SessionImpl *impl) :
41 token(0),
42 parentSessionImpl(impl),
43 next(0),
44 ndbTransaction(0),
45 tcNodeId(0),
46 openOperationSet(0)
47 {
48 setJsWrapper(this);
49 emptyOpSet = new BatchImpl(this, 0);
50 emptyOpSetWrapper.Reset(v8::Isolate::GetCurrent(), getWrappedObject(emptyOpSet));
51 }
52
~TransactionImpl()53 TransactionImpl::~TransactionImpl() {
54 DEBUG_MARKER(UDEB_DETAIL);
55 // jsWrapper.Reset();
56 // jsWrapper.MakeWeak();
57 }
58
59
getNdbError()60 const NdbError & TransactionImpl::getNdbError() {
61 if(ndbTransaction) { // transaction is open
62 return ndbTransaction->getNdbError();
63 } else { // startTransaction() failed
64 return parentSessionImpl->getNdbError();
65 }
66 }
67
tryImmediateStartTransaction(KeyOperation * op)68 bool TransactionImpl::tryImmediateStartTransaction(KeyOperation * op) {
69 token = parentSessionImpl->registerIntentToOpen();
70 if(token == -1) {
71 startTransaction(op);
72 return true;
73 }
74 return false;
75 }
76
startTransaction(KeyOperation * op)77 void TransactionImpl::startTransaction(KeyOperation * op) {
78 assert(ndbTransaction == 0);
79 bool startWithHint = (op && op->key_buffer && op->key_record->partitionKey());
80
81 if(startWithHint) {
82 char hash_buffer[512];
83 ndbTransaction = parentSessionImpl->ndb->
84 startTransaction(op->key_record->getNdbRecord(),
85 op->key_buffer, hash_buffer, 512);
86 } else {
87 ndbTransaction = parentSessionImpl->ndb->startTransaction();
88 }
89
90 tcNodeId = ndbTransaction ? ndbTransaction->getConnectedNodeId() : 0;
91 DEBUG_PRINT("START TRANSACTION %s TC Node %d",
92 startWithHint ? "[with hint]" : "[ no hint ]", tcNodeId);
93 }
94
prepareAndExecuteScan(ScanOperation * scan)95 int TransactionImpl::prepareAndExecuteScan(ScanOperation *scan) {
96 if(! ndbTransaction) {
97 startTransaction(NULL);
98 }
99 scan->prepareScan(ndbTransaction);
100 return ndbTransaction->execute(NdbTransaction::NoCommit, NdbOperation::AO_IgnoreError, 1);
101 }
102
prepareAndExecuteQuery(QueryOperation * query)103 int TransactionImpl::prepareAndExecuteQuery(QueryOperation *query) {
104 if(! ndbTransaction) {
105 startTransaction(NULL);
106 }
107 if(! query->createNdbQuery(ndbTransaction)) {
108 DEBUG_PRINT("%d %s", query->getNdbError().code, query->getNdbError().message);
109 return -1;
110 }
111 return ndbTransaction->execute(NdbTransaction::NoCommit, NdbOperation::AO_IgnoreError, 1);
112 }
113
closeTransaction()114 void TransactionImpl::closeTransaction() {
115 openOperationSet->saveNdbErrors();
116 ndbTransaction->close();
117 }
118
registerClose()119 void TransactionImpl::registerClose() {
120 ndbTransaction = 0;
121 openOperationSet->transactionIsClosed();
122 parentSessionImpl->registerTxClosed(token, tcNodeId);
123 }
124
execute(BatchImpl * operations,int _execType,int _abortOption,int force)125 int TransactionImpl::execute(BatchImpl *operations,
126 int _execType, int _abortOption, int force) {
127 int rval;
128 int opListSize = operations->size;
129 openOperationSet = operations;
130 NdbTransaction::ExecType execType = static_cast<NdbTransaction::ExecType>(_execType);
131 NdbOperation::AbortOption abortOption = static_cast<NdbOperation::AbortOption>(_abortOption);
132 bool doClose = (execType != NdbTransaction::NoCommit);
133
134 if(! ndbTransaction) {
135 startTransaction(operations->getKeyOperation(0));
136 }
137 operations->prepare(ndbTransaction);
138
139 if(operations->hasBlobReadOperations()) {
140 ndbTransaction->execute(NdbTransaction::NoCommit);
141 DEBUG_PRINT("BLOB EXECUTE DONE");
142 }
143
144 rval = ndbTransaction->execute(execType, abortOption, force);
145 DEBUG_PRINT("EXECUTE sync : %s %d operation%s %s => return: %d error: %d",
146 modes[execType],
147 opListSize,
148 (opListSize == 1 ? "" : "s"),
149 (doClose ? " & close transaction" : ""),
150 rval,
151 ndbTransaction->getNdbError().code);
152 if(doClose) {
153 closeTransaction();
154 operations->transactionIsClosed();
155 }
156 return rval;
157 }
158
executeAsynch(BatchImpl * operations,int execType,int abortOption,int forceSend,v8::Handle<v8::Function> callback)159 int TransactionImpl::executeAsynch(BatchImpl *operations,
160 int execType, int abortOption, int forceSend,
161 v8::Handle<v8::Function> callback) {
162 assert(ndbTransaction);
163 operations->prepare(ndbTransaction);
164 openOperationSet = operations;
165 int opListSize = operations->size;
166 DEBUG_PRINT("EXECUTE async: %s %d operation%s", modes[execType],
167 opListSize, (opListSize == 1 ? "" : "s"));
168 return parentSessionImpl->asyncContext->
169 executeAsynch(this, ndbTransaction, execType, abortOption, forceSend,callback);
170 }
171
172 // THESE WERE ORIGINALLY INLINED --- MOVE THEM BACK AFTER FIXED
173
getJsWrapper() const174 v8::Local<v8::Object> TransactionImpl::getJsWrapper() const {
175 return ToLocal( &jsWrapper);
176 }
177
getWrappedEmptyOperationSet() const178 v8::Local<v8::Object> TransactionImpl::getWrappedEmptyOperationSet() const {
179 return ToLocal(& emptyOpSetWrapper);
180 }
181