~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/ndb/test/ndbapi/bank/Bank.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2003 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "Bank.hpp"
 
17
#include <time.h>
 
18
#include <NdbSleep.h>
 
19
#include <UtilTransactions.hpp>
 
20
 
 
21
Bank::Bank(Ndb_cluster_connection& con, bool _init, const char * dbase):
 
22
  m_ndb(&con, dbase),
 
23
  m_maxAccount(-1),
 
24
  m_initialized(false),
 
25
  m_skip_create(false)
 
26
{
 
27
  if(_init)
 
28
    init();
 
29
}
 
30
 
 
31
int Bank::init(){
 
32
  if (m_initialized == true)
 
33
    return NDBT_OK;
 
34
 
 
35
  myRandom48Init(NdbTick_CurrentMillisecond());
 
36
 
 
37
  m_ndb.init();   
 
38
  if (m_ndb.waitUntilReady(30) != 0)
 
39
  {
 
40
    ndbout << "Ndb not ready" << endl;
 
41
    return NDBT_FAILED;
 
42
  }
 
43
  
 
44
  if (getNumAccounts() != NDBT_OK)
 
45
    return NDBT_FAILED;
 
46
 
 
47
  m_initialized = true;
 
48
  return NDBT_OK;
 
49
}
 
50
 
 
51
int Bank::performTransactions(int maxSleepBetweenTrans, int yield){
 
52
 
 
53
  int transactions = 0;
 
54
 
 
55
  while(performTransaction() == NDBT_OK)
 
56
  {
 
57
    transactions++;
 
58
    
 
59
    if (maxSleepBetweenTrans > 0){
 
60
      int val = myRandom48(maxSleepBetweenTrans);
 
61
      NdbSleep_MilliSleep(val);      
 
62
    }
 
63
    
 
64
    if((transactions % 100) == 0)
 
65
      g_info << transactions  << endl;
 
66
    
 
67
    if (yield != 0 && transactions >= yield)
 
68
      return NDBT_OK;
 
69
  }
 
70
 
 
71
  return NDBT_FAILED;
 
72
 
 
73
}
 
74
 
 
75
int Bank::performTransaction(){
 
76
  int result = NDBT_OK;
 
77
 
 
78
  if (m_maxAccount <= 0){
 
79
    g_err << "No accounts in bank" << endl;
 
80
    return NDBT_FAILED;
 
81
  }
 
82
 
 
83
  int fromAccount = myRandom48(m_maxAccount);
 
84
  int toAccount = myRandom48(m_maxAccount);
 
85
    
 
86
  if (fromAccount == toAccount){
 
87
    // Increase toAccount with 1
 
88
    toAccount = (toAccount+1)%m_maxAccount;
 
89
  }
 
90
    
 
91
  int maxAmount = getMaxAmount();
 
92
    
 
93
  int amount = myRandom48(maxAmount);
 
94
 
 
95
retry_transaction:
 
96
  int res = performTransaction(fromAccount, toAccount, amount);
 
97
  if (res != 0){
 
98
    switch (res){
 
99
    case NDBT_FAILED:
 
100
      g_err << "performTransaction returned NDBT_FAILED" << endl
 
101
            << "  fromAccount = " << fromAccount << endl
 
102
            << "  toAccount = " << toAccount << endl
 
103
            << "  amount = " << amount << endl;
 
104
      result = NDBT_FAILED;
 
105
      break;
 
106
    case NOT_ENOUGH_FUNDS:
 
107
      //   ndbout << "performTransaction returned NOT_ENOUGH_FUNDS" << endl;    
 
108
      break;
 
109
    case NDBT_TEMPORARY:
 
110
      g_err << "TEMPORARY_ERRROR retrying" << endl;
 
111
      NdbSleep_MilliSleep(50);
 
112
      goto retry_transaction;
 
113
      break;
 
114
    default:
 
115
      g_info << "performTransaction returned "<<res << endl;    
 
116
      break;
 
117
    }
 
118
  }
 
119
  return result;
 
120
}
 
121
 
 
122
/**
 
123
 * Perform a transaction in the bank. 
 
124
 * Ie. transfer money from one account to another.
 
125
 *
 
126
 * @param 
 
127
 * @return 0 if successful or an error code
 
128
 */
 
129
int Bank::performTransaction(int fromAccountId,
 
130
                             int toAccountId,
 
131
                             int amount ){
 
132
  /**
 
133
   * 1. Start transaction
 
134
   * 2. Check balance on from account, if there is
 
135
   *    not enough funds abort transaction
 
136
   * 3. Update ACCOUNT set balance = balance - amount on
 
137
   *    from account 
 
138
   * 4. Insert withdrawal in TRANSACTION
 
139
   * 5. Insert deposit in transaction
 
140
   * 6. Update ACCOUNT set balance = balance + amount on 
 
141
   *    to account
 
142
   * 7. Commit transaction
 
143
   */ 
 
144
  //  g_info << "performTransaction " << fromAccountId 
 
145
  //     << ", "<<toAccountId<<", "<<amount << endl;
 
146
 
 
147
  // Call the first implementation of this trans
 
148
  // In the future we can have several different versions of this trans
 
149
  // and call them randomly 
 
150
  return performTransactionImpl1(fromAccountId, toAccountId, amount); 
 
151
}
 
152
 
 
153
 
 
154
int Bank::performTransactionImpl1(int fromAccountId,
 
155
                                  int toAccountId,
 
156
                                  int amount ){
 
157
 
 
158
  int check;
 
159
    
 
160
  // Ok, all clear to do the transaction
 
161
  Uint64 transId;
 
162
  int result = NDBT_OK;
 
163
  if ((result= getNextTransactionId(transId)) != NDBT_OK){
 
164
    return result;
 
165
  }
 
166
 
 
167
  NdbConnection* pTrans = m_ndb.startTransaction();
 
168
 
 
169
  if( pTrans == NULL ) {
 
170
    const NdbError err = m_ndb.getNdbError();
 
171
    if (err.status == NdbError::TemporaryError){
 
172
      ERR(err);
 
173
      return NDBT_TEMPORARY;
 
174
    }
 
175
    ERR(err);
 
176
    return NDBT_FAILED;
 
177
  }
 
178
    
 
179
  Uint64 currTime;
 
180
  if (prepareGetCurrTimeOp(pTrans, currTime) != NDBT_OK){
 
181
    ERR(pTrans->getNdbError());
 
182
    m_ndb.closeTransaction(pTrans);
 
183
    return NDBT_FAILED;
 
184
  }
 
185
 
 
186
  /** 
 
187
   * Check balance on from account
 
188
   */
 
189
  NdbOperation* pOp = pTrans->getNdbOperation("ACCOUNT");
 
190
  if (pOp == NULL) {
 
191
    ERR(pTrans->getNdbError());
 
192
    m_ndb.closeTransaction(pTrans);
 
193
    return NDBT_FAILED;
 
194
  }
 
195
    
 
196
  check = pOp->readTupleExclusive();
 
197
  if( check == -1 ) {
 
198
    ERR(pTrans->getNdbError());
 
199
    m_ndb.closeTransaction(pTrans);
 
200
    return NDBT_FAILED;
 
201
  }
 
202
    
 
203
  check = pOp->equal("ACCOUNT_ID", fromAccountId);
 
204
  if( check == -1 ) {
 
205
    ERR(pTrans->getNdbError());
 
206
    m_ndb.closeTransaction(pTrans);
 
207
    return NDBT_FAILED;
 
208
  }
 
209
    
 
210
  NdbRecAttr* balanceFromRec = pOp->getValue("BALANCE");
 
211
  if( balanceFromRec ==NULL ) {
 
212
    ERR(pTrans->getNdbError());
 
213
    m_ndb.closeTransaction(pTrans);
 
214
    return NDBT_FAILED;
 
215
  }
 
216
    
 
217
  NdbRecAttr* fromAccountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
218
  if( fromAccountTypeRec == NULL ) {
 
219
    ERR(pTrans->getNdbError());
 
220
    m_ndb.closeTransaction(pTrans);
 
221
    return NDBT_FAILED;
 
222
  }
 
223
 
 
224
  /** 
 
225
   * Read balance on to account
 
226
   */
 
227
  NdbOperation* pOp6 = pTrans->getNdbOperation("ACCOUNT");
 
228
  if (pOp6 == NULL) {
 
229
    ERR(pTrans->getNdbError());
 
230
    m_ndb.closeTransaction(pTrans);
 
231
    return NDBT_FAILED;
 
232
  }
 
233
    
 
234
  check = pOp6->readTupleExclusive();
 
235
  if( check == -1 ) {
 
236
    ERR(pTrans->getNdbError());
 
237
    m_ndb.closeTransaction(pTrans);
 
238
    return NDBT_FAILED;
 
239
  }
 
240
    
 
241
  check = pOp6->equal("ACCOUNT_ID", toAccountId);
 
242
  if( check == -1 ) {
 
243
    ERR(pTrans->getNdbError());
 
244
    m_ndb.closeTransaction(pTrans);
 
245
    return NDBT_FAILED;
 
246
  }
 
247
    
 
248
  NdbRecAttr* balanceToRec = pOp6->getValue("BALANCE");
 
249
  if( balanceToRec == NULL ) {
 
250
    ERR(pTrans->getNdbError());
 
251
    m_ndb.closeTransaction(pTrans);
 
252
    return NDBT_FAILED;
 
253
  }
 
254
 
 
255
  NdbRecAttr* toAccountTypeRec = pOp6->getValue("ACCOUNT_TYPE");
 
256
  if( toAccountTypeRec == NULL ) {
 
257
    ERR(pTrans->getNdbError());
 
258
    m_ndb.closeTransaction(pTrans);
 
259
    return NDBT_FAILED;
 
260
  }
 
261
    
 
262
  check = pTrans->execute(NoCommit);
 
263
  if( check == -1 ) {
 
264
    const NdbError err = pTrans->getNdbError();
 
265
    m_ndb.closeTransaction(pTrans);    
 
266
    if (err.status == NdbError::TemporaryError){
 
267
      ERR(err);
 
268
      return NDBT_TEMPORARY;
 
269
    }
 
270
    ERR(err);
 
271
    return NDBT_FAILED;
 
272
  }
 
273
    
 
274
 
 
275
  Uint32  balanceFrom = balanceFromRec->u_32_value();
 
276
  //  ndbout << "balanceFrom: " << balanceFrom << endl;
 
277
 
 
278
  if (((Int64)balanceFrom - amount) < 0){
 
279
    m_ndb.closeTransaction(pTrans);      
 
280
    //ndbout << "Not enough funds" << endl;      
 
281
    return NOT_ENOUGH_FUNDS;
 
282
  }
 
283
 
 
284
  Uint32 fromAccountType = fromAccountTypeRec->u_32_value();
 
285
 
 
286
  Uint32  balanceTo = balanceToRec->u_32_value();
 
287
  //  ndbout << "balanceTo: " << balanceTo << endl;
 
288
  Uint32 toAccountType = toAccountTypeRec->u_32_value();
 
289
 
 
290
  /**
 
291
   * Update balance on from account
 
292
   */
 
293
  NdbOperation* pOp2 = pTrans->getNdbOperation("ACCOUNT");
 
294
  if (pOp2 == NULL) {
 
295
    ERR(pTrans->getNdbError());
 
296
    m_ndb.closeTransaction(pTrans);
 
297
    return NDBT_FAILED;
 
298
  }
 
299
    
 
300
  check = pOp2->updateTuple();
 
301
  if( check == -1 ) {
 
302
    ERR(pTrans->getNdbError());
 
303
    m_ndb.closeTransaction(pTrans);
 
304
    return NDBT_FAILED;
 
305
  }
 
306
    
 
307
  check = pOp2->equal("ACCOUNT_ID", fromAccountId);
 
308
  if( check == -1 ) {
 
309
    ERR(pTrans->getNdbError());
 
310
    m_ndb.closeTransaction(pTrans);
 
311
    return NDBT_FAILED;
 
312
  }
 
313
 
 
314
  check = pOp2->setValue("BALANCE", balanceFrom - amount);
 
315
  if( check == -1 ) {
 
316
    ERR(pTrans->getNdbError());
 
317
    m_ndb.closeTransaction(pTrans);
 
318
    return NDBT_FAILED;
 
319
  }
 
320
 
 
321
  /**
 
322
   * Update balance on to account
 
323
   */
 
324
  NdbOperation* pOp3 = pTrans->getNdbOperation("ACCOUNT");
 
325
  if (pOp3 == NULL) {
 
326
    ERR(pTrans->getNdbError());
 
327
    m_ndb.closeTransaction(pTrans);
 
328
    return NDBT_FAILED;
 
329
  }
 
330
    
 
331
  check = pOp3->updateTuple();
 
332
  if( check == -1 ) {
 
333
    ERR(pTrans->getNdbError());
 
334
    m_ndb.closeTransaction(pTrans);
 
335
    return NDBT_FAILED;
 
336
  }
 
337
    
 
338
  check = pOp3->equal("ACCOUNT_ID", toAccountId);
 
339
  if( check == -1 ) {
 
340
    ERR(pTrans->getNdbError());
 
341
    m_ndb.closeTransaction(pTrans);
 
342
    return NDBT_FAILED;
 
343
  }
 
344
 
 
345
  check = pOp3->setValue("BALANCE", balanceTo + amount);
 
346
  if( check == -1 ) {
 
347
    ERR(pTrans->getNdbError());
 
348
    m_ndb.closeTransaction(pTrans);
 
349
    return NDBT_FAILED;
 
350
  }
 
351
 
 
352
  /**
 
353
   * Insert withdrawal transaction
 
354
   */
 
355
  NdbOperation* pOp4 = pTrans->getNdbOperation("TRANSACTION");
 
356
  if (pOp4 == NULL) {
 
357
    ERR(pTrans->getNdbError());
 
358
    m_ndb.closeTransaction(pTrans);
 
359
    return NDBT_FAILED;
 
360
  }
 
361
    
 
362
  check = pOp4->insertTuple();
 
363
  if( check == -1 ) {
 
364
    ERR(pTrans->getNdbError());
 
365
    m_ndb.closeTransaction(pTrans);
 
366
    return NDBT_FAILED;
 
367
  }
 
368
    
 
369
  check = pOp4->equal("TRANSACTION_ID", transId);
 
370
  if( check == -1 ) {
 
371
    ERR(pTrans->getNdbError());
 
372
    m_ndb.closeTransaction(pTrans);
 
373
    return NDBT_FAILED;
 
374
  }
 
375
 
 
376
  check = pOp4->equal("ACCOUNT", fromAccountId);
 
377
  if( check == -1 ) {
 
378
    ERR(pTrans->getNdbError());
 
379
    m_ndb.closeTransaction(pTrans);
 
380
    return NDBT_FAILED;
 
381
  }
 
382
 
 
383
  check = pOp4->setValue("ACCOUNT_TYPE", fromAccountType);
 
384
  if( check == -1 ) {
 
385
    ERR(pTrans->getNdbError());
 
386
    m_ndb.closeTransaction(pTrans);
 
387
    return NDBT_FAILED;
 
388
  }
 
389
 
 
390
  check = pOp4->setValue("OTHER_ACCOUNT", toAccountId);
 
391
  if( check == -1 ) {
 
392
    ERR(pTrans->getNdbError());
 
393
    m_ndb.closeTransaction(pTrans);
 
394
    return NDBT_FAILED;
 
395
  }
 
396
 
 
397
  check = pOp4->setValue("TRANSACTION_TYPE", WithDrawal);
 
398
  if( check == -1 ) {
 
399
    ERR(pTrans->getNdbError());
 
400
    m_ndb.closeTransaction(pTrans);
 
401
    return NDBT_FAILED;
 
402
  }
 
403
    
 
404
  check = pOp4->setValue("TIME", currTime);
 
405
  if( check == -1 ) {
 
406
    ERR(pTrans->getNdbError());
 
407
    m_ndb.closeTransaction(pTrans);
 
408
    return NDBT_FAILED;
 
409
  }
 
410
 
 
411
  check = pOp4->setValue("AMOUNT", amount);
 
412
  if( check == -1 ) {
 
413
    ERR(pTrans->getNdbError());
 
414
    m_ndb.closeTransaction(pTrans);
 
415
    return NDBT_FAILED;
 
416
  }
 
417
 
 
418
  /**
 
419
   * Insert deposit transaction
 
420
   */
 
421
  NdbOperation* pOp5 = pTrans->getNdbOperation("TRANSACTION");
 
422
  if (pOp5 == NULL) {
 
423
    ERR(pTrans->getNdbError());
 
424
    m_ndb.closeTransaction(pTrans);
 
425
    return NDBT_FAILED;
 
426
  }
 
427
    
 
428
  check = pOp5->insertTuple();
 
429
  if( check == -1 ) {
 
430
    ERR(pTrans->getNdbError());
 
431
    m_ndb.closeTransaction(pTrans);
 
432
    return NDBT_FAILED;
 
433
  }
 
434
    
 
435
  check = pOp5->equal("TRANSACTION_ID", transId);
 
436
  if( check == -1 ) {
 
437
    ERR(pTrans->getNdbError());
 
438
    m_ndb.closeTransaction(pTrans);
 
439
    return NDBT_FAILED;
 
440
  }
 
441
 
 
442
  check = pOp5->equal("ACCOUNT", toAccountId);
 
443
  if( check == -1 ) {
 
444
    ERR(pTrans->getNdbError());
 
445
    m_ndb.closeTransaction(pTrans);
 
446
    return NDBT_FAILED;
 
447
  }
 
448
 
 
449
  check = pOp5->setValue("ACCOUNT_TYPE", toAccountType);
 
450
  if( check == -1 ) {
 
451
    ERR(pTrans->getNdbError());
 
452
    m_ndb.closeTransaction(pTrans);
 
453
    return NDBT_FAILED;
 
454
  }
 
455
 
 
456
  check = pOp5->setValue("OTHER_ACCOUNT", fromAccountId);
 
457
  if( check == -1 ) {
 
458
    ERR(pTrans->getNdbError());
 
459
    m_ndb.closeTransaction(pTrans);
 
460
    return NDBT_FAILED;
 
461
  }
 
462
 
 
463
  check = pOp5->setValue("TRANSACTION_TYPE", Deposit);
 
464
  if( check == -1 ) {
 
465
    ERR(pTrans->getNdbError());
 
466
    m_ndb.closeTransaction(pTrans);
 
467
    return NDBT_FAILED;
 
468
  }
 
469
 
 
470
  check = pOp5->setValue("TIME", currTime);
 
471
  if( check == -1 ) {
 
472
    ERR(pTrans->getNdbError());
 
473
    m_ndb.closeTransaction(pTrans);
 
474
    return NDBT_FAILED;
 
475
  }
 
476
 
 
477
  check = pOp5->setValue("AMOUNT", amount);
 
478
  if( check == -1 ) {
 
479
    ERR(pTrans->getNdbError());
 
480
    m_ndb.closeTransaction(pTrans);
 
481
    return NDBT_FAILED;
 
482
  }
 
483
 
 
484
  check = pTrans->execute(Commit);
 
485
  if( check == -1 ) {
 
486
    const NdbError err = pTrans->getNdbError();
 
487
    m_ndb.closeTransaction(pTrans);    
 
488
    if (err.status == NdbError::TemporaryError){
 
489
      ERR(err);
 
490
      return NDBT_TEMPORARY;
 
491
    }
 
492
    ERR(err);
 
493
    return NDBT_FAILED;
 
494
  }
 
495
    
 
496
  m_ndb.closeTransaction(pTrans);      
 
497
  return NDBT_OK;  
 
498
}
 
