1 /* Copyright (c) 2003-2006 MySQL AB
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
17 #include <NDBT_Test.hpp>
18 #include <HugoTransactions.hpp>
19 #include <UtilTransactions.hpp>
21 #include <NdbConfig.hpp>
22 #include <signaldata/DumpStateOrd.hpp>
24 #define TIMEOUT (Uint32)3000
25 Uint32 g_org_timeout
= 3000;
26 Uint32 g_org_deadlock
= 3000;
29 setTransactionTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
30 NdbRestarter restarter
;
31 int timeout
= ctx
->getProperty("TransactionInactiveTimeout",TIMEOUT
);
33 NdbConfig
conf(GETNDB(step
)->getNodeId()+1);
34 unsigned int nodeId
= conf
.getMasterNodeId();
35 if (!conf
.getProperty(nodeId
,
37 CFG_DB_TRANSACTION_INACTIVE_TIMEOUT
,
42 int val
[] = { DumpStateOrd::TcSetApplTransactionTimeout
, timeout
};
43 if(restarter
.dumpStateAllNodes(val
, 2) != 0){
51 resetTransactionTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
52 NdbRestarter restarter
;
54 int val
[] = { DumpStateOrd::TcSetApplTransactionTimeout
, g_org_timeout
};
55 if(restarter
.dumpStateAllNodes(val
, 2) != 0){
63 setDeadlockTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
64 NdbRestarter restarter
;
65 int timeout
= ctx
->getProperty("TransactionDeadlockTimeout", TIMEOUT
);
67 NdbConfig
conf(GETNDB(step
)->getNodeId()+1);
68 unsigned int nodeId
= conf
.getMasterNodeId();
69 if (!conf
.getProperty(nodeId
,
71 CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT
,
75 g_err
<< "Setting timeout: " << timeout
<< endl
;
76 int val
[] = { DumpStateOrd::TcSetTransactionTimeout
, timeout
};
77 if(restarter
.dumpStateAllNodes(val
, 2) != 0){
85 getDeadlockTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
86 NdbRestarter restarter
;
89 NdbConfig
conf(GETNDB(step
)->getNodeId()+1);
90 unsigned int nodeId
= conf
.getMasterNodeId();
91 if (!conf
.getProperty(nodeId
,
93 CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT
,
99 ctx
->setProperty("TransactionDeadlockTimeout", 4*val
);
105 resetDeadlockTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
106 NdbRestarter restarter
;
108 int val
[] = { DumpStateOrd::TcSetTransactionTimeout
, g_org_deadlock
};
109 if(restarter
.dumpStateAllNodes(val
, 2) != 0){
117 int runLoadTable(NDBT_Context
* ctx
, NDBT_Step
* step
){
119 int records
= ctx
->getNumRecords();
120 HugoTransactions
hugoTrans(*ctx
->getTab());
121 if (hugoTrans
.loadTable(GETNDB(step
), records
) != 0){
127 int runClearTable(NDBT_Context
* ctx
, NDBT_Step
* step
){
128 int records
= ctx
->getNumRecords();
130 UtilTransactions
utilTrans(*ctx
->getTab());
131 if (utilTrans
.clearTable2(GETNDB(step
), records
) != 0){
138 #define CHECK(b) if (!(b)) { \
139 ndbout << "ERR: "<< step->getName() \
140 << " failed on line " << __LINE__ << endl; \
141 result = NDBT_FAILED; \
144 int runTimeoutTrans2(NDBT_Context
* ctx
, NDBT_Step
* step
){
145 int result
= NDBT_OK
;
146 int loops
= ctx
->getNumLoops();
147 int stepNo
= step
->getStepNo();
148 int mul1
= ctx
->getProperty("Op1", (Uint32
)0);
149 int mul2
= ctx
->getProperty("Op2", (Uint32
)0);
150 int records
= ctx
->getNumRecords();
152 int timeout
= ctx
->getProperty("TransactionInactiveTimeout",TIMEOUT
);
154 int minSleep
= (int)(timeout
* 1.5);
155 int maxSleep
= timeout
* 2;
157 HugoOperations
hugoOps(*ctx
->getTab());
158 Ndb
* pNdb
= GETNDB(step
);
160 for (int l
= 0; l
<loops
&& !ctx
->isTestStopped() && result
== NDBT_OK
; l
++){
162 int op1
= 0 + (l
+ stepNo
) * mul1
;
163 int op2
= 0 + (l
+ stepNo
) * mul2
;
168 ndbout
<< stepNo
<< ": TransactionInactiveTimeout="<< timeout
169 << ", minSleep="<<minSleep
170 << ", maxSleep="<<maxSleep
172 << ", op2=" << op2
<< endl
;;
175 // Commit transaction
176 CHECK(hugoOps
.startTransaction(pNdb
) == 0);
182 if(hugoOps
.pkReadRecord(pNdb
, stepNo
) != 0){
183 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
184 result
= NDBT_FAILED
; break;
188 if(hugoOps
.pkUpdateRecord(pNdb
, stepNo
) != 0){
189 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
190 result
= NDBT_FAILED
; break;
194 if(hugoOps
.pkDeleteRecord(pNdb
, stepNo
) != 0){
195 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
196 result
= NDBT_FAILED
; break;
200 if(hugoOps
.pkInsertRecord(pNdb
, stepNo
+records
+l
) != 0){
201 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
202 result
= NDBT_FAILED
; break;
207 if(result
!= NDBT_OK
)
210 int res
= hugoOps
.execute_NoCommit(pNdb
);
212 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
213 result
= NDBT_FAILED
; break;
216 int sleep
= minSleep
+ myRandom48(maxSleep
-minSleep
);
217 ndbout
<< stepNo
<< ": Sleeping for "<< sleep
<< " milliseconds" << endl
;
218 NdbSleep_MilliSleep(sleep
);
224 if(hugoOps
.pkReadRecord(pNdb
, stepNo
) != 0){
225 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
226 result
= NDBT_FAILED
; break;
230 if(hugoOps
.pkUpdateRecord(pNdb
, stepNo
) != 0){
231 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
232 result
= NDBT_FAILED
; break;
236 if(hugoOps
.pkDeleteRecord(pNdb
, stepNo
) != 0){
237 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
238 result
= NDBT_FAILED
; break;
242 if(hugoOps
.pkInsertRecord(pNdb
, stepNo
+2*records
+l
) != 0){
243 g_err
<< stepNo
<< ": Fail" << __LINE__
<< endl
;
244 result
= NDBT_FAILED
; break;
249 // Expect that transaction has timed-out
250 res
= hugoOps
.execute_Commit(pNdb
);
251 if(op1
!= 0 && res
!= 266){
252 g_err
<< stepNo
<< ": Fail: " << res
<< "!= 237, op1="
253 << op1
<< ", op2=" << op2
<< endl
;
254 result
= NDBT_FAILED
; break;
259 hugoOps
.closeTransaction(pNdb
);
265 int runDontTimeoutTrans(NDBT_Context
* ctx
, NDBT_Step
* step
){
266 int result
= NDBT_OK
;
267 int loops
= ctx
->getNumLoops();
268 int stepNo
= step
->getStepNo();
270 int timeout
= ctx
->getProperty("TransactionInactiveTimeout",TIMEOUT
);
272 int maxSleep
= (int)(timeout
* 0.5);
273 ndbout
<< "TransactionInactiveTimeout="<< timeout
274 << ", maxSleep="<<maxSleep
<<endl
;
277 HugoOperations
hugoOps(*ctx
->getTab());
278 Ndb
* pNdb
= GETNDB(step
);
280 for (int l
= 0; l
< loops
&& result
== NDBT_OK
; l
++){
283 // Commit transaction
284 CHECK(hugoOps
.startTransaction(pNdb
) == 0);
285 CHECK(hugoOps
.pkReadRecord(pNdb
, stepNo
) == 0);
286 CHECK(hugoOps
.execute_NoCommit(pNdb
) == 0);
288 int sleep
= myRandom48(maxSleep
);
289 ndbout
<< "Sleeping for " << sleep
<< " milliseconds" << endl
;
290 NdbSleep_MilliSleep(sleep
);
292 // Expect that transaction has NOT timed-out
293 CHECK(hugoOps
.execute_Commit(pNdb
) == 0);
297 hugoOps
.closeTransaction(pNdb
);
303 int runDeadlockTimeoutTrans(NDBT_Context
* ctx
, NDBT_Step
* step
){
304 int result
= NDBT_OK
;
305 int loops
= ctx
->getNumLoops();
306 int stepNo
= step
->getStepNo();
308 Uint32 deadlock_timeout
;
309 NdbConfig
conf(GETNDB(step
)->getNodeId()+1);
310 unsigned int nodeId
= conf
.getMasterNodeId();
311 if (!conf
.getProperty(nodeId
,
313 CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT
,
319 int do_sleep
= (int)(deadlock_timeout
* 0.5);
322 HugoOperations
hugoOps(*ctx
->getTab());
323 Ndb
* pNdb
= GETNDB(step
);
325 for (int l
= 0; l
< loops
&& result
== NDBT_OK
; l
++){
328 // Commit transaction
329 CHECK(hugoOps
.startTransaction(pNdb
) == 0);
330 CHECK(hugoOps
.pkReadRecord(pNdb
, stepNo
) == 0);
331 CHECK(hugoOps
.execute_NoCommit(pNdb
) == 0);
333 int sleep
= deadlock_timeout
* 1.5 + myRandom48(do_sleep
);
334 ndbout
<< "Sleeping for " << sleep
<< " milliseconds" << endl
;
335 NdbSleep_MilliSleep(sleep
);
337 // Expect that transaction has NOT timed-out
338 CHECK(hugoOps
.execute_Commit(pNdb
) == 0);
342 hugoOps
.closeTransaction(pNdb
);
348 int runBuddyTransNoTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
349 int result
= NDBT_OK
;
350 int loops
= ctx
->getNumLoops();
351 int records
= ctx
->getNumRecords();
352 int stepNo
= step
->getStepNo();
353 int maxSleep
= (int)(TIMEOUT
* 0.3);
354 ndbout
<< "TransactionInactiveTimeout="<< TIMEOUT
355 << ", maxSleep="<<maxSleep
<<endl
;
357 HugoOperations
hugoOps(*ctx
->getTab());
358 Ndb
* pNdb
= GETNDB(step
);
360 for (int l
= 1; l
< loops
&& result
== NDBT_OK
; l
++){
363 // Start an insert trans
364 CHECK(hugoOps
.startTransaction(pNdb
) == 0);
365 int recordNo
= records
+ (stepNo
*loops
) + l
;
366 CHECK(hugoOps
.pkInsertRecord(pNdb
, recordNo
) == 0);
367 CHECK(hugoOps
.execute_NoCommit(pNdb
) == 0);
369 for (int i
= 0; i
< 3; i
++){
370 // Perform buddy scan reads
371 CHECK((hugoOps
.scanReadRecords(pNdb
)) == 0);
372 CHECK(hugoOps
.execute_NoCommit(pNdb
) == 0);
374 int sleep
= myRandom48(maxSleep
);
375 ndbout
<< "Sleeping for " << sleep
<< " milliseconds" << endl
;
376 NdbSleep_MilliSleep(sleep
);
379 // Expect that transaction has NOT timed-out
380 CHECK(hugoOps
.execute_Commit(pNdb
) == 0);
384 hugoOps
.closeTransaction(pNdb
);
390 int runBuddyTransTimeout(NDBT_Context
* ctx
, NDBT_Step
* step
){
391 int result
= NDBT_OK
;
392 int loops
= ctx
->getNumLoops();
393 int records
= ctx
->getNumRecords();
394 int stepNo
= step
->getStepNo();
395 ndbout
<< "TransactionInactiveTimeout="<< TIMEOUT
<<endl
;
397 HugoOperations
hugoOps(*ctx
->getTab());
398 Ndb
* pNdb
= GETNDB(step
);
400 for (int l
= 1; l
< loops
&& result
== NDBT_OK
; l
++){
402 NdbTransaction
* pTrans
= 0;
404 pTrans
= pNdb
->startTransaction();
405 NdbScanOperation
* pOp
= pTrans
->getNdbScanOperation(ctx
->getTab());
406 CHECK(pOp
->readTuples(NdbOperation::LM_Read
, 0, 0, 1) == 0);
407 CHECK(pTrans
->execute(NoCommit
) == 0);
409 int sleep
= 2 * TIMEOUT
;
410 ndbout
<< "Sleeping for " << sleep
<< " milliseconds" << endl
;
411 NdbSleep_MilliSleep(sleep
);
414 while((res
= pOp
->nextResult()) == 0);
415 ndbout_c("res: %d", res
);
430 runError4012(NDBT_Context
* ctx
, NDBT_Step
* step
){
431 int result
= NDBT_OK
;
432 int loops
= ctx
->getNumLoops();
433 int stepNo
= step
->getStepNo();
435 int timeout
= ctx
->getProperty("TransactionDeadlockTimeout", TIMEOUT
);
437 HugoOperations
hugoOps(*ctx
->getTab());
438 Ndb
* pNdb
= GETNDB(step
);
441 // Commit transaction
442 CHECK(hugoOps
.startTransaction(pNdb
) == 0);
443 CHECK(hugoOps
.pkUpdateRecord(pNdb
, 0) == 0);
444 int ret
= hugoOps
.execute_NoCommit(pNdb
);
448 ndbout
<< "Sleeping for " << sleep
<< " milliseconds" << endl
;
449 NdbSleep_MilliSleep(sleep
);
451 // Expect that transaction has NOT timed-out
452 CHECK(hugoOps
.execute_Commit(pNdb
) == 0);
460 hugoOps
.closeTransaction(pNdb
);
466 NDBT_TESTSUITE(testTimeout
);
467 TESTCASE("DontTimeoutTransaction",
468 "Test that the transaction does not timeout "\
469 "if we sleep during the transaction. Use a sleep "\
470 "value which is smaller than TransactionInactiveTimeout"){
471 INITIALIZER(runLoadTable
);
472 INITIALIZER(setTransactionTimeout
);
473 STEPS(runDontTimeoutTrans
, 1);
474 FINALIZER(resetTransactionTimeout
);
475 FINALIZER(runClearTable
);
478 "Setting TransactionInactiveTimeout to 0(zero) "\
479 "should result in infinite timeout, and not as "\
480 "was the bug, a timeout that is equal to the deadlock timeout"){
481 TC_PROPERTY("TransactionInactiveTimeout",(Uint32
)0);
482 INITIALIZER(runLoadTable
);
483 INITIALIZER(setTransactionTimeout
);
484 STEPS(runDeadlockTimeoutTrans
, 1);
485 FINALIZER(resetTransactionTimeout
);
486 FINALIZER(runClearTable
);
488 TESTCASE("DontTimeoutTransaction5",
489 "Test that the transaction does not timeout "\
490 "if we sleep during the transaction. Use a sleep "\
491 "value which is smaller than TransactionInactiveTimeout" \
492 "Five simultaneous threads"){
493 INITIALIZER(runLoadTable
);
494 INITIALIZER(setTransactionTimeout
);
495 STEPS(runDontTimeoutTrans
, 5);
496 FINALIZER(resetTransactionTimeout
);
497 FINALIZER(runClearTable
);
499 TESTCASE("TimeoutRandTransaction",
500 "Test that the transaction does timeout "\
501 "if we sleep during the transaction. Use a sleep "\
502 "value which is larger than TransactionInactiveTimeout"){
503 INITIALIZER(runLoadTable
);
504 INITIALIZER(setTransactionTimeout
);
505 TC_PROPERTY("Op1", 7);
506 TC_PROPERTY("Op2", 11);
507 STEPS(runTimeoutTrans2
, 5);
508 FINALIZER(resetTransactionTimeout
);
509 FINALIZER(runClearTable
);
511 TESTCASE("BuddyTransNoTimeout",
512 "Start a transaction and perform an insert with NoCommit. " \
513 "Start a buddy transaction wich performs long running scans " \
515 "The total sleep time is longer than TransactionInactiveTimeout" \
516 "Commit the first transaction, it should not have timed out."){
517 INITIALIZER(runLoadTable
);
518 INITIALIZER(setTransactionTimeout
);
519 STEPS(runBuddyTransNoTimeout
, 1);
520 FINALIZER(resetTransactionTimeout
);
521 FINALIZER(runClearTable
);
523 TESTCASE("BuddyTransNoTimeout5",
524 "Start a transaction and perform an insert with NoCommit. " \
525 "Start a buddy transaction wich performs long running scans " \
527 "The total sleep time is longer than TransactionInactiveTimeout" \
528 "Commit the first transaction, it should not have timed out." \
529 "Five simultaneous threads"){
530 INITIALIZER(runLoadTable
);
531 INITIALIZER(setTransactionTimeout
);
532 STEPS(runBuddyTransNoTimeout
, 5);
533 FINALIZER(resetTransactionTimeout
);
534 FINALIZER(runClearTable
);
536 TESTCASE("BuddyTransTimeout1",
537 "Start a scan and check that it gets aborted"){
538 INITIALIZER(runLoadTable
);
539 INITIALIZER(setTransactionTimeout
);
540 STEPS(runBuddyTransTimeout
, 1);
541 FINALIZER(resetTransactionTimeout
);
542 FINALIZER(runClearTable
);
545 TESTCASE("Error4012", ""){
546 TC_PROPERTY("TransactionDeadlockTimeout", 120000);
547 INITIALIZER(runLoadTable
);
548 INITIALIZER(getDeadlockTimeout
);
549 INITIALIZER(setDeadlockTimeout
);
550 STEPS(runError4012
, 2);
551 FINALIZER(runClearTable
);
554 NDBT_TESTSUITE_END(testTimeout
);
556 int main(int argc
, const char** argv
){
558 myRandom48Init(NdbTick_CurrentMillisecond());
559 return testTimeout
.execute(argc
, argv
);