1 /*
2    Copyright (c) 2005, 2021, Oracle and/or its affiliates.
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 <NDBT.hpp>
26 #include <NDBT_Test.hpp>
27 #include <HugoTransactions.hpp>
28 #include <UtilTransactions.hpp>
29 #include <NdbBackup.hpp>
30 
31 #include "bank/Bank.hpp"
32 #include <NdbMixRestarter.hpp>
33 
34 bool disk = false;
35 
runCreateBank(NDBT_Context * ctx,NDBT_Step * step)36 int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
37   Bank bank(ctx->m_cluster_connection);
38   int overWriteExisting = true;
39   if (bank.createAndLoadBank(overWriteExisting, disk, 10) != NDBT_OK)
40     return NDBT_FAILED;
41   return NDBT_OK;
42 }
43 
44 /**
45  *
46  * SR_RUNNING  (0) - Normal, no failures are allowed.
47  * SR_STOPPING (1) - Shutdown in progress, failures should
48  *                   be expected/ignored, and operations retried.
49  * SR_STOPPED  (2) - restart in progress, halt operations
50  *                   until we are SR_RUNNING.
51  */
52 int
runBankTimer(NDBT_Context * ctx,NDBT_Step * step)53 runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
54   int wait = 5; // Max seconds between each "day"
55   int yield = 1; // Loops before bank returns
56 
57   while (!ctx->isTestStopped())
58   {
59     Bank bank(ctx->m_cluster_connection);
60     ctx->incProperty(NMR_SR_THREADS_ACTIVE);
61     while(!ctx->isTestStopped() &&
62           ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
63     {
64       if(bank.performIncreaseTime(wait, yield) == NDBT_FAILED)
65       {
66         ndbout << "performIncreaseTime FAILED" << endl;
67         if (ctx->getProperty(NMR_SR) == NdbMixRestarter::SR_RUNNING)
68           return NDBT_FAILED;
69         else
70           break;  // Possibly retry
71       }
72     }
73 
74     ndbout_c("runBankTimer is stopped");
75     ctx->decProperty(NMR_SR_THREADS_ACTIVE);
76     if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
77       break;
78   }
79   return NDBT_OK;
80 }
81 
runBankTransactions(NDBT_Context * ctx,NDBT_Step * step)82 int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
83   int wait = 0; // Max ms between each transaction
84   int yield = 1; // Loops before bank returns
85 
86   while (!ctx->isTestStopped())
87   {
88     Bank bank(ctx->m_cluster_connection);
89     ctx->incProperty(NMR_SR_THREADS_ACTIVE);
90     while(!ctx->isTestStopped() &&
91           ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
92     {
93       if(bank.performTransactions(wait, yield) == NDBT_FAILED)
94       {
95         ndbout << "performTransactions FAILED" << endl;
96         if (ctx->getProperty(NMR_SR) == NdbMixRestarter::SR_RUNNING)
97           return NDBT_FAILED;
98         else
99           break;  // Possibly retry
100       }
101     }
102     ndbout_c("runBankTransactions is stopped");
103     ctx->decProperty(NMR_SR_THREADS_ACTIVE);
104     if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
105       break;
106   }
107   return NDBT_OK;
108 }
109 
runBankGL(NDBT_Context * ctx,NDBT_Step * step)110 int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
111   int yield = 1; // Loops before bank returns
112 
113   while (ctx->isTestStopped() == false)
114   {
115     Bank bank(ctx->m_cluster_connection);
116     ctx->incProperty(NMR_SR_THREADS_ACTIVE);
117     while(!ctx->isTestStopped() &&
118           ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
119     {
120       if (bank.performMakeGLs(yield) == NDBT_FAILED)
121       {
122         ndbout << "bank.performMakeGLs FAILED" << endl;
123         if (ctx->getProperty(NMR_SR) == NdbMixRestarter::SR_RUNNING)
124           return NDBT_FAILED;
125         else
126           break;  // Possibly retry
127       }
128     }
129     ndbout_c("runBankGL is stopped");
130     ctx->decProperty(NMR_SR_THREADS_ACTIVE);
131     if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
132       break;
133   }
134   return NDBT_OK;
135 }
136 
137 int
runBankSrValidator(NDBT_Context * ctx,NDBT_Step * step)138 runBankSrValidator(NDBT_Context* ctx, NDBT_Step* step)
139 {
140   ctx->incProperty(NMR_SR_VALIDATE_THREADS);
141 
142   while(!ctx->isTestStopped())
143   {
144     if (ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_VALIDATING))
145       break;
146 
147     int wait = 0;
148     int yield = 1;
149     Bank bank(ctx->m_cluster_connection);
150     if (bank.performSumAccounts(wait, yield) != 0)
151     {
152       ndbout << "bank.performSumAccounts FAILED" << endl;
153       return NDBT_FAILED;
154     }
155 
156     if (bank.performValidateAllGLs() != 0)
157     {
158       ndbout << "bank.performValidateAllGLs FAILED" << endl;
159       return NDBT_FAILED;
160     }
161 
162     ndbout_c("runBankSrValidator is stopped");
163     ctx->decProperty(NMR_SR_VALIDATE_THREADS_ACTIVE);
164 
165     if (ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
166       break;
167   }
168 
169   ctx->decProperty(NMR_SR_VALIDATE_THREADS);
170   return NDBT_OK;
171 }
172 
runBankSum(NDBT_Context * ctx,NDBT_Step * step)173 int runBankSum(NDBT_Context* ctx, NDBT_Step* step)
174 {
175   int wait = 2000; // Max ms between each sum of accounts
176   int yield = 1; // Loops before bank returns
177 
178   while (!ctx->isTestStopped())
179   {
180     Bank bank(ctx->m_cluster_connection);
181     ctx->incProperty(NMR_SR_THREADS_ACTIVE);
182     while(!ctx->isTestStopped() &&
183           ctx->getProperty(NMR_SR) <= NdbMixRestarter::SR_STOPPING)
184     {
185       if (bank.performSumAccounts(wait, yield) == NDBT_FAILED)
186       {
187         ndbout << "bank.performSumAccounts FAILED" << endl;
188         if (ctx->getProperty(NMR_SR) == NdbMixRestarter::SR_RUNNING)
189           return NDBT_FAILED;
190         else
191           break;  // Possibly retry
192       }
193     }
194     ndbout_c("performSumAccounts is stopped");
195     ctx->decProperty(NMR_SR_THREADS_ACTIVE);
196     if(ctx->getPropertyWait(NMR_SR, NdbMixRestarter::SR_RUNNING))
197       break;
198   }
199   return NDBT_OK;
200 }
201 
202 int
runMixRestart(NDBT_Context * ctx,NDBT_Step * step)203 runMixRestart(NDBT_Context* ctx, NDBT_Step* step)
204 {
205   NdbMixRestarter res;
206   int runtime = ctx->getNumLoops();
207   int sleeptime = ctx->getNumRecords();
208   Uint32 mask = ctx->getProperty("Type", ~(Uint32)0);
209   res.setRestartTypeMask(mask);
210 
211   if (res.runPeriod(ctx, step, runtime, sleeptime))
212   {
213     return NDBT_FAILED;
214   }
215 
216   ctx->stopTest();
217   return NDBT_OK;
218 }
219 
220 /**
221  * Verify Bank consisteny after load has been stopped.
222  * Then, unconditionaly drop the Bank-DB
223  */
224 int
runVerifyAndDropBank(NDBT_Context * ctx,NDBT_Step * step)225 runVerifyAndDropBank(NDBT_Context* ctx, NDBT_Step* step)
226 {
227   int wait = 0;
228   int yield = 1;
229   int result = NDBT_OK;
230   Bank bank(ctx->m_cluster_connection);
231 
232   if (bank.performSumAccounts(wait, yield) == NDBT_FAILED)
233   {
234     ndbout << "runVerifyAndDropBank: bank.performSumAccounts FAILED" << endl;
235     result = NDBT_FAILED;
236   }
237   if (bank.performValidateAllGLs() == NDBT_FAILED)
238   {
239     ndbout << "runVerifyAndDropBank: bank.performValidateAllGLs FAILED" << endl;
240     result = NDBT_FAILED;
241   }
242 
243   if (bank.dropBank() != NDBT_OK)
244     return NDBT_FAILED;
245   return result;
246 }
247 
248 
249 NDBT_TESTSUITE(testSRBank);
250 TESTCASE("SR",
251 	 " Test that a consistent bank is restored after graceful shutdown\n"
252 	 "1.  Create bank\n"
253 	 "2.  Start bank and let it run\n"
254 	 "3.  Restart ndb and verify consistency\n"
255 	 "4.  Drop bank\n")
256 {
257   TC_PROPERTY("Type", NdbMixRestarter::RTM_SR);
258   INITIALIZER(runCreateBank);
259   STEP(runBankTimer);
260   STEPS(runBankTransactions, 10);
261   STEP(runBankGL);
262   STEP(runBankSum);
263   STEP(runBankSrValidator);
264   STEP(runMixRestart);
265   FINALIZER(runVerifyAndDropBank);
266 }
267 TESTCASE("NR",
268 	 " Test that a consistent bank is restored after graceful shutdown\n"
269 	 "1.  Create bank\n"
270 	 "2.  Start bank and let it run\n"
271 	 "3.  Restart ndb and verify consistency\n"
272 	 "4.  Drop bank\n")
273 {
274   TC_PROPERTY("Type", NdbMixRestarter::RTM_NR);
275   INITIALIZER(runCreateBank);
276   STEP(runBankTimer);
277   STEPS(runBankTransactions, 10);
278   STEP(runBankGL);
279   STEP(runBankSum);
280   STEP(runMixRestart);
281   FINALIZER(runVerifyAndDropBank);
282 }
283 TESTCASE("Mix",
284 	 " Test that a consistent bank is restored after graceful shutdown\n"
285 	 "1.  Create bank\n"
286 	 "2.  Start bank and let it run\n"
287 	 "3.  Restart ndb and verify consistency\n"
288 	 "4.  Drop bank\n")
289 {
290   TC_PROPERTY("Type", NdbMixRestarter::RTM_ALL);
291   INITIALIZER(runCreateBank);
292   STEP(runBankTimer);
293   STEPS(runBankTransactions, 10);
294   STEP(runBankGL);
295   STEP(runBankSum);
296   STEP(runMixRestart);
297   STEP(runBankSrValidator);
298   FINALIZER(runVerifyAndDropBank);
299 }
300 NDBT_TESTSUITE_END(testSRBank);
301 
302 int
main(int argc,const char ** argv)303 main(int argc, const char** argv){
304   ndb_init();
305   for (int i = 0; i<argc; i++)
306   {
307     if (strcmp(argv[i], "--disk") == 0)
308     {
309       argc--;
310       disk = true;
311       for (; i<argc; i++)
312 	argv[i] = argv[i+1];
313       break;
314     }
315   }
316   NDBT_TESTSUITE_INSTANCE(testSRBank);
317   return testSRBank.execute(argc, argv);
318 }
319 
320