499
 
 
500
 
 
501
    
 
502
 
 
503
int Bank::performMakeGLs(int yield){
 
504
  int result;
 
505
  
 
506
  int counter, maxCounter;
 
507
  int yieldCounter = 0;
 
508
 
 
509
  while (1){
 
510
    // Counters to keep tracck of how many
 
511
    // GLs should be made before performing a validation
 
512
    counter = 0;
 
513
    maxCounter = 50 + myRandom48(100);
 
514
    
 
515
    /** 
 
516
     * Validate GLs and Transactions for previous days
 
517
     *
 
518
     */
 
519
    result = performValidateGLs();
 
520
    if (result != NDBT_OK){
 
521
      if (result == VERIFICATION_FAILED){
 
522
        g_err << "performValidateGLs verification failed" << endl;
 
523
        return NDBT_FAILED;
 
524
      }
 
525
      g_info << "performValidateGLs failed" << endl;
 
526
      return NDBT_FAILED;
 
527
      continue;
 
528
    }
 
529
 
 
530
    result = performValidatePurged();
 
531
    if (result != NDBT_OK){
 
532
      if (result == VERIFICATION_FAILED){
 
533
        g_err << "performValidatePurged verification failed" << endl;
 
534
        return NDBT_FAILED;
 
535
      }
 
536
      g_info << "performValidatePurged failed" << endl;
 
537
      return NDBT_FAILED;
 
538
    }
 
539
 
 
540
    while (1){
 
541
 
 
542
      yieldCounter++;
 
543
      if (yield != 0 && yieldCounter >= yield)
 
544
        return NDBT_OK;
 
545
 
 
546
      /**
 
547
       * Find last GL time.  
 
548
       * ( GL record with highest time value)
 
549
       */
 
550
      Uint64 lastGLTime;
 
551
      if (findLastGL(lastGLTime) != NDBT_OK){   
 
552
        g_info << "findLastGL failed" << endl;
 
553
        // Break out of inner while loop
 
554
        break;
 
555
      }
 
556
      
 
557
      lastGLTime++;
 
558
      
 
559
      /** 
 
560
       * If last GL time + 1 is smaller than current time
 
561
       * perform a GL for that time
 
562
       */
 
563
      Uint64 currTime;
 
564
      if (getCurrTime(currTime) != NDBT_OK){
 
565
        g_info << "getCurrTime failed" << endl;
 
566
        // Break out of inner while loop
 
567
        break;
 
568
      }      
 
569
      if (lastGLTime < currTime){
 
570
        counter++;
 
571
        if (performMakeGL(lastGLTime) != NDBT_OK){
 
572
          g_info << "performMakeGL failed" << endl;
 
573
        // Break out of inner while loop
 
574
          break;
 
575
        }
 
576
        
 
577
        if (counter > maxCounter){
 
578
          // Break out of inner while loop and 
 
579
          // validatePreviousGLs
 
580
          g_info << "counter("<<counter<<") > maxCounter("<<maxCounter<<")" << endl;
 
581
          break;
 
582
        }
 
583
 
 
584
      } else {
 
585
        ;//ndbout << "It's not time to make GL yet" << endl;
 
586
 
 
587
        // ndbout << "Sleeping 1 second" << endl;
 
588
        NdbSleep_SecSleep(1);      
 
589
 
 
590
      }
 
591
      
 
592
      Uint32 age = 3;
 
593
      if (purgeOldGLTransactions(currTime, age) != NDBT_OK){
 
594
        g_info << "purgeOldGLTransactions failed" << endl;
 
595
        // Break out of inner while loop
 
596
        break;
 
597
      }     
 
598
            
 
599
    }
 
600
  }
 
601
    
 
602
  return NDBT_FAILED;
 
603
  
 
604
}
 
605
 
 
606
int Bank::performValidateAllGLs(){
 
607
  int result;
 
608
  
 
609
  while (1){
 
610
    
 
611
    /** 
 
612
     * Validate GLs and Transactions for previous days
 
613
     * Set age so that ALL GL's are validated
 
614
     */
 
615
    int age = 100000;
 
616
    result = performValidateGLs(age);
 
617
    if (result != NDBT_OK){
 
618
      if (result == VERIFICATION_FAILED){
 
619
        g_err << "performValidateGLs verification failed" << endl;
 
620
        return NDBT_FAILED;
 
621
      }
 
622
      g_err << "performValidateGLs failed" << endl;
 
623
      return NDBT_FAILED;
 
624
    }
 
625
 
 
626
    /**
 
627
     * 
 
628
     *
 
629
     */
 
630
    result = performValidatePurged();
 
631
    if (result != NDBT_OK){
 
632
      if (result == VERIFICATION_FAILED){
 
633
        g_err << "performValidatePurged verification failed" << endl;
 
634
        return NDBT_FAILED;
 
635
      }
 
636
      g_err << "performValidatePurged failed" << endl;
 
637
      return NDBT_FAILED;
 
638
    }
 
639
    return NDBT_OK;
 
640
  }
 
641
    
 
642
  return NDBT_FAILED;
 
643
  
 
644
}
 
645
 
 
646
int Bank::findLastGL(Uint64 &lastTime){
 
647
 
 
648
 int check;  
 
649
  /**
 
650
   * SELECT MAX(time) FROM GL
 
651
   */
 
652
  NdbConnection* pScanTrans = m_ndb.startTransaction();
 
653
  if (pScanTrans == NULL) {
 
654
    ERR(m_ndb.getNdbError());
 
655
    return NDBT_FAILED;
 
656
  }
 
657
      
 
658
  NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");        
 
659
  if (pOp == NULL) {
 
660
    ERR(pScanTrans->getNdbError());
 
661
    m_ndb.closeTransaction(pScanTrans);
 
662
    return NDBT_FAILED;
 
663
  }
 
664
 
 
665
  if( pOp->readTuples() ) {
 
666
    ERR(pScanTrans->getNdbError());
 
667
    m_ndb.closeTransaction(pScanTrans);
 
668
    return NDBT_FAILED;
 
669
  }
 
670
 
 
671
  check = pOp->interpret_exit_ok();
 
672
  if( check == -1 ) {
 
673
    ERR(pScanTrans->getNdbError());
 
674
    m_ndb.closeTransaction(pScanTrans);
 
675
    return NDBT_FAILED;
 
676
  }
 
677
 
 
678
  NdbRecAttr* timeRec = pOp->getValue("TIME");
 
679
  if( timeRec ==NULL ) {
 
680
    ERR(pScanTrans->getNdbError());
 
681
    m_ndb.closeTransaction(pScanTrans);
 
682
    return NDBT_FAILED;
 
683
  }
 
684
 
 
685
  check = pScanTrans->execute(NoCommit);
 
686
  if( check == -1 ) {
 
687
    ERR(pScanTrans->getNdbError());
 
688
    m_ndb.closeTransaction(pScanTrans);
 
689
    return NDBT_FAILED;
 
690
  }
 
691
    
 
692
  int eof;
 
693
  int rows = 0;
 
694
  eof = pOp->nextResult();
 
695
  lastTime = 0;
 
696
    
 
697
  while(eof == 0){
 
698
    rows++;
 
699
    Uint64 t = timeRec->u_32_value();
 
700
 
 
701
    if (t > lastTime)
 
702
      lastTime = t;
 
703
    
 
704
    eof = pOp->nextResult();
 
705
  }
 
706
  if (eof == -1) {
 
707
    ERR(pScanTrans->getNdbError());
 
708
    m_ndb.closeTransaction(pScanTrans);
 
709
    return NDBT_FAILED;
 
710
  }
 
711
    
 
712
  m_ndb.closeTransaction(pScanTrans);
 
713
  
 
714
  return NDBT_OK;
 
715
}
 
716
 
 
717
 
 
718
int Bank::performMakeGL(int time){
 
719
  g_info << "performMakeGL: " << time << endl;
 
720
  /**
 
721
   *  Create one GL record for each account type.
 
722
   *  All in the same transaction
 
723
   */
 
724
  // Start transaction    
 
725
  NdbConnection* pTrans = m_ndb.startTransaction();
 
726
  if (pTrans == NULL){
 
727
    ERR(m_ndb.getNdbError());
 
728
    return NDBT_FAILED;
 
729
  }
 
730
  for (int i = 0; i < getNumAccountTypes(); i++){
 
731
  
 
732
    if (performMakeGLForAccountType(pTrans, time, i) != NDBT_OK){
 
733
      g_err << "performMakeGLForAccountType returned NDBT_FAILED"<<endl;
 
734
      m_ndb.closeTransaction(pTrans);      
 
735
      return NDBT_FAILED;
 
736
    }
 
737
  }
 
738
  // Execute transaction    
 
739
  if( pTrans->execute(Commit) == -1 ) {
 
740
    ERR(pTrans->getNdbError());
 
741
    m_ndb.closeTransaction(pTrans);
 
742
    return NDBT_FAILED;
 
743
  }    
 
744
  m_ndb.closeTransaction(pTrans);      
 
745
  
 
746
  return NDBT_OK;
 
747
}
 
748
 
 
749
int Bank::performMakeGLForAccountType(NdbConnection* pTrans, 
 
750
                                      Uint64 glTime,
 
751
                                      Uint32 accountTypeId){
 
752
  int check;
 
753
 
 
754
  Uint32 balance = 0;
 
755
  Uint32 withdrawalCount = 0;
 
756
  Uint32 withdrawalSum = 0;
 
757
  Uint32 depositSum = 0;
 
758
  Uint32 depositCount = 0;
 
759
  Uint32 countTransactions = 0;
 
760
  Uint32 purged = 0;
 
761
 
 
762
  // Insert record in GL so that we know
 
763
  // that no one else is performing the same task
 
764
  // Set purged = 0 to indicate that TRANSACTION
 
765
  // records still exist
 
766
  NdbOperation* pOp = pTrans->getNdbOperation("GL");
 
767
  if (pOp == NULL) {
 
768
    ERR(pTrans->getNdbError());
 
769
    return NDBT_FAILED;
 
770
  }
 
771
    
 
772
  check = pOp->insertTuple();
 
773
  if( check == -1 ) {
 
774
    ERR(pTrans->getNdbError());
 
775
    return NDBT_FAILED;
 
776
  }
 
777
      
 
778
  check = pOp->equal("TIME", glTime);
 
779
  if( check == -1 ) {
 
780
    ERR(pTrans->getNdbError());
 
781
    return NDBT_FAILED;
 
782
  }
 
783
 
 
784
  check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
 
785
  if( check == -1 ) {
 
786
    ERR(pTrans->getNdbError());
 
787
    return NDBT_FAILED;
 
788
  }
 
789
 
 
790
  check = pOp->setValue("BALANCE", balance);
 
791
  if( check == -1 ) {
 
792
    ERR(pTrans->getNdbError());
 
793
    return NDBT_FAILED;
 
794
  }
 
795
 
 
796
  check = pOp->setValue("DEPOSIT_COUNT", depositCount);
 
797
  if( check == -1 ) {
 
798
    ERR(pTrans->getNdbError());
 
799
    return NDBT_FAILED;
 
800
  }
 
801
 
 
802
  check = pOp->setValue("DEPOSIT_SUM", depositSum);
 
803
  if( check == -1 ) {
 
804
    ERR(pTrans->getNdbError());
 
805
    return NDBT_FAILED;
 
806
  }
 
807
 
 
808
  check = pOp->setValue("WITHDRAWAL_COUNT", withdrawalCount);
 
809
  if( check == -1 ) {
 
810
    ERR(pTrans->getNdbError());
 
811
    return NDBT_FAILED;
 
812
  }
 
813
 
 
814
  check = pOp->setValue("WITHDRAWAL_SUM", withdrawalSum);
 
815
  if( check == -1 ) {
 
816
    ERR(pTrans->getNdbError());
 
817
    return NDBT_FAILED;
 
818
  }
 
819
 
 
820
  check = pOp->setValue("PURGED", purged);
 
821
  if( check == -1 ) {
 
822
    ERR(pTrans->getNdbError());
 
823
    return NDBT_FAILED;
 
824
  }
 
825
      
 
826
  check = pTrans->execute(NoCommit);
 
827
  if( check == -1 ) {
 
828
    ERR(pOp->getNdbError());
 
829
    return NDBT_FAILED;
 
830
  }
 
831
 
 
832
  // Read previous GL record to get old balance
 
833
  NdbOperation* pOp2 = pTrans->getNdbOperation("GL");
 
834
  if (pOp2 == NULL) {
 
835
    ERR(pTrans->getNdbError());
 
836
    return NDBT_FAILED;
 
837
  }
 
838
    
 
839
  check = pOp2->readTuple();
 
840
  if( check == -1 ) {
 
841
    ERR(pTrans->getNdbError());
 
842
    return NDBT_FAILED;
 
843
  }
 
844
      
 
845
  check = pOp2->equal("TIME", glTime-1);
 
846
  if( check == -1 ) {
 
847
    ERR(pTrans->getNdbError());
 
848
    return NDBT_FAILED;
 
849
  }
 
850
 
 
851
  check = pOp2->equal("ACCOUNT_TYPE", accountTypeId);
 
852
  if( check == -1 ) {
 
853
    ERR(pTrans->getNdbError());
 
854
    return NDBT_FAILED;
 
855
  }
 
856
 
 
857
  NdbRecAttr* oldBalanceRec = pOp2->getValue("BALANCE");
 
858
  if( oldBalanceRec == NULL ) {
 
859
    ERR(pTrans->getNdbError());
 
860
    return NDBT_FAILED;
 
861
  }
 
862
 
 
863
  check = pTrans->execute(NoCommit);
 
864
  if( check == -1 ) {
 
865
    ERR(pOp2->getNdbError());
 
866
    return NDBT_FAILED;
 
867
  }    
 
868
 
 
869
  Uint32 oldBalance = oldBalanceRec->u_32_value();
 
870
  //  ndbout << "oldBalance = "<<oldBalance<<endl;
 
871
  balance = oldBalance;
 
872
  // Start a scan transaction to search
 
873
  // for TRANSACTION records with TIME = time 
 
874
  // and ACCOUNT_TYPE = accountTypeId
 
875
  // Build sum of all found transactions
 
876
    
 
877
  if (sumTransactionsForGL(glTime, 
 
878
                           accountTypeId,
 
879
                           balance,
 
880
                           withdrawalCount,
 
881
                           withdrawalSum,
 
882
                           depositSum,
 
883
                           depositCount,
 
884
                           countTransactions,
 
885
                           pTrans) != NDBT_OK){
 
886
    return NDBT_FAILED;
 
887
  }
 
888
  //  ndbout << "sumTransactionsForGL completed" << endl;
 
889
  //  ndbout << "balance="<<balance<<endl
 
890
  //     << "withdrawalCount="<<withdrawalCount<<endl
 
891
  //     << "withdrawalSum="<<withdrawalSum<<endl
 
892
  //     << "depositCount="<<depositCount<<endl
 
893
  //     << "depositSum="<<depositSum<<endl;
 
894
      
 
895
 
 
896
 
 
897
  NdbOperation* pOp3 = pTrans->getNdbOperation("GL");
 
898
  if (pOp3 == NULL) {
 
899
    ERR(pTrans->getNdbError());
 
900
    return NDBT_FAILED;
 
901
  }
 
902
    
 
903
  check = pOp3->updateTuple();
 
904
  if( check == -1 ) {
 
905
    ERR(pTrans->getNdbError());
 
906
    return NDBT_FAILED;
 
907
  }
 
908
      
 
909
  check = pOp3->equal("TIME", glTime);
 
910
  if( check == -1 ) {
 
911
    ERR(pTrans->getNdbError());
 
912
    return NDBT_FAILED;
 
913
  }
 
914
 
 
915
  check = pOp3->equal("ACCOUNT_TYPE", accountTypeId);
 
916
  if( check == -1 ) {
 
917
    ERR(pTrans->getNdbError());
 
918
    return NDBT_FAILED;
 
919
  }
 
920
 
 
921
  check = pOp3->setValue("BALANCE", balance);
 
922
  if( check == -1 ) {
 
923
    ERR(pTrans->getNdbError());
 
924
    return NDBT_FAILED;
 
925
  }
 
926
 
 
927
  check = pOp3->setValue("DEPOSIT_COUNT", depositCount);
 
928
  if( check == -1 ) {
 
929
    ERR(pTrans->getNdbError());
 
930
    return NDBT_FAILED;
 
931
  }
 
932
 
 
933
  check = pOp3->setValue("DEPOSIT_SUM", depositSum);
 
934
  if( check == -1 ) {
 
935
    ERR(pTrans->getNdbError());
 
936
    return NDBT_FAILED;
 
937
  }
 
938
 
 
939
  check = pOp3->setValue("WITHDRAWAL_COUNT", withdrawalCount);
 
940
  if( check == -1 ) {
 
941
    ERR(pTrans->getNdbError());
 
942
    return NDBT_FAILED;
 
943
  }
 
944
 
 
945
  check = pOp3->setValue("WITHDRAWAL_SUM", withdrawalSum);
 
946
  if( check == -1 ) {
 
947
    ERR(pTrans->getNdbError());
 
948
    return NDBT_FAILED;
 
949
  }
 
950
 
 
951
  check = pOp3->setValue("PURGED", purged);
 
952
  if( check == -1 ) {
 
953
    ERR(pTrans->getNdbError());
 
954
    return NDBT_FAILED;
 
955
  }
 
956
 
 
957
  // Execute transaction    
 
958
  check = pTrans->execute(NoCommit);
 
959
  if( check == -1 ) {
 
960
    ERR(pTrans->getNdbError());
 
961
    return NDBT_FAILED;
 
962
  }    
 
963
 
 
964
  return NDBT_OK;
 
965
}
 
966
 
 
967
 
 
968
 
 
969
 
 
970
int Bank::sumTransactionsForGL(const Uint64 glTime, 
 
971
                               const Uint32 accountType,
 
972
                               Uint32& balance,
 
973
                               Uint32& withdrawalCount,
 
974
                               Uint32& withdrawalSum,
 
975
                               Uint32& depositSum,
 
976
                               Uint32& depositCount,
 
977
                               Uint32& transactionsCount,
 
978
                               NdbConnection* pTrans){
 
979
  int check;
 
980
 
 
981
  //  g_info << "sumTransactionsForGL: " << glTime << ", " << accountType << endl;
 
982
    
 
983
  NdbConnection* pScanTrans = m_ndb.startTransaction();
 
984
  if (pScanTrans == NULL) {
 
985
    ERR(m_ndb.getNdbError());
 
986
    return NDBT_FAILED;
 
987
  }
 
988
      
 
989
  NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");
 
990
  if (pOp == NULL) {
 
991
    ERR(pScanTrans->getNdbError());
 
992
    m_ndb.closeTransaction(pScanTrans);
 
993
    return NDBT_FAILED;
 
994
  }
 
995
 
 
996
  if( pOp->readTuplesExclusive()) {
 
997
    ERR(pScanTrans->getNdbError());
 
998
    m_ndb.closeTransaction(pScanTrans);
 
999
    return NDBT_FAILED;
 
1000
  }
 
1001
 
 
1002
  check = pOp->interpret_exit_ok();
 
1003
  if( check == -1 ) {
 
1004
    ERR(pScanTrans->getNdbError());
 
1005
    m_ndb.closeTransaction(pScanTrans);
 
1006
    return NDBT_FAILED;
 
1007
  }
 
1008
 
 
1009
  NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1010
  if( accountTypeRec ==NULL ) {
 
1011
    ERR(pScanTrans->getNdbError());
 
1012
    m_ndb.closeTransaction(pScanTrans);
 
1013
    return NDBT_FAILED;
 
1014
  }
 
1015
 
 
1016
  NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1017
  if( timeRec ==NULL ) {
 
1018
    ERR(pScanTrans->getNdbError());
 
1019
    m_ndb.closeTransaction(pScanTrans);
 
1020
    return NDBT_FAILED;
 
1021
  }
 
1022
 
 
1023
  NdbRecAttr* transTypeRec = pOp->getValue("TRANSACTION_TYPE");
 
1024
  if( transTypeRec ==NULL ) {
 
1025
    ERR(pScanTrans->getNdbError());
 
1026
    m_ndb.closeTransaction(pScanTrans);
 
1027
    return NDBT_FAILED;
 
1028
  }
 
1029
 
 
1030
  NdbRecAttr* amountRec = pOp->getValue("AMOUNT");
 
1031
  if( amountRec ==NULL ) {
 
1032
    ERR(pScanTrans->getNdbError());
 
1033
    m_ndb.closeTransaction(pScanTrans);
 
1034
    return NDBT_FAILED;
 
1035
  }
 
1036
 
 
1037
  check = pScanTrans->execute(NoCommit);
 
1038
  if( check == -1 ) {
 
1039
    ERR(pScanTrans->getNdbError());
 
1040
    m_ndb.closeTransaction(pScanTrans);
 
1041
    return NDBT_FAILED;
 
1042
  }
 
1043
    
 
1044
  int eof;
 
1045
  int rows = 0;
 
1046
  int rowsFound = 0;
 
1047
  eof = pOp->nextResult();
 
1048
    
 
1049
  while(eof == 0){
 
1050
    rows++;
 
1051
    Uint32 a = accountTypeRec->u_32_value();
 
1052
    Uint64 t = timeRec->u_64_value();
 
1053
 
 
1054
    if (a == accountType && t == glTime){
 
1055
      rowsFound++;
 
1056
      // One record found
 
1057
      int transType = transTypeRec->u_32_value();
 
1058
      int amount = amountRec->u_32_value();
 
1059
      if (transType == WithDrawal){
 
1060
        withdrawalCount++;
 
1061
        withdrawalSum += amount;
 
1062
        balance -= amount;
 
1063
      } else {    
 
1064
        assert(transType == Deposit);
 
1065
        depositCount++;
 
1066
        depositSum += amount;
 
1067
        balance += amount;
 
1068
      }
 
1069
    }
 
1070
 
 
1071
    eof = pOp->nextResult();
 
1072
 
 
1073
    if ((rows % 100) == 0){
 
1074
      // "refresh" ownner transaction every 100th row
 
1075
      if (pTrans->refresh() == -1) {
 
1076
        ERR(pTrans->getNdbError());
 
1077
        return NDBT_FAILED;
 
1078
      }
 
1079
    }
 
1080
 
 
1081
  }
 
1082
  if (eof == -1) {
 
1083
    ERR(pScanTrans->getNdbError());
 
1084
    m_ndb.closeTransaction(pScanTrans);
 
1085
    return NDBT_FAILED;
 
1086
  }
 
1087
    
 
1088
  m_ndb.closeTransaction(pScanTrans);
 
1089
  //  ndbout << rows << " TRANSACTIONS have been read" << endl;
 
1090
  transactionsCount = rowsFound;
 
1091
 
 
1092
  return NDBT_OK;
 
1093
 
 
1094
}
 
1095
 
 
1096
 int Bank::performValidateGLs(Uint64 age){
 
1097
 
 
1098
  Uint64 currTime;
 
1099
  if (getCurrTime(currTime) != NDBT_OK){
 
1100
    return NDBT_FAILED;
 
1101
  }
 
1102
  Uint64 glTime = currTime - 1;
 
1103
  while((glTime > 0) && ((glTime + age) >= currTime)){
 
1104
    
 
1105
    int result = performValidateGL(glTime);
 
1106
    if (result != NDBT_OK){
 
1107
      g_err << "performValidateGL failed" << endl;
 
1108
      return result;
 
1109
    }
 
1110
    
 
1111
    glTime--;
 
1112
  }
 
1113
  
 
1114
  return NDBT_OK;
 
1115
 }
 
1116
 
 
1117
int Bank::performValidateGL(Uint64 glTime){
 
1118
   
 
1119
   ndbout << "performValidateGL: " << glTime << endl;
 
1120
   /**
 
1121
    * Rules: 
 
1122
    * - There should be zero or NoAccountTypes GL records for each glTime
 
1123
    * - If purged == 0, then the TRANSACTION table should be checked
 
1124
    *   to see that there are:
 
1125
    *   + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
 
1126
    *     and TIME == glTime. The sum of these transactions should be 
 
1127
    *     DEPOSIT_SUM
 
1128
    *   + WITHDRAWAL_COUNT withdrawal transactions with account_type == 
 
1129
    *     ACCOUNT_TYPE and TIME == glTime. The sum of these transactions 
 
1130
    *     should be WITHDRAWAL_SUM
 
1131
    *   + BALANCE should be equal to the sum of all transactions plus
 
1132
    *     the balance of the previous GL record
 
1133
    * - If purged == 1 then there should be NO transactions with TIME == glTime
 
1134
    *   and ACCOUNT_TYPE == account_type
 
1135
    *  
 
1136
    */ 
 
1137
 
 
1138
   int check;  
 
1139
   /**
 
1140
    * SELECT * FROM GL WHERE account_type = @accountType and time = @time
 
1141
    */
 
1142
   NdbConnection* pScanTrans = m_ndb.startTransaction();
 
1143
   if (pScanTrans == NULL) {
 
1144
     ERR(m_ndb.getNdbError());
 
1145
     return NDBT_FAILED;
 
1146
   }
 
1147
   
 
1148
   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");       
 
1149
   if (pOp == NULL) {
 
1150
     ERR(pScanTrans->getNdbError());
 
1151
     m_ndb.closeTransaction(pScanTrans);
 
1152
     return NDBT_FAILED;
 
1153
   }
 
1154
   
 
1155
   if( pOp->readTuples() ) {
 
1156
     ERR(pScanTrans->getNdbError());
 
1157
     m_ndb.closeTransaction(pScanTrans);
 
1158
     return NDBT_FAILED;
 
1159
   }
 
1160
   
 
1161
   check = pOp->interpret_exit_ok();
 
1162
   if( check == -1 ) {
 
1163
     ERR(pScanTrans->getNdbError());
 
1164
     m_ndb.closeTransaction(pScanTrans);
 
1165
     return NDBT_FAILED;
 
1166
   }
 
1167
   
 
1168
   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1169
   if( accountTypeRec ==NULL ) {
 
1170
     ERR(pScanTrans->getNdbError());
 
1171
     m_ndb.closeTransaction(pScanTrans);
 
1172
     return NDBT_FAILED;
 
1173
   }
 
1174
 
 
1175
  NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1176
  if( timeRec ==NULL ) {
 
1177
    ERR(pScanTrans->getNdbError());
 
1178
    m_ndb.closeTransaction(pScanTrans);
 
1179
    return NDBT_FAILED;
 
1180
  }
 
1181
 
 
1182
  NdbRecAttr* purgedRec = pOp->getValue("PURGED");
 
1183
  if( purgedRec ==NULL ) {
 
1184
    ERR(pScanTrans->getNdbError());
 
1185
    m_ndb.closeTransaction(pScanTrans);
 
1186
    return NDBT_FAILED;
 
1187
  }
 
1188
 
 
1189
  NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
 
1190
  if( balanceRec ==NULL ) {
 
1191
    ERR(pScanTrans->getNdbError());
 
1192
    m_ndb.closeTransaction(pScanTrans);
 
1193
    return NDBT_FAILED;
 
1194
  }
 
1195
 
 
1196
  NdbRecAttr* depositSumRec = pOp->getValue("DEPOSIT_SUM");
 
1197
  if( depositSumRec ==NULL ) {
 
1198
    ERR(pScanTrans->getNdbError());
 
1199
    m_ndb.closeTransaction(pScanTrans);
 
1200
    return NDBT_FAILED;
 
1201
  }
 
1202
 
 
1203
  NdbRecAttr* depositCountRec = pOp->getValue("DEPOSIT_COUNT");
 
1204
  if( depositCountRec ==NULL ) {
 
1205
    ERR(pScanTrans->getNdbError());
 
1206
    m_ndb.closeTransaction(pScanTrans);
 
1207
    return NDBT_FAILED;
 
1208
  }
 
1209
 
 
1210
  NdbRecAttr* withdrawalSumRec = pOp->getValue("WITHDRAWAL_SUM");
 
1211
  if( withdrawalSumRec ==NULL ) {
 
1212
    ERR(pScanTrans->getNdbError());
 
1213
    m_ndb.closeTransaction(pScanTrans);
 
1214
    return NDBT_FAILED;
 
1215
  }
 
1216
  NdbRecAttr* withdrawalCountRec = pOp->getValue("WITHDRAWAL_COUNT");
 
1217
  if( withdrawalCountRec ==NULL ) {
 
1218
    ERR(pScanTrans->getNdbError());
 
1219
    m_ndb.closeTransaction(pScanTrans);
 
1220
    return NDBT_FAILED;
 
1221
  }
 
1222
 
 
1223
  check = pScanTrans->execute(NoCommit);
 
1224
  if( check == -1 ) {
 
1225
    ERR(pScanTrans->getNdbError());
 
1226
    m_ndb.closeTransaction(pScanTrans);
 
1227
    return NDBT_FAILED;
 
1228
  }
 
1229
 
 
1230
  int eof;
 
1231
  int rows = 0;
 
1232
  int countGlRecords = 0;
 
1233
  int result = NDBT_OK;
 
1234
  eof = pOp->nextResult();
 
1235
    
 
1236
  while(eof == 0){
 
1237
    rows++;
 
1238
    Uint64 t = timeRec->u_64_value();
 
1239
 
 
1240
    if (t == glTime){
 
1241
      countGlRecords++;
 
1242
      Uint32 a = accountTypeRec->u_32_value();
 
1243
      Uint32 purged = purgedRec->u_32_value();
 
1244
      Uint32 wsum = withdrawalSumRec->u_32_value();
 
1245
      Uint32 wcount = withdrawalCountRec->u_32_value();
 
1246
      Uint32 dsum = depositSumRec->u_32_value();
 
1247
      Uint32 dcount = depositCountRec->u_32_value();
 
1248
      Uint32 b = balanceRec->u_32_value();
 
1249
 
 
1250
      Uint32 balance = 0; 
 
1251
      Uint32 withdrawalSum = 0;
 
1252
      Uint32 withdrawalCount = 0;
 
1253
      Uint32 depositSum = 0;
 
1254
      Uint32 depositCount = 0;
 
1255
      Uint32 countTransactions = 0;
 
1256
      if (purged == 0){ 
 
1257
        // If purged == 0, then the TRANSACTION table should be checked
 
1258
        // to see that there are:
 
1259
        // + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
 
1260
        //   and TIME == glTime. The sum of these transactions should be 
 
1261
        //   DEPOSIT_SUM
 
1262
        // + WITHDRAWAL_COUNT withdrawal transactions with account_type == 
 
1263
        //   ACCOUNT_TYPE and TIME == glTime. The sum of these transactions 
 
1264
        //   should be WITHDRAWAL_SUM
 
1265
        // + BALANCE should be equal to the sum of all transactions plus
 
1266
        //   the balance of the previous GL record      
 
1267
        if (sumTransactionsForGL(t, 
 
1268
                                 a,
 
1269
                                 balance,
 
1270
                                 withdrawalCount,
 
1271
                                 withdrawalSum,
 
1272
                                 depositSum,
 
1273
                                 depositCount,
 
1274
                                 countTransactions,
 
1275
                                 pScanTrans) != NDBT_OK){
 
1276
          result = NDBT_FAILED;   
 
1277
        } else {
 
1278
          Uint32 prevBalance = 0;
 
1279
          if (getBalanceForGL(t-1, a, prevBalance) != NDBT_OK){
 
1280
            result = NDBT_FAILED;
 
1281
          } else
 
1282
          if (((prevBalance + balance) != b) ||
 
1283
              (wsum != withdrawalSum) ||
 
1284
              (wcount != withdrawalCount) ||
 
1285
              (dsum != depositSum) ||
 
1286
              (dcount != depositCount)){
 
1287
            g_err << "performValidateGL, sums and counts failed" << endl
 
1288
                  << "balance   :   " << balance+prevBalance << "!="<<b<<endl
 
1289
                  << "with sum  :   " << withdrawalSum << "!="<<wsum<<endl
 
1290
                  << "with count:   " << withdrawalCount << "!="<<wcount<<endl
 
1291
                  << "dep sum   :   " << depositSum << "!="<<dsum<<endl
 
1292
                  << "dep count :   " << depositCount << "!="<<dcount<<endl;
 
1293
            result = VERIFICATION_FAILED;
 
1294
          }
 
1295
            }     
 
1296
 
 
1297
      } else {
 
1298
        assert(purged == 1);
 
1299
        // If purged == 1 then there should be NO transactions with 
 
1300
        // TIME == glTime and ACCOUNT_TYPE == account_type
 
1301
        
 
1302
        if (sumTransactionsForGL(t, 
 
1303
                                 a,
 
1304
                                 balance,
 
1305
                                 withdrawalCount,
 
1306
                                 withdrawalSum,
 
1307
                                 depositSum,
 
1308
                                 depositCount,
 
1309
                                 countTransactions,
 
1310
                                 pScanTrans) != NDBT_OK){
 
1311
          result = NDBT_FAILED;   
 
1312
        } else {
 
1313
          if (countTransactions != 0){
 
1314
            g_err << "performValidateGL, countTransactions("<<countTransactions<<") != 0" << endl;
 
1315
            result = VERIFICATION_FAILED;
 
1316
          }
 
1317
        }        
 
1318
      }
 
1319
 
 
1320
    }
 
1321
    eof = pOp->nextResult();
 
1322
  }
 
1323
  if (eof == -1) {
 
1324
    ERR(pScanTrans->getNdbError());
 
1325
    m_ndb.closeTransaction(pScanTrans);
 
1326
    return NDBT_FAILED;
 
1327
  }
 
1328
    
 
1329
  m_ndb.closeTransaction(pScanTrans);
 
1330
 
 
1331
  // - There should be zero or NoAccountTypes GL records for each glTime
 
1332
  if ((countGlRecords != 0) && (countGlRecords != getNumAccountTypes())){
 
1333
    g_err << "performValidateGL: " << endl
 
1334
           << "countGlRecords = " << countGlRecords << endl;
 
1335
    result = VERIFICATION_FAILED;
 
1336
  }
 
1337
 
 
1338
  return result;
 
1339
 
 
1340
   
 
1341
 }
 
1342
 
 
1343
int Bank::getBalanceForGL(const Uint64 glTime,
 
1344
                          const Uint32 accountTypeId,
 
1345
                          Uint32 &balance){
 
1346
  int check;
 
1347
 
 
1348
  NdbConnection* pTrans = m_ndb.startTransaction();
 
1349
  if (pTrans == NULL) {
 
1350
    ERR(m_ndb.getNdbError());
 
1351
    return NDBT_FAILED;
 
1352
  }
 
1353
  
 
1354
  NdbOperation* pOp = pTrans->getNdbOperation("GL");
 
1355
  if (pOp == NULL) {
 
1356
    ERR(pTrans->getNdbError());
 
1357
    return NDBT_FAILED;
 
1358
  }
 
1359
    
 
1360
  check = pOp->readTuple();
 
1361
  if( check == -1 ) {
 
1362
    ERR(pTrans->getNdbError());
 
1363
    return NDBT_FAILED;
 
1364
  }
 
1365
      
 
1366
  check = pOp->equal("TIME", glTime);
 
1367
  if( check == -1 ) {
 
1368
    ERR(pTrans->getNdbError());
 
1369
    return NDBT_FAILED;
 
1370
  }
 
1371
 
 
1372
  check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
 
1373
  if( check == -1 ) {
 
1374
    ERR(pTrans->getNdbError());
 
1375
    return NDBT_FAILED;
 
1376
  }
 
1377
 
 
1378
  NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
 
1379
  if( balanceRec == NULL ) {
 
1380
    ERR(pTrans->getNdbError());
 
1381
    return NDBT_FAILED;
 
1382
  }
 
1383
 
 
1384
  check = pTrans->execute(Commit);
 
1385
  if( check == -1 ) {
 
1386
    ERR(pTrans->getNdbError());
 
1387
    return NDBT_FAILED;
 
1388
  } 
 
1389
 
 
1390
  m_ndb.closeTransaction(pTrans);
 
1391
 
 
1392
  balance = balanceRec->u_32_value();
 
1393
 
 
1394
  return NDBT_OK;
 
1395
}
 
1396
 
 
1397
 
 
1398
 
 
1399
int Bank::getOldestPurgedGL(const Uint32 accountType,
 
1400
                            Uint64 &oldest){
 
1401
  int check;  
 
1402
  /**
 
1403
   * SELECT MAX(time) FROM GL WHERE account_type = @accountType and purged=1
 
1404
   */
 
1405
  NdbConnection* pScanTrans = 0;
 
1406
  do
 
1407
  {
 
1408
    pScanTrans = m_ndb.startTransaction();
 
1409
    if (pScanTrans == NULL) {
 
1410
      ERR(m_ndb.getNdbError());
 
1411
      return NDBT_FAILED;
 
1412
    }
 
1413
    
 
1414
    NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");      
 
1415
    if (pOp == NULL) {
 
1416
      ERR(pScanTrans->getNdbError());
 
1417
      m_ndb.closeTransaction(pScanTrans);
 
1418
      return NDBT_FAILED;
 
1419
    }
 
1420
    
 
1421
    if( pOp->readTuples() ) {
 
1422
      ERR(pScanTrans->getNdbError());
 
1423
      m_ndb.closeTransaction(pScanTrans);
 
1424
      return NDBT_FAILED;
 
1425
    }
 
1426
    
 
1427
    check = pOp->interpret_exit_ok();
 
1428
    if( check == -1 ) {
 
1429
      ERR(pScanTrans->getNdbError());
 
1430
      m_ndb.closeTransaction(pScanTrans);
 
1431
      return NDBT_FAILED;
 
1432
    }
 
1433
    
 
1434
    NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1435
    if( accountTypeRec ==NULL ) {
 
1436
      ERR(pScanTrans->getNdbError());
 
1437
      m_ndb.closeTransaction(pScanTrans);
 
1438
      return NDBT_FAILED;
 
1439
    }
 
1440
    
 
1441
    NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1442
    if( timeRec ==NULL ) {
 
1443
      ERR(pScanTrans->getNdbError());
 
1444
      m_ndb.closeTransaction(pScanTrans);
 
1445
      return NDBT_FAILED;
 
1446
    }
 
1447
    
 
1448
    NdbRecAttr* purgedRec = pOp->getValue("PURGED");
 
1449
    if( purgedRec ==NULL ) {
 
1450
      ERR(pScanTrans->getNdbError());
 
1451
      m_ndb.closeTransaction(pScanTrans);
 
1452
      return NDBT_FAILED;
 
1453
    }
 
1454
    
 
1455
    check = pScanTrans->execute(NoCommit);
 
1456
    if( check == -1 ) {
 
1457
      NdbError err = pScanTrans->getNdbError();
 
1458
      ERR(err);
 
1459
      m_ndb.closeTransaction(pScanTrans);
 
1460
      if (err.status == NdbError::TemporaryError)
 
1461
      {
 
1462
        NdbSleep_MilliSleep(50);
 
1463
        continue;
 
1464
      }
 
1465
      return NDBT_FAILED;
 
1466
    }
 
1467
    
 
1468
    int eof;
 
1469
    int rows = 0;
 
1470
    eof = pOp->nextResult();
 
1471
    oldest = 0;
 
1472
    
 
1473
    while(eof == 0){
 
1474
      rows++;
 
1475
      Uint32 a = accountTypeRec->u_32_value();
 
1476
      Uint32 p = purgedRec->u_32_value();
 
1477
      
 
1478
      if (a == accountType && p == 1){
 
1479
        // One record found
 
1480
        Uint64 t = timeRec->u_64_value();
 
1481
        if (t > oldest)
 
1482
          oldest = t;
 
1483
      }
 
1484
      eof = pOp->nextResult();
 
1485
    }
 
1486
    if (eof == -1) 
 
1487
    {
 
1488
      NdbError err = pScanTrans->getNdbError();
 
1489
      ERR(err);
 
1490
      m_ndb.closeTransaction(pScanTrans);
 
1491
      
 
1492
      if (err.status == NdbError::TemporaryError)
 
1493
      {
 
1494
        NdbSleep_MilliSleep(50);
 
1495
        continue;
 
1496
      }
 
1497
      return NDBT_FAILED;
 
1498
    }
 
1499
    break;
 
1500
  } while(true);
 
1501
  
 
1502
  m_ndb.closeTransaction(pScanTrans);
 
1503
  
 
1504
  return NDBT_OK;
 
1505
}
 
1506
 
 
1507
int Bank::getOldestNotPurgedGL(Uint64 &oldest,
 
1508
                               Uint32 &accountTypeId,
 
1509
                               bool &found){
 
1510
  int check;  
 
1511
  /**
 
1512
   * SELECT time, accountTypeId FROM GL 
 
1513
   * WHERE purged=0 order by time asc
 
1514
   */
 
1515
  NdbConnection* pScanTrans = m_ndb.startTransaction();
 
1516
  if (pScanTrans == NULL) {
 
1517
    ERR(m_ndb.getNdbError());
 
1518
    return NDBT_FAILED;
 
1519
  }
 
1520
      
 
1521
  NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");        
 
1522
  if (pOp == NULL) {
 
1523
    ERR(pScanTrans->getNdbError());
 
1524
    m_ndb.closeTransaction(pScanTrans);
 
1525
    return NDBT_FAILED;
 
1526
  }
 
1527
 
 
1528
  if( pOp->readTuples() ) {
 
1529
    ERR(pScanTrans->getNdbError());
 
1530
    m_ndb.closeTransaction(pScanTrans);
 
1531
    return NDBT_FAILED;
 
1532
  }
 
1533
 
 
1534
  check = pOp->interpret_exit_ok();
 
1535
  if( check == -1 ) {
 
1536
    ERR(pScanTrans->getNdbError());
 
1537
    m_ndb.closeTransaction(pScanTrans);
 
1538
    return NDBT_FAILED;
 
1539
  }
 
1540
 
 
1541
  NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1542
  if( accountTypeRec ==NULL ) {
 
1543
    ERR(pScanTrans->getNdbError());
 
1544
    m_ndb.closeTransaction(pScanTrans);
 
1545
    return NDBT_FAILED;
 
1546
  }
 
1547
 
 
1548
  NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1549
  if( timeRec ==NULL ) {
 
1550
    ERR(pScanTrans->getNdbError());
 
1551
    m_ndb.closeTransaction(pScanTrans);
 
1552
    return NDBT_FAILED;
 
1553
  }
 
1554
 
 
1555
  NdbRecAttr* purgedRec = pOp->getValue("PURGED");
 
1556
  if( purgedRec ==NULL ) {
 
1557
    ERR(pScanTrans->getNdbError());
 
1558
    m_ndb.closeTransaction(pScanTrans);
 
1559
    return NDBT_FAILED;
 
1560
  }
 
1561
 
 
1562
  check = pScanTrans->execute(NoCommit);
 
1563
  if( check == -1 ) {
 
1564
    ERR(pScanTrans->getNdbError());
 
1565
    m_ndb.closeTransaction(pScanTrans);
 
1566
    return NDBT_FAILED;
 
1567
  }
 
1568
    
 
1569
  int eof;
 
1570
  int rows = 0;
 
1571
  eof = pOp->nextResult();
 
1572
  oldest = (Uint64)-1;
 
1573
  found = false;
 
1574
    
 
1575
  while(eof == 0){
 
1576
    rows++;
 
1577
    Uint32 p = purgedRec->u_32_value();
 
1578
    if (p == 0){
 
1579
      found = true;
 
1580
      // One record found
 
1581
      Uint32 a = accountTypeRec->u_32_value();      
 
1582
      Uint64 t = timeRec->u_64_value();
 
1583
      if (t < oldest){
 
1584
        oldest = t;
 
1585
        accountTypeId = a;
 
1586
      }
 
1587
    }
 
1588
    eof = pOp->nextResult();
 
1589
  }
 
1590
  if (eof == -1) {
 
1591
    ERR(pScanTrans->getNdbError());
 
1592
    m_ndb.closeTransaction(pScanTrans);
 
1593
    return NDBT_FAILED;
 
1594
  }
 
1595
    
 
1596
  m_ndb.closeTransaction(pScanTrans);
 
1597
 
 
1598
  return NDBT_OK;
 
1599
}
 
1600
 
 
1601
 
 
1602
int Bank::checkNoTransactionsOlderThan(const Uint32 accountType,
 
1603
                                       const Uint64 oldest){
 
1604
  /**
 
1605
   * SELECT COUNT(transaction_id) FROM TRANSACTION 
 
1606
   * WHERE account_type = @accountType and time <= @oldest
 
1607
   *
 
1608
   */
 
1609
 
 
1610
  int loop = 0;
 
1611
  int found = 0;
 
1612
  NdbConnection* pScanTrans = 0;
 
1613
  do {
 
1614
    int check;  
 
1615
    loop++;
 
1616
    pScanTrans = m_ndb.startTransaction();
 
1617
    if (pScanTrans == NULL) {
 
1618
      ERR(m_ndb.getNdbError());
 
1619
      return NDBT_FAILED;
 
1620
    }
 
1621
    
 
1622
    NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");
 
1623
    if (pOp == NULL) {
 
1624
      ERR(pScanTrans->getNdbError());
 
1625
      m_ndb.closeTransaction(pScanTrans);
 
1626
      return NDBT_FAILED;
 
1627
    }
 
1628
    
 
1629
    if( pOp->readTuples() ) {
 
1630
      ERR(pScanTrans->getNdbError());
 
1631
      m_ndb.closeTransaction(pScanTrans);
 
1632
      return NDBT_FAILED;
 
1633
    }
 
1634
    
 
1635
    check = pOp->interpret_exit_ok();
 
1636
    if( check == -1 ) {
 
1637
      ERR(pScanTrans->getNdbError());
 
1638
      m_ndb.closeTransaction(pScanTrans);
 
1639
      return NDBT_FAILED;
 
1640
    }
 
1641
    
 
1642
    NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1643
    if( accountTypeRec ==NULL ) {
 
1644
      ERR(pScanTrans->getNdbError());
 
1645
      m_ndb.closeTransaction(pScanTrans);
 
1646
      return NDBT_FAILED;
 
1647
    }
 
1648
    
 
1649
    NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1650
    if( timeRec ==NULL ) {
 
1651
      ERR(pScanTrans->getNdbError());
 
1652
      m_ndb.closeTransaction(pScanTrans);
 
1653
      return NDBT_FAILED;
 
1654
    }
 
1655
    
 
1656
    NdbRecAttr* transactionIdRec = pOp->getValue("TRANSACTION_ID");
 
1657
    if( transactionIdRec ==NULL ) {
 
1658
      ERR(pScanTrans->getNdbError());
 
1659
      m_ndb.closeTransaction(pScanTrans);
 
1660
      return NDBT_FAILED;
 
1661
    }
 
1662
    
 
1663
    check = pScanTrans->execute(NoCommit);   
 
1664
    if( check == -1 ) {
 
1665
      NdbError err = pScanTrans->getNdbError();
 
1666
      ERR(err);
 
1667
      m_ndb.closeTransaction(pScanTrans);
 
1668
 
 
1669
      if (err.status == NdbError::TemporaryError)
 
1670
      {
 
1671
        NdbSleep_MilliSleep(50);
 
1672
        continue;
 
1673
      }
 
1674
      return NDBT_FAILED;
 
1675
    }
 
1676
    
 
1677
    int eof;
 
1678
    int rows = 0;
 
1679
    found = 0;
 
1680
    eof = pOp->nextResult();
 
1681
    
 
1682
    while(eof == 0){
 
1683
      rows++;
 
1684
      Uint32 a = accountTypeRec->u_32_value();
 
1685
      Uint32 t = timeRec->u_32_value();
 
1686
      
 
1687
      if (a == accountType && t <= oldest){
 
1688
        // One record found
 
1689
        Uint64 ti = transactionIdRec->u_64_value();
 
1690
        g_err << "checkNoTransactionsOlderThan found one record" << endl
 
1691
              << "  t = " << t << endl
 
1692
              << "  a = " << a << endl
 
1693
              << "  ti = " << ti << endl;
 
1694
        found++;
 
1695
      }
 
1696
      eof = pOp->nextResult();
 
1697
    }
 
1698
    if (eof == -1) {
 
1699
      NdbError err = pScanTrans->getNdbError();
 
1700
      ERR(err);
 
1701
      m_ndb.closeTransaction(pScanTrans);
 
1702
      
 
1703
      if (err.status == NdbError::TemporaryError)
 
1704
      {
 
1705
        NdbSleep_MilliSleep(50);
 
1706
        continue;
 
1707
      }
 
1708
      
 
1709
      return NDBT_FAILED;
 
1710
    }
 
1711
 
 
1712
    break;
 
1713
  } while(true);
 
1714
 
 
1715
  m_ndb.closeTransaction(pScanTrans);
 
1716
  
 
1717
  if (found == 0)
 
1718
    return NDBT_OK;
 
1719
  else
 
1720
    return VERIFICATION_FAILED;
 
1721
}
 
1722
 
 
1723
 
 
1724
 int Bank::performValidatePurged(){
 
1725
   /**
 
1726
    * Make sure there are no TRANSACTIONS older than the oldest 
 
1727
    * purged GL record
 
1728
    * 
 
1729
    */
 
1730
 
 
1731
   for (int i = 0; i < getNumAccountTypes(); i++){
 
1732
     ndbout << "performValidatePurged: " << i << endl;
 
1733
     Uint64 oldestGlTime; 
 
1734
     if (getOldestPurgedGL(i, oldestGlTime) != NDBT_OK){
 
1735
       g_err << "getOldestPurgedGL failed" << endl;
 
1736
       return NDBT_FAILED;    
 
1737
     }
 
1738
     int result = checkNoTransactionsOlderThan(i, oldestGlTime);
 
1739
     if (result != NDBT_OK){
 
1740
       g_err << "checkNoTransactionsOlderThan failed" << endl;
 
1741
       return result;
 
1742
     }
 
1743
     
 
1744
   }
 
1745
   
 
1746
   return NDBT_OK;
 
1747
 }
 
1748
 
 
1749
 int Bank::purgeOldGLTransactions(Uint64 currTime, Uint32 age){
 
1750
   /** 
 
1751
    * For each GL record that are older than age and have purged == 0
 
1752
    *  - delete all TRANSACTIONS belonging to the GL and set purged = 1
 
1753
    *
 
1754
    * 
 
1755
    */
 
1756
   bool found;
 
1757
   int count = 0;
 
1758
 
 
1759
   while(1){
 
1760
     count++;
 
1761
     if (count > 100)
 
1762
       return NDBT_OK;
 
1763
     
 
1764
     // Search for the oldest GL record with purged == 0
 
1765
     Uint64 oldestGlTime;
 
1766
     Uint32 accountTypeId;
 
1767
     if (getOldestNotPurgedGL(oldestGlTime, accountTypeId, found) != NDBT_OK){
 
1768
       g_err << "getOldestNotPurgedGL failed" << endl;
 
1769
       return NDBT_FAILED;
 
1770
     }
 
1771
 
 
1772
 
 
1773
     if (found == false){
 
1774
       // ndbout << "not found" << endl;
 
1775
       return NDBT_OK;
 
1776
     }
 
1777
 
 
1778
     
 
1779
//      ndbout << "purgeOldGLTransactions" << endl
 
1780
//                  << "  oldestGlTime = " << oldestGlTime << endl
 
1781
//                  << "  currTime = " << currTime << endl
 
1782
//          << "  age = " << age << endl;
 
1783
     // Check if this GL is old enough to be purged
 
1784
     if ((currTime < age) || (oldestGlTime > (currTime-age))){
 
1785
       //       ndbout << "is not old enough" << endl;
 
1786
       return NDBT_OK;
 
1787
     }
 
1788
 
 
1789
     if (purgeTransactions(oldestGlTime, accountTypeId) != NDBT_OK){
 
1790
       g_err << "purgeTransactions failed" << endl;
 
1791
       return NDBT_FAILED;
 
1792
     }
 
1793
   }
 
1794
   g_err << "abnormal return" << endl; 
 
1795
   return NDBT_FAILED;
 
1796
 }
 
1797
 
 
1798
 
 
1799
int Bank::purgeTransactions(const Uint64 glTime, 
 
1800
                            const Uint32 accountTypeId)
 
1801
{
 
1802
  int check;
 
1803
  g_info << "purgeTransactions: " << glTime << ", "<<accountTypeId<<endl;
 
1804
  NdbConnection* pTrans = m_ndb.startTransaction();
 
1805
  if (pTrans == NULL){
 
1806
    ERR(m_ndb.getNdbError());
 
1807
    return NDBT_FAILED;
 
1808
  }
 
1809
 
 
1810
  // Start by updating the GL record with purged = 1, use NoCommit
 
1811
  NdbOperation* pOp = pTrans->getNdbOperation("GL");
 
1812
  if (pOp == NULL) {
 
1813
    ERR(pTrans->getNdbError());
 
1814
    return NDBT_FAILED;
 
1815
  }
 
1816
    
 
1817
  check = pOp->updateTuple();
 
1818
  if( check == -1 ) {
 
1819
    ERR(pTrans->getNdbError());
 
1820
    return NDBT_FAILED;
 
1821
  }
 
1822
      
 
1823
  check = pOp->equal("TIME", glTime);
 
1824
  if( check == -1 ) {
 
1825
    ERR(pTrans->getNdbError());
 
1826
    return NDBT_FAILED;
 
1827
  }
 
1828
 
 
1829
  check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
 
1830
  if( check == -1 ) {
 
1831
    ERR(pTrans->getNdbError());
 
1832
    return NDBT_FAILED;
 
1833
  }
 
1834
 
 
1835
  Uint32 purged = 1;
 
1836
  check = pOp->setValue("PURGED", purged);
 
1837
  if( check == -1 ) {
 
1838
    ERR(pTrans->getNdbError());
 
1839
    return NDBT_FAILED;
 
1840
  }
 
1841
 
 
1842
  // Execute transaction    
 
1843
  check = pTrans->execute(NoCommit);
 
1844
  if( check == -1 ) {
 
1845
    ERR(pTrans->getNdbError());
 
1846
    return NDBT_FAILED;
 
1847
  }    
 
1848
 
 
1849
  // Find all transactions and take over them for delete
 
1850
 
 
1851
  if(findTransactionsToPurge(glTime,
 
1852
                            accountTypeId,
 
1853
                            pTrans) != NDBT_OK){
 
1854
    g_err << "findTransactionToPurge failed" << endl;
 
1855
    m_ndb.closeTransaction(pTrans);
 
1856
    return NDBT_FAILED;
 
1857
  }
 
1858
 
 
1859
 
 
1860
 
 
1861
  check = pTrans->execute(Commit);
 
1862
  if( check == -1 ) {
 
1863
    ERR(pTrans->getNdbError());
 
1864
    return NDBT_FAILED;
 
1865
  } 
 
1866
 
 
1867
  m_ndb.closeTransaction(pTrans);
 
1868
  return NDBT_OK;
 
1869
}
 
1870
 
 
1871
 
 
1872
int Bank::findTransactionsToPurge(const Uint64 glTime, 
 
1873
                                  const Uint32 accountType,
 
1874
                                  NdbConnection* pTrans){
 
1875
  int check;
 
1876
  
 
1877
  NdbConnection* pScanTrans = m_ndb.startTransaction();
 
1878
  if (pScanTrans == NULL) {
 
1879
    ERR(m_ndb.getNdbError());
 
1880
    return NDBT_FAILED;
 
1881
  }
 
1882
      
 
1883
  NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");       
 
1884
  if (pOp == NULL) {
 
1885
    ERR(pScanTrans->getNdbError());
 
1886
    m_ndb.closeTransaction(pScanTrans);
 
1887
    return NDBT_FAILED;
 
1888
  }
 
1889
 
 
1890
  if( pOp->readTuplesExclusive() ) {
 
1891
    ERR(pScanTrans->getNdbError());
 
1892
    m_ndb.closeTransaction(pScanTrans);
 
1893
    return NDBT_FAILED;
 
1894
  }
 
1895
 
 
1896
  check = pOp->interpret_exit_ok();
 
1897
  if( check == -1 ) {
 
1898
    ERR(pScanTrans->getNdbError());
 
1899
    m_ndb.closeTransaction(pScanTrans);
 
1900
    return NDBT_FAILED;
 
1901
  }
 
1902
 
 
1903
  NdbRecAttr* timeRec = pOp->getValue("TIME");
 
1904
  if( timeRec ==NULL ) {
 
1905
    ERR(pScanTrans->getNdbError());
 
1906
    m_ndb.closeTransaction(pScanTrans);
 
1907
    return NDBT_FAILED;
 
1908
  }
 
1909
 
 
1910
  NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
 
1911
  if( accountTypeRec ==NULL ) {
 
1912
    ERR(pScanTrans->getNdbError());
 
1913
    m_ndb.closeTransaction(pScanTrans);
 
1914
    return NDBT_FAILED;
 
1915
  }
 
1916
 
 
1917
  check = pScanTrans->execute(NoCommit);   
 
1918
  if( check == -1 ) {
 
1919
    ERR(pScanTrans->getNdbError());
 
1920
    m_ndb.closeTransaction(pScanTrans);
 
1921
    return NDBT_FAILED;
 
1922
  }
 
1923
    
 
1924
  int eof;
 
1925
  int rows = 0;
 
1926
  int rowsFound = 0;
 
1927
  eof = pOp->nextResult();
 
1928
    
 
1929
  while(eof == 0){
 
1930
    rows++;
 
1931
    Uint64 t = timeRec->u_64_value();
 
1932
    Uint32 a = accountTypeRec->u_32_value();
 
1933
 
 
1934
    if (a == accountType && t == glTime){
 
1935
      rowsFound++;
 
1936
      // One record found
 
1937
      check = pOp->deleteCurrentTuple(pTrans);
 
1938
      if (check == -1){
 
1939
        ERR(m_ndb.getNdbError());
 
1940
        m_ndb.closeTransaction(pScanTrans);
 
1941
        return NDBT_FAILED;
 
1942
      }
 
1943
      
 
1944
      // Execute transaction    
 
1945
      check = pTrans->execute(NoCommit);
 
1946
      if( check == -1 ) {
 
1947
        ERR(pTrans->getNdbError());
 
1948
        m_ndb.closeTransaction(pScanTrans);
 
1949
        return NDBT_FAILED;
 
1950
      }       
 
1951
    }
 
1952
    eof = pOp->nextResult();
 
1953
  }
 
1954
  if (eof == -1) {
 
1955
    ERR(pScanTrans->getNdbError());
 
1956
    m_ndb.closeTransaction(pScanTrans);
 
1957
    return NDBT_FAILED;
 
1958
  }
 
1959
    
 
1960
  m_ndb.closeTransaction(pScanTrans);
 
1961
  //  ndbout << rowsFound << " TRANSACTIONS have been deleted" << endl;
 
1962
 
 
1963
  return NDBT_OK;
 
1964
 
 
1965
}
 
1966
 
 
1967
 
 
1968
int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield)
 
1969
{
 
1970
  int yieldCounter = 0;
 
1971
  
 
1972
  while(1){
 
1973
    
 
1974
    Uint64 currTime;
 
1975
    if (incCurrTime(currTime) != NDBT_OK)
 
1976
      break;
 
1977
    
 
1978
    g_info << "Current time is " << currTime << endl;
 
1979
    if (maxSleepBetweenDays > 0){
 
1980
      int val = myRandom48(maxSleepBetweenDays);
 
1981
      NdbSleep_SecSleep(val);
 
1982
    }
 
1983
    
 
1984
    yieldCounter++;
 
1985
    if (yield != 0 && yieldCounter >= yield)
 
1986
      return NDBT_OK;
 
1987
    
 
1988
  }
 
1989
  return NDBT_FAILED;
 
1990
}
 
1991
 
 
1992
int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){
 
1993
 
 
1994
  int check;
 
1995
  NdbConnection* pTrans = 0;
 
1996
  while (true)
 
1997
  {
 
1998
    pTrans = m_ndb.startTransaction();
 
1999
    if (pTrans == NULL)
 
2000
    {
 
2001
      ERR(m_ndb.getNdbError());
 
2002
      if(m_ndb.getNdbError().status == NdbError::TemporaryError)
 
2003
      {
 
2004
        NdbSleep_MilliSleep(50);
 
2005
        continue;
 
2006
      }
 
2007
      return NDBT_FAILED;
 
2008
    }
 
2009
    
 
2010
    int result;
 
2011
    if ((result= prepareReadSystemValueOp(pTrans, sysValId, value)) != NDBT_OK)
 
2012
    {
 
2013
      ERR(pTrans->getNdbError());
 
2014
      m_ndb.closeTransaction(pTrans);
 
2015
      return result;
 
2016
    }
 
2017
    
 
2018
    check = pTrans->execute(Commit);
 
2019
    if( check == -1 ) {
 
2020
      NdbError err = pTrans->getNdbError();
 
2021
      m_ndb.closeTransaction(pTrans);
 
2022
      ERR(err);
 
2023
      if(err.status == NdbError::TemporaryError)
 
2024
      {
 
2025
        NdbSleep_MilliSleep(50);
 
2026
        continue;
 
2027
      }
 
2028
      return NDBT_FAILED;
 
2029
    }
 
2030
    
 
2031
    break;
 
2032
  }
 
2033
  
 
2034
  m_ndb.closeTransaction(pTrans);      
 
2035
  return NDBT_OK;
 
2036
 
 
2037
}
 
2038
 
 
2039
int Bank::prepareReadSystemValueOp(NdbConnection* pTrans, SystemValueId sysValId, Uint64 & value){
 
2040
 
 
2041
  int check;
 
2042
    
 
2043
  NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2044
  if (pOp == NULL) {
 
2045
    return NDBT_FAILED;
 
2046
  }
 
2047
    
 
2048
  check = pOp->readTuple();
 
2049
  if( check == -1 ) {
 
2050
    return NDBT_FAILED;
 
2051
  }
 
2052
    
 
2053
  check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
 
2054
  if( check == -1 ) {
 
2055
    return NDBT_FAILED;
 
2056
  }
 
2057
    
 
2058
  NdbRecAttr* valueRec = pOp->getValue("VALUE", (char *)&value);
 
2059
  if( valueRec == NULL ) {
 
2060
    return NDBT_FAILED;
 
2061
  }
 
2062
    
 
2063
  return NDBT_OK;
 
2064
}
 
2065
 
 
2066
int Bank::writeSystemValue(SystemValueId sysValId, Uint64 value){
 
2067
 
 
2068
  int check;
 
2069
    
 
2070
  NdbConnection* pTrans = m_ndb.startTransaction();
 
2071
  if (pTrans == NULL){
 
2072
    ERR(m_ndb.getNdbError());
 
2073
    return NDBT_FAILED;
 
2074
  }
 
2075
    
 
2076
  NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2077
  if (pOp == NULL) {
 
2078
    ERR(pTrans->getNdbError());
 
2079
    m_ndb.closeTransaction(pTrans);
 
2080
    return NDBT_FAILED;
 
2081
  }
 
2082
    
 
2083
  check = pOp->insertTuple();
 
2084
  if( check == -1 ) {
 
2085
    ERR(pTrans->getNdbError());
 
2086
    m_ndb.closeTransaction(pTrans);
 
2087
    return NDBT_FAILED;
 
2088
  }
 
2089
      
 
2090
  check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
 
2091
  if( check == -1 ) {
 
2092
    ERR(pTrans->getNdbError());
 
2093
    m_ndb.closeTransaction(pTrans);
 
2094
    return NDBT_FAILED;
 
2095
  }
 
2096
 
 
2097
  check = pOp->setValue("VALUE", value);
 
2098
  if( check == -1 ) {
 
2099
    ERR(pTrans->getNdbError());
 
2100
    m_ndb.closeTransaction(pTrans);
 
2101
    return NDBT_FAILED;
 
2102
  }
 
2103
 
 
2104
  check = pTrans->execute(Commit);
 
2105
  if( check == -1 ) {
 
2106
    ERR(pTrans->getNdbError());
 
2107
    m_ndb.closeTransaction(pTrans);
 
2108
    return NDBT_FAILED;
 
2109
  }
 
2110
    
 
2111
  m_ndb.closeTransaction(pTrans);      
 
2112
  return NDBT_OK;
 
2113
 
 
2114
}
 
2115
 
 
2116
int Bank::getNextTransactionId(Uint64 &value){
 
2117
  return increaseSystemValue2(LastTransactionId, value);
 
2118
}
 
2119
 
 
2120
int Bank::incCurrTime(Uint64 &value){
 
2121
  return increaseSystemValue(CurrentTime, value);
 
2122
}
 
2123
 
 
2124
  
 
2125
int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){
 
2126
  /**
 
2127
   * Increase value with one and return
 
2128
   * updated value
 
2129
   *
 
2130
   */
 
2131
 
 
2132
  DBUG_ENTER("Bank::increaseSystemValue");
 
2133
 
 
2134
  int check;
 
2135
    
 
2136
  NdbConnection* pTrans = m_ndb.startTransaction();
 
2137
  if (pTrans == NULL){
 
2138
    ERR(m_ndb.getNdbError());
 
2139
    if (m_ndb.getNdbError().status == NdbError::TemporaryError)
 
2140
      DBUG_RETURN(NDBT_TEMPORARY);
 
2141
    DBUG_RETURN(NDBT_FAILED);
 
2142
  }
 
2143
    
 
2144
  NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2145
  if (pOp == NULL) {
 
2146
    ERR(pTrans->getNdbError());
 
2147
    m_ndb.closeTransaction(pTrans);
 
2148
    DBUG_RETURN(NDBT_FAILED);
 
2149
  }
 
2150
    
 
2151
  check = pOp->readTupleExclusive();
 
2152
  //  check = pOp->readTuple();
 
2153
  if( check == -1 ) {
 
2154
    ERR(pTrans->getNdbError());
 
2155
    m_ndb.closeTransaction(pTrans);
 
2156
    DBUG_RETURN(NDBT_FAILED);
 
2157
  }
 
2158
    
 
2159
  check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
 
2160
  if( check == -1 ) {
 
2161
    ERR(pTrans->getNdbError());
 
2162
    m_ndb.closeTransaction(pTrans);
 
2163
    DBUG_RETURN(NDBT_FAILED);
 
2164
  }
 
2165
    
 
2166
  NdbRecAttr* valueRec = pOp->getValue("VALUE");
 
2167
  if( valueRec ==NULL ) {
 
2168
    ERR(pTrans->getNdbError());
 
2169
    m_ndb.closeTransaction(pTrans);
 
2170
    DBUG_RETURN(NDBT_FAILED);
 
2171
  }
 
2172
    
 
2173
  check = pTrans->execute(NoCommit);
 
2174
  if( check == -1 ) {
 
2175
    ERR(pTrans->getNdbError());
 
2176
    if (pTrans->getNdbError().status == NdbError::TemporaryError)
 
2177
    {
 
2178
      m_ndb.closeTransaction(pTrans);
 
2179
      DBUG_RETURN(NDBT_TEMPORARY);
 
2180
    }
 
2181
    m_ndb.closeTransaction(pTrans);
 
2182
    DBUG_RETURN(NDBT_FAILED);
 
2183
  }
 
2184
    
 
2185
  value = valueRec->u_64_value();
 
2186
  value++;
 
2187
    
 
2188
  NdbOperation* pOp2 = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2189
  if (pOp2 == NULL) {
 
2190
    ERR(pTrans->getNdbError());
 
2191
    m_ndb.closeTransaction(pTrans);
 
2192
    DBUG_RETURN(NDBT_FAILED);
 
2193
  }
 
2194
    
 
2195
  check = pOp2->updateTuple();
 
2196
  if( check == -1 ) {
 
2197
    ERR(pTrans->getNdbError());
 
2198
    m_ndb.closeTransaction(pTrans);
 
2199
    DBUG_RETURN(NDBT_FAILED);
 
2200
  }
 
2201
    
 
2202
  check = pOp2->equal("SYSTEM_VALUES_ID", sysValId);
 
2203
  if( check == -1 ) {
 
2204
    ERR(pTrans->getNdbError());
 
2205
    m_ndb.closeTransaction(pTrans);
 
2206
    DBUG_RETURN(NDBT_FAILED);
 
2207
  }
 
2208
    
 
2209
  check = pOp2->setValue("VALUE", value);
 
2210
  if( check == -1 ) {
 
2211
    ERR(pTrans->getNdbError());
 
2212
    m_ndb.closeTransaction(pTrans);
 
2213
    DBUG_RETURN(NDBT_FAILED);
 
2214
  }
 
2215
 
 
2216
  check = pTrans->execute(NoCommit);
 
2217
  if( check == -1 ) {
 
2218
    ERR(pTrans->getNdbError());
 
2219
    m_ndb.closeTransaction(pTrans);
 
2220
    DBUG_RETURN(NDBT_FAILED);
 
2221
  }
 
2222
 
 
2223
  NdbOperation* pOp3 = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2224
  if (pOp3 == NULL) {
 
2225
    ERR(pTrans->getNdbError());
 
2226
    m_ndb.closeTransaction(pTrans);
 
2227
    DBUG_RETURN(NDBT_FAILED);
 
2228
  }
 
2229
 
 
2230
  check = pOp3->readTuple();
 
2231
  if( check == -1 ) {
 
2232
    ERR(pTrans->getNdbError());
 
2233
    m_ndb.closeTransaction(pTrans);
 
2234
    DBUG_RETURN(NDBT_FAILED);
 
2235
  }
 
2236
    
 
2237
  check = pOp3->equal("SYSTEM_VALUES_ID", sysValId);
 
2238
  if( check == -1 ) {
 
2239
    ERR(pTrans->getNdbError());
 
2240
    m_ndb.closeTransaction(pTrans);
 
2241
    DBUG_RETURN(NDBT_FAILED);
 
2242
  }
 
2243
 
 
2244
  // Read new value
 
2245
  NdbRecAttr* valueNewRec = pOp3->getValue("VALUE");
 
2246
  if( valueNewRec ==NULL ) {
 
2247
    ERR(pTrans->getNdbError());
 
2248
    m_ndb.closeTransaction(pTrans);
 
2249
    DBUG_RETURN(NDBT_FAILED);
 
2250
  }
 
2251
 
 
2252
  check = pTrans->execute(Commit);
 
2253
  if( check == -1 ) {
 
2254
    ERR(pTrans->getNdbError());
 
2255
    if (pTrans->getNdbError().status == NdbError::TemporaryError)
 
2256
    {
 
2257
      m_ndb.closeTransaction(pTrans);
 
2258
      DBUG_RETURN(NDBT_TEMPORARY);
 
2259
    }
 
2260
    m_ndb.closeTransaction(pTrans);
 
2261
    DBUG_RETURN(NDBT_FAILED);
 
2262
  }
 
2263
 
 
2264
  // Check that value updated equals the value we read after the update
 
2265
  if (valueNewRec->u_64_value() != value){
 
2266
    
 
2267
    printf("value actual=%lld\n", valueNewRec->u_64_value());
 
2268
    printf("value expected=%lld actual=%lld\n", value, valueNewRec->u_64_value());
 
2269
    
 
2270
    DBUG_PRINT("info", ("value expected=%ld actual=%ld", value, valueNewRec->u_64_value()));
 
2271
    g_err << "getNextTransactionId: value was not updated" << endl;
 
2272
    m_ndb.closeTransaction(pTrans);
 
2273
    DBUG_RETURN(NDBT_FAILED);
 
2274
  }
 
2275
 
 
2276
  m_ndb.closeTransaction(pTrans);
 
2277
  
 
2278
  DBUG_RETURN(0);
 
2279
}
 
2280
 
 
2281
int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){
 
2282
  /**
 
2283
   * Increase value with one and return
 
2284
   * updated value
 
2285
   * A more optimized version using interpreted update!
 
2286
   *
 
2287
   */
 
2288
 
 
2289
  int check;
 
2290
    
 
2291
  NdbConnection* pTrans = m_ndb.startTransaction();
 
2292
  if (pTrans == NULL){
 
2293
    ERR(m_ndb.getNdbError());
 
2294
    if(m_ndb.getNdbError().status == NdbError::TemporaryError)
 
2295
      return NDBT_TEMPORARY;
 
2296
    return NDBT_FAILED;
 
2297
  }
 
2298
    
 
2299
  NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
 
2300
  if (pOp == NULL) {
 
2301
    ERR(pTrans->getNdbError());
 
2302
    m_ndb.closeTransaction(pTrans);
 
2303
    return NDBT_FAILED;
 
2304
  }
 
2305
 
 
2306
  check = pOp->interpretedUpdateTuple();
 
2307
  if( check == -1 ) {
 
2308
    ERR(pTrans->getNdbError());
 
2309
    m_ndb.closeTransaction(pTrans);
 
2310
    return NDBT_FAILED;
 
2311
  }
 
2312
 
 
2313
  check = pOp->equal("SYSTEM_VALUES_ID", sysValId );
 
2314
  if( check == -1 ) {
 
2315
    ERR(pTrans->getNdbError());
 
2316
    m_ndb.closeTransaction(pTrans);
 
2317
    return NDBT_FAILED;
 
2318
  }
 
2319
 
 
2320
  Uint32 valToIncWith = 1;
 
2321
  check = pOp->incValue("VALUE", valToIncWith);
 
2322
  if( check == -1 ) {
 
2323
    ERR(pTrans->getNdbError());
 
2324
    m_ndb.closeTransaction(pTrans);
 
2325
    return NDBT_FAILED;
 
2326
  }
 
2327
 
 
2328
  NdbRecAttr* valueRec = pOp->getValue("VALUE");
 
2329
  if( valueRec == NULL ) {
 
2330
    ERR(pTrans->getNdbError());
 
2331
    m_ndb.closeTransaction(pTrans);
 
2332
    return NDBT_FAILED;
 
2333
  }
 
2334
  
 
2335
  check = pTrans->execute(Commit);
 
2336
  if( check == -1 ) {
 
2337
    ERR(pTrans->getNdbError());
 
2338
    if(pTrans->getNdbError().status == NdbError::TemporaryError)
 
2339
    {
 
2340
      m_ndb.closeTransaction(pTrans);
 
2341
      return NDBT_TEMPORARY;
 
2342
    }
 
2343
    m_ndb.closeTransaction(pTrans);
 
2344
    return NDBT_FAILED;
 
2345
  }
 
2346
 
 
2347
  value = valueRec->u_64_value();
 
2348
    
 
2349
  m_ndb.closeTransaction(pTrans);
 
2350
 
 
2351
  return 0;
 
2352
 
 
2353
}
 
2354
 
 
2355
 
 
2356
 
 
2357
int Bank::getCurrTime(Uint64 &time){
 
2358
  return readSystemValue(CurrentTime, time);
 
2359
}
 
2360
 
 
2361
int Bank::prepareGetCurrTimeOp(NdbConnection *pTrans, Uint64 &time){
 
2362
  return prepareReadSystemValueOp(pTrans, CurrentTime, time);
 
2363
}
 
2364
 
 
2365
 
 
2366
int Bank::performSumAccounts(int maxSleepBetweenSums, int yield){
 
2367
  
 
2368
  int yieldCounter = 0;
 
2369
 
 
2370
  while (1){
 
2371
 
 
2372
    Uint32 sumAccounts = 0;
 
2373
    Uint32 numAccounts = 0;
 
2374
    if (getSumAccounts(sumAccounts, numAccounts) != NDBT_OK){
 
2375
      g_err << "getSumAccounts FAILED" << endl;
 
2376
    } else {
 
2377
    
 
2378
      g_info << "num="<<numAccounts<<", sum=" << sumAccounts << endl;
 
2379
      
 
2380
      if (sumAccounts != (10000000 + (10000*(numAccounts-1)))){
 
2381
        g_err << "performSumAccounts  FAILED" << endl
 
2382
              << "   sumAccounts="<<sumAccounts<<endl
 
2383
              << "   expected   ="<<(10000000 + (10000*(numAccounts-1)))<<endl
 
2384
              << "   numAccounts="<<numAccounts<<endl;
 
2385
        return NDBT_FAILED;
 
2386
      } 
 
2387
    
 
2388
      if (maxSleepBetweenSums > 0){
 
2389
        int val = myRandom48(maxSleepBetweenSums);
 
2390
        NdbSleep_MilliSleep(val);      
 
2391
      }
 
2392
    }
 
2393
 
 
2394
    yieldCounter++;
 
2395
    if (yield != 0 && yieldCounter >= yield)
 
2396
      return NDBT_OK;
 
2397
  }
 
2398
  return NDBT_FAILED;
 
2399
}
 
2400
 
 
2401
 
 
2402
int Bank::getSumAccounts(Uint32 &sumAccounts, 
 
2403
                         Uint32 &numAccounts){
 
2404
 
 
2405
  // SELECT SUM(balance) FROM ACCOUNT
 
2406
 
 
2407
  int check;    
 
2408
  NdbConnection* pScanTrans = m_ndb.startTransaction();
 
2409
  if (pScanTrans == NULL) {
 
2410
    ERR(m_ndb.getNdbError());
 
2411
    return NDBT_FAILED;
 
2412
  }
 
2413
 
 
2414
  NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("ACCOUNT");   
 
2415
  if (pOp == NULL) {
 
2416
    ERR(pScanTrans->getNdbError());
 
2417
    m_ndb.closeTransaction(pScanTrans);
 
2418
    return NDBT_FAILED;
 
2419
  }
 
2420
 
 
2421
  if( pOp->readTuplesExclusive() ) {
 
2422
    ERR(pScanTrans->getNdbError());
 
2423
    m_ndb.closeTransaction(pScanTrans);
 
2424
    return NDBT_FAILED;
 
2425
  }
 
2426
 
 
2427
  check = pOp->interpret_exit_ok();
 
2428
  if( check == -1 ) {
 
2429
    ERR(pScanTrans->getNdbError());
 
2430
    m_ndb.closeTransaction(pScanTrans);
 
2431
    return NDBT_FAILED;
 
2432
  }
 
2433
 
 
2434
  NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
 
2435
  if( balanceRec ==NULL ) {
 
2436
    ERR(pScanTrans->getNdbError());
 
2437
    m_ndb.closeTransaction(pScanTrans);
 
2438
    return NDBT_FAILED;
 
2439
  }
 
2440
 
 
2441
  check = pScanTrans->execute(NoCommit);   
 
2442
  if( check == -1 ) {
 
2443
    ERR(pScanTrans->getNdbError());
 
2444
    m_ndb.closeTransaction(pScanTrans);
 
2445
    return NDBT_FAILED;
 
2446
  }
 
2447
 
 
2448
  NdbConnection* pTrans = m_ndb.startTransaction();
 
2449
  if (pTrans == NULL) {
 
2450
    ERR(m_ndb.getNdbError());
 
2451
    m_ndb.closeTransaction(pScanTrans);
 
2452
    return NDBT_FAILED;
 
2453
  }   
 
2454
 
 
2455
  int eof;
 
2456
  eof = pOp->nextResult();
 
2457
    
 
2458
  while(eof == 0){
 
2459
    Uint32 b = balanceRec->u_32_value();
 
2460
    
 
2461
    sumAccounts += b;
 
2462
    numAccounts++;
 
2463
 
 
2464
    //    ndbout << numAccounts << ": balance =" << b 
 
2465
    //     << ", sum="<< sumAccounts << endl;
 
2466
 
 
2467
    // Take over the operation so that the lock is kept in db
 
2468
    NdbOperation* pLockOp = pOp->updateCurrentTuple(pTrans);
 
2469
    if (pLockOp == NULL){
 
2470
      ERR(m_ndb.getNdbError());
 
2471
      m_ndb.closeTransaction(pScanTrans);
 
2472
      m_ndb.closeTransaction(pTrans);
 
2473
      return NDBT_FAILED;
 
2474
    }
 
2475
    
 
2476
    Uint32 illegalBalance = 99;
 
2477
    check = pLockOp->setValue("BALANCE", illegalBalance);
 
2478
    if( check == -1 ) {
 
2479
      ERR(pTrans->getNdbError());
 
2480
      m_ndb.closeTransaction(pTrans);
 
2481
      m_ndb.closeTransaction(pScanTrans);
 
2482
      return NDBT_FAILED;
 
2483
    }
 
2484
    
 
2485
    // Execute transaction    
 
2486
    check = pTrans->execute(NoCommit);
 
2487
    if( check == -1 ) {
 
2488
      ERR(pTrans->getNdbError());
 
2489
      m_ndb.closeTransaction(pScanTrans);
 
2490
      m_ndb.closeTransaction(pTrans);
 
2491
      return NDBT_FAILED;
 
2492
    }       
 
2493
 
 
2494
    eof = pOp->nextResult();
 
2495
  }
 
2496
  if (eof == -1) {
 
2497
    ERR(pScanTrans->getNdbError());
 
2498
    m_ndb.closeTransaction(pScanTrans);
 
2499
    m_ndb.closeTransaction(pTrans);
 
2500
    return NDBT_FAILED;
 
2501
  }
 
2502
 
 
2503
  // TODO Forget about rolling back, just close pTrans!!
 
2504
 
 
2505
  // Rollback transaction    
 
2506
  check = pTrans->execute(Rollback);
 
2507
  if( check == -1 ) {
 
2508
    ERR(pTrans->getNdbError());
 
2509
    m_ndb.closeTransaction(pScanTrans);
 
2510
    m_ndb.closeTransaction(pTrans);
 
2511
    return NDBT_FAILED;
 
2512
  }       
 
2513
    
 
2514
  m_ndb.closeTransaction(pScanTrans);
 
2515
  m_ndb.closeTransaction(pTrans);
 
2516
 
 
2517
 
 
2518
  return NDBT_OK;
 
2519
 
 
2520
}