/* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #define CHK1(b) \ if (!(b)) { \ g_err << "ERR: " << #b << " failed at line " << __LINE__; \ result = NDBT_FAILED; \ break; \ } #define CHK2(b, e) \ if (!(b)) { \ g_err << "ERR: " << #b << " failed at line " << __LINE__ \ << ": " << e << endl; \ result = NDBT_FAILED; \ break; \ } /** * TODO * dirtyWrite, write, dirtyUpdate * delete should be visible to same transaction * */ int runLoadTable2(NDBT_Context* ctx, NDBT_Step* step) { int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records, 512, false, 0, true) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runLoadTable(NDBT_Context* ctx, NDBT_Step* step) { int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runInsert(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); // Insert records, dont allow any // errors(except temporary) while inserting if (hugoTrans.loadTable(GETNDB(step), records, 1, false) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runInsertTwice(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); // Insert records, expect primary key violation 630 if (hugoTrans.loadTable(GETNDB(step), records, 1, false) != 630){ return NDBT_FAILED; } return NDBT_OK; } int runVerifyInsert(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.pkDelRecords(GETNDB(step), records, 1, false) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runInsertUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; if (hugoTrans.loadTable(GETNDB(step), records) != 0){ g_info << endl; return NDBT_FAILED; } i++; } g_info << endl; return NDBT_OK; } int runClearTable(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.pkDelRecords(GETNDB(step), records, batchSize) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runPkDelete(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (igetNumLoops(); int records = ctx->getNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); int lm = ctx->getProperty("LockMode", NdbOperation::LM_Read); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (igetNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize) != 0){ g_info << endl; return NDBT_FAILED; } i++; } g_info << endl; return NDBT_OK; } int runPkUpdate(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (igetNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped()) { g_info << i << ": "; if (hugoTrans.pkUpdateRecords(GETNDB(step), records, batchSize) != 0){ g_info << endl; return NDBT_FAILED; } i++; } g_info << endl; return NDBT_OK; } int runLocker(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.lockRecords(GETNDB(step), records, 10, 500) != 0){ result = NDBT_FAILED; } ctx->stopTest(); return result; } int runInsertOne(NDBT_Context* ctx, NDBT_Step* step){ if(ctx->getProperty("InsertCommitted", (Uint32)0) != 0){ abort(); } while(ctx->getProperty("Read1Performed", (Uint32)0) == 0){ NdbSleep_MilliSleep(20); } HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), 1, 1) != 0){ return NDBT_FAILED; } ctx->setProperty("InsertCommitted", 1); NdbSleep_SecSleep(2); return NDBT_OK; } /** * Insert error 5083 in DBLQH that puts operation into LOG_QUEUED state and puts * the operation in the REDO log queue. After a while it will be timed out and * the abort code will handle it, the runLoadTableFail method will then abort and * be assumed to be ok, so as long as the node doesn't crash we're passing the * test case and also the operation should be aborted. * * If this test case is run on 7.2 it will simply be the same as Fill since we * don't queue REDO log operations but rather abort it immediately. So it will * pass as well but won't test the desired functionality. */ int runLoadTableFail(NDBT_Context* ctx, NDBT_Step* step) { int records = 16; int res; HugoTransactions hugoTrans(*ctx->getTab()); res = hugoTrans.loadTable(GETNDB(step), records, 64, true, 0, true, true); if (res == 266 || /* Timeout when REDO logging queueing active (or not) */ res == 0) /* No error when not REDO logging active and no error insert */ { ndbout << "res = " << res << endl; return NDBT_OK; } /* All other error variants are errors in this case */ return NDBT_FAILED; } int insertError5083(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter restarter; restarter.insertErrorInAllNodes(5083); return 0; } int clearError5083(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter restarter; restarter.insertErrorInAllNodes(0); return 0; } static int readOneNoCommit(Ndb* pNdb, NdbConnection* pTrans, const NdbDictionary::Table* tab,NDBT_ResultRow * row){ int a; NdbOperation * pOp = pTrans->getNdbOperation(tab->getName()); if (pOp == NULL){ NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } HugoTransactions tmp(*tab); int check = pOp->readTuple(); if( check == -1 ) { NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } // Define primary keys for(a = 0; agetNoOfColumns(); a++){ if (tab->getColumn(a)->getPrimaryKey() == true){ if(tmp.equalForAttr(pOp, a, 0) != 0){ NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } } } // Define attributes to read for(a = 0; agetNoOfColumns(); a++){ if((row->attributeStore(a) = pOp->getValue(tab->getColumn(a)->getName())) == 0) { NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } } check = pTrans->execute(NoCommit); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); NDB_ERR(err); return err.code; } return NDBT_OK; } int runReadOne(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* tab = ctx->getTab(); NDBT_ResultRow row1(*tab); NDBT_ResultRow row2(*tab); if(ctx->getProperty("Read1Performed", (Uint32)0) != 0){ abort(); } if(ctx->getProperty("InsertCommitted", (Uint32)0) != 0){ abort(); } NdbConnection * pTrans = pNdb->startTransaction(); if (pTrans == NULL) { abort(); } // Read a record with NoCommit // Since the record isn't inserted yet it wil return 626 const int res1 = readOneNoCommit(pNdb, pTrans, tab, &row1); g_info << "|- res1 = " << res1 << endl; ctx->setProperty("Read1Performed", 1); while(ctx->getProperty("InsertCommitted", (Uint32)0) == 0 && !ctx->isTestStopped()){ g_info << "|- Waiting for insert" << endl; NdbSleep_MilliSleep(20); } if(ctx->isTestStopped()){ abort(); } // Now the record should have been inserted // Read it once again in the same transaction // Should also reutrn 626 if reads are consistent // NOTE! Currently it's not possible to start a new operation // on a transaction that has returned an error code // This is wat fail in this test // MASV 20030624 const int res2 = readOneNoCommit(pNdb, pTrans, tab, &row2); pTrans->execute(Commit); pNdb->closeTransaction(pTrans); g_info << "|- res2 = " << res2 << endl; if (res2 == 626 && res1 == res2) return NDBT_OK; else return NDBT_FAILED; } int runFillTable(NDBT_Context* ctx, NDBT_Step* step){ int batch = 512; //4096; HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.fillTable(GETNDB(step), batch ) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runClearTable2(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); UtilTransactions utilTrans(*ctx->getTab()); if (utilTrans.clearTable2(GETNDB(step), records, 240) != 0){ return NDBT_FAILED; } return NDBT_OK; } #define CHECK(b) if (!(b)) { \ ndbout << "ERR: "<< step->getName() \ << " failed on line " << __LINE__ << endl; \ result = NDBT_FAILED; \ break; } #define CHECK2(b) if (!(b)) { \ ndbout << "ERR: "<< step->getName() \ << " failed on line " << __LINE__ << endl; \ result = NDBT_FAILED; } int runNoCommitSleep(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); int sleepTime = 100; // ms for (int i = 2; i < 8; i++){ CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); ndbout << i <<": Sleeping for " << sleepTime << " ms" << endl; NdbSleep_MilliSleep(sleepTime); // Dont care about result of these ops hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive); hugoOps.closeTransaction(pNdb); sleepTime = sleepTime *i; } hugoOps.closeTransaction(pNdb); return result; } int runCommit626(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCommit630(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 630); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCommit_TryCommit626(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction, TryCommit CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction, TryCommit // Several operations in one transaction // The insert is OK CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCommit_TryCommit630(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction, TryCommit CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 630); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCommit_CommitAsMuchAsPossible626(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); } while(false); hugoOps.closeTransaction(pNdb); return result; } int runCommit_CommitAsMuchAsPossible630(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.pkDeleteRecord(pNdb, 2) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 630); CHECK(hugoOps.closeTransaction(pNdb) == 0); CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 2) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); } while(false); hugoOps.closeTransaction(pNdb); return result; } int runNoCommit626(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // No commit transaction, readTuple CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // No commit transaction, readTupleExcluive CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runNoCommit630(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // No commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 630); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runNoCommitRollback626(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // No commit transaction, rollback CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // No commit transaction, rollback // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runNoCommitRollback630(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // No commit transaction, rollback CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 630); CHECK(hugoOps.execute_Rollback(pNdb) == 0); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runNoCommitAndClose(NDBT_Context* ctx, NDBT_Step* step){ int i, result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Read CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) CHECK(hugoOps.pkReadRecord(pNdb, i, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Update CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) CHECK(hugoOps.pkUpdateRecord(pNdb, i) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Delete CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) CHECK(hugoOps.pkDeleteRecord(pNdb, i) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Try to insert, record should already exist CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) CHECK(hugoOps.pkInsertRecord(pNdb, i) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 630); CHECK(hugoOps.closeTransaction(pNdb) == 0); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCheckRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.saveCopyOfRecord() == NDBT_OK); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Delete record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkDeleteRecord(pNdb, 5) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is deleted CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.compareRecordToCopy() == NDBT_OK); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); int numRecords = 5; do{ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Update value 0 CHECK(hugoOps.closeTransaction(pNdb) == 0); // Update record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkUpdateRecord(pNdb, 1, numRecords, 5) == 0);// Updates value 5 CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is updated CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(5) == NDBT_OK); // Updates value 5 CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Updates value 0 }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); CHECK(hugoOps.closeTransaction(pNdb) == 0); Uint32 updatesValue = 0; Uint32 j; for(Uint32 i = 0; i<1; i++){ // Read record 5 - 10 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); for(j = 0; j<10; j++){ // Update record 5 - 10 updatesValue++; CHECK(hugoOps.pkUpdateRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } for(j = 0; j<10; j++){ // Delete record 5 - 10 times CHECK(hugoOps.pkDeleteRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); #if 0 // Check records are deleted CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); #endif updatesValue++; CHECK(hugoOps.pkInsertRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } CHECK(hugoOps.pkDeleteRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check records are deleted CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); } // Check records are not deleted // after rollback CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCheckImplicitRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Read record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Update record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkUpdateRecord(pNdb, 5) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Delete record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkDeleteRecord(pNdb, 5) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is not deleted // Close transaction should have rollbacked CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runCheckCommitDelete(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Read 10 records CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Update 10 records CHECK(hugoOps.pkUpdateRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Delete 10 records CHECK(hugoOps.pkDeleteRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record's are deleted CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runRollbackNothing(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); do{ // Delete record 5 - 15 CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkDeleteRecord(pNdb, 5, 10) == 0); // Rollback CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check records are not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.execute_Rollback(pNdb) == 0); }while(false); hugoOps.closeTransaction(pNdb); return result; } int runMassiveRollback(NDBT_Context* ctx, NDBT_Step* step){ NdbRestarter restarter; const int records = 4 * restarter.getNumDbNodes(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records) != 0){ return NDBT_FAILED; } int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); const Uint32 OPS_PER_TRANS = 256; const Uint32 OPS_TOTAL = 4096; for(int row = 0; row < records; row++){ int res; CHECK(hugoOps.startTransaction(pNdb) == 0); for(Uint32 i = 0; igetNdbError(res); CHECK(err.classification == NdbError::TimeoutExpired); break; } } if(result != NDBT_OK){ break; } g_info << "executeRollback" << endl; CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); } hugoOps.closeTransaction(pNdb); return result; } int runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), 1) != 0){ return NDBT_FAILED; } int result = NDBT_OK; HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); const Uint32 OPS_TOTAL = 4096; const Uint32 LOOPS = 10; for(Uint32 loop = 0; loopgetTab()); Ndb* pNdb = GETNDB(step); const Uint32 BATCH = 10; const Uint32 OPS_TOTAL = 50; const Uint32 LOOPS = 100; for(Uint32 loop = 0; loopgetTab()); Ndb* pNdb = GETNDB(step); const Uint32 BATCH = 10; const Uint32 OPS_TOTAL = 20; const Uint32 LOOPS = 100; for(Uint32 loop = 0; loopno_of_events; i++) { if (time0->events[i].MemoryUsage.block != block) continue; unsigned node = time0->events[i].source_nodeid; for (int j = 0; j < time1->no_of_events; j++) { if (time1->events[j].MemoryUsage.block != block) continue; if (time1->events[j].source_nodeid != node) continue; diff += time0->events[i].MemoryUsage.pages_used - time1->events[j].MemoryUsage.pages_used; } } return diff; } int runTupErrors(NDBT_Context* ctx, NDBT_Step* step){ NdbRestarter restarter; HugoTransactions hugoTrans(*ctx->getTab()); HugoOperations hugoOps(*ctx->getTab()); Ndb* pNdb = GETNDB(step); const NdbDictionary::Table * tab = ctx->getTab(); int i; int bits = TupError::TE_MULTI_OP; for(i = 0; igetNoOfColumns(); i++) { if (tab->getColumn(i)->getArrayType() != NdbDictionary::Column::ArrayTypeFixed) bits |= TupError::TE_VARSIZE; if (tab->getColumn(i)->getStorageType()!= NdbDictionary::Column::StorageTypeMemory) bits |= TupError::TE_DISK; } if (restarter.getNumDbNodes() >= 2) { bits |= TupError::TE_REPLICA; } NdbDictionary::Dictionary::List l; pNdb->getDictionary()->listIndexes(l, tab->getName()); for (i = 0; i<(int)l.count; i++) { if (DictTabInfo::isOrderedIndex(l.elements[i].type)) bits |= TupError::TE_OI; if (DictTabInfo::isUniqueIndex(l.elements[i].type)) bits |= TupError::TE_UI; } /** * Insert */ for(i = 0; f_tup_errors[i].op != -1; i++) { if (f_tup_errors[i].op != NdbOperation::InsertRequest) { continue; } if ((f_tup_errors[i].bits & bits) != f_tup_errors[i].bits) { g_err << "Skipping " << f_tup_errors[i].error << " - req bits: " << hex << f_tup_errors[i].bits << " bits: " << hex << bits << endl; continue; } g_err << "Testing error insert: " << f_tup_errors[i].error << endl; restarter.insertErrorInAllNodes(f_tup_errors[i].error); struct ndb_mgm_events * before = ndb_mgm_dump_events(restarter.handle, NDB_LE_MemoryUsage, 0, 0); if (before == 0) { ndbout_c("ERROR: failed to fetch report!"); return NDBT_FAILED;; } if (f_tup_errors[i].bits & TupError::TE_MULTI_OP) { } else { hugoTrans.loadTable(pNdb, 5); } restarter.insertErrorInAllNodes(0); if (hugoTrans.clearTable(pNdb, 5) != 0) { return NDBT_FAILED; } struct ndb_mgm_events * after = ndb_mgm_dump_events(restarter.handle, NDB_LE_MemoryUsage, 0, 0); if (after == 0) { ndbout_c("ERROR: failed to fetch report!"); return NDBT_FAILED;; } /** * check memory leak */ if (compare(DBTUP, before, after) != 0) { ndbout_c("memleak detected!!"); return NDBT_FAILED;; } free(before); free(after); } /** * update */ struct ndb_mgm_events * before = ndb_mgm_dump_events(restarter.handle, NDB_LE_MemoryUsage, 0, 0); hugoTrans.loadTable(pNdb, 5); for(i = 0; f_tup_errors[i].op != -1; i++) { if (f_tup_errors[i].op != NdbOperation::UpdateRequest) { continue; } if ((f_tup_errors[i].bits & bits) != f_tup_errors[i].bits) { g_err << "Skipping " << f_tup_errors[i].error << " - req bits: " << hex << f_tup_errors[i].bits << " bits: " << hex << bits << endl; continue; } g_err << "Testing error insert: " << f_tup_errors[i].error << endl; restarter.insertErrorInAllNodes(f_tup_errors[i].error); if (f_tup_errors[i].bits & TupError::TE_MULTI_OP) { } else { hugoTrans.scanUpdateRecords(pNdb, 5); } restarter.insertErrorInAllNodes(0); if (hugoTrans.scanUpdateRecords(pNdb, 5) != 0) { return NDBT_FAILED; } } if (hugoTrans.clearTable(pNdb) != 0) { return NDBT_FAILED; } struct ndb_mgm_events * after = ndb_mgm_dump_events(restarter.handle, NDB_LE_MemoryUsage, 0, 0); int diff = compare(DBTUP, before, after); free(before); free(after); if (diff != 0) { ndbout_c("memleak detected!!"); return NDBT_FAILED;; } return NDBT_OK; } int runInsertError(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; HugoOperations hugoOp1(*ctx->getTab()); HugoOperations hugoOp2(*ctx->getTab()); Ndb* pNdb = GETNDB(step); NdbRestarter restarter; restarter.insertErrorInAllNodes(4017); const Uint32 LOOPS = 10; for (Uint32 i = 0; igetTab()); Ndb* pNdb = GETNDB(step); NdbRestarter restarter; restarter.insertErrorInAllNodes(4017); const Uint32 LOOPS = 1; for (Uint32 i = 0; igetDictionary(); HugoOperations ops(*ctx->getTab()); int loops = ctx->getNumLoops(); //const int rows = ctx->getNumRecords(); while (loops--) { ops.startTransaction(pNdb); ops.pkReadRecord(pNdb, 1, 1); ops.execute_Commit(pNdb, AO_IgnoreError); sleep(10); ops.closeTransaction(pNdb); } return NDBT_OK; } int runDeleteRead(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* tab = ctx->getTab(); NDBT_ResultRow row(*ctx->getTab()); HugoTransactions tmp(*ctx->getTab()); int a; int loops = ctx->getNumLoops(); //const int rows = ctx->getNumRecords(); while (loops--) { NdbTransaction* pTrans = pNdb->startTransaction(); NdbOperation* pOp = pTrans->getNdbOperation(tab->getName()); pOp->deleteTuple(); tmp.equalForRow(pOp, loops); // Define attributes to read for(a = 0; agetNoOfColumns(); a++) { if((row.attributeStore(a) = pOp->getValue(tab->getColumn(a)->getName())) == 0) { NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } } pTrans->execute(Commit); pTrans->close(); pTrans = pNdb->startTransaction(); pOp = pTrans->getNdbOperation(tab->getName()); pOp->insertTuple(); tmp.setValues(pOp, loops, 0); pOp = pTrans->getNdbOperation(tab->getName()); pOp->deleteTuple(); tmp.equalForRow(pOp, loops); for(a = 0; agetNoOfColumns(); a++) { if((row.attributeStore(a) = pOp->getValue(tab->getColumn(a)->getName())) == 0) { NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } } if (pTrans->execute(Commit) != 0) { NDB_ERR(pTrans->getNdbError()); return NDBT_FAILED; } pTrans->close(); } return NDBT_OK; } int runBug27756(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); //NdbDictionary::Dictionary * dict = pNdb->getDictionary(); HugoOperations ops(*ctx->getTab()); int loops = ctx->getNumLoops(); //const int rows = ctx->getNumRecords(); Vector copies; while (loops--) { ops.startTransaction(pNdb); ops.pkInsertRecord(pNdb, 1, 1); ops.execute_NoCommit(pNdb); NdbTransaction* pTrans = ops.getTransaction(); NdbOperation* op = pTrans->getNdbOperation(ctx->getTab()->getName()); op->interpretedUpdateTuple(); ops.equalForRow(op, 1); NdbRecAttr* attr = op->getValue(NdbDictionary::Column::COPY_ROWID); ops.execute_NoCommit(pNdb); copies.push_back(attr->u_64_value()); ndbout_c("copy at: %llx", copies.back()); ops.execute_NoCommit(pNdb); ops.pkDeleteRecord(pNdb, 1, 1); ops.execute_NoCommit(pNdb); if (loops & 1) { ops.execute_Rollback(pNdb); ops.closeTransaction(pNdb); } else { ops.execute_Commit(pNdb); ops.closeTransaction(pNdb); ops.clearTable(pNdb, 100); } } for (Uint32 i = 0; igetTab(); HugoOperations hugoOp1(*table); HugoOperations hugoOp2(*table); Ndb* pNdb = GETNDB(step); int loops = ctx->getNumLoops(); bool inserted= false; while (loops--) { if (!inserted) { CHECK(hugoOp1.startTransaction(pNdb) == 0); CHECK(hugoOp1.pkInsertRecord(pNdb, 1, 1) == 0); CHECK(hugoOp1.execute_Commit(pNdb) == 0); CHECK(hugoOp1.closeTransaction(pNdb) == 0); inserted= 1; } // Use TC hint to hit the same node in both transactions. Uint32 key_val= 0; const char *key= (const char *)(&key_val); CHECK(hugoOp1.startTransaction(pNdb, table, key, 4) == 0); CHECK(hugoOp2.startTransaction(pNdb, table, key, 4) == 0); // First take 2*read lock on the tuple in transaction 1. for (Uint32 i= 0; i < 2; i++) { CHECK(hugoOp1.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); CHECK(hugoOp1.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } CHECK(hugoOp1.execute_NoCommit(pNdb) == 0); // Now send ops in two transactions, one batch. // First 2*read in transaction 2. for (Uint32 i= 0; i < 2; i++) { CHECK(hugoOp2.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); CHECK(hugoOp2.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } CHECK(hugoOp2.execute_async_prepare(pNdb, NdbTransaction::NoCommit) == 0); // Second op an update in transaction 1. CHECK(hugoOp1.pkUpdateRecord(pNdb, 1, 1) == 0); CHECK(hugoOp1.execute_async_prepare(pNdb, NdbTransaction::Commit) == 0); // Transaction 1 will now hang waiting on transaction 2 to commit before it // can upgrade its read lock to a write lock. // With the bug, we get a node failure due to watchdog timeout here. CHECK(hugoOp2.wait_async(pNdb) == 0); // Now commit transaction 2, we should see transaction 1 finish with the // update. CHECK(hugoOp2.execute_async_prepare(pNdb, NdbTransaction::Commit) == 0); CHECK(hugoOp2.wait_async(pNdb) == 0); // No error check, as transaction 1 may have terminated already. hugoOp1.wait_async(pNdb); CHECK(hugoOp1.closeTransaction(pNdb) == 0); CHECK(hugoOp2.closeTransaction(pNdb) == 0); } return result; } int runBug20535(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); const NdbDictionary::Table * tab = ctx->getTab(); bool hasDefault = false; for (Uint32 i = 0; i<(Uint32)tab->getNoOfColumns(); i++) { if (tab->getColumn(i)->getNullable() || tab->getColumn(i)->getDefaultValue()) { hasDefault = true; break; } } if (!hasDefault) return NDBT_OK; HugoTransactions hugoTrans(* tab); hugoTrans.loadTable(pNdb, 1); NdbTransaction* pTrans = pNdb->startTransaction(); NdbOperation* pOp = pTrans->getNdbOperation(tab->getName()); pOp->deleteTuple(); hugoTrans.equalForRow(pOp, 0); if (pTrans->execute(NoCommit) != 0) return NDBT_FAILED; pOp = pTrans->getNdbOperation(tab->getName()); pOp->insertTuple(); hugoTrans.equalForRow(pOp, 0); for (Uint32 i = 0; i<(Uint32)tab->getNoOfColumns(); i++) { if (!tab->getColumn(i)->getPrimaryKey() && !tab->getColumn(i)->getNullable() && !tab->getColumn(i)->getDefaultValue()) { hugoTrans.setValueForAttr(pOp, i, 0, 1); } } if (pTrans->execute(Commit) != 0) return NDBT_FAILED; pTrans->close(); pTrans = pNdb->startTransaction(); pOp = pTrans->getNdbOperation(tab->getName()); pOp->readTuple(); hugoTrans.equalForRow(pOp, 0); Vector values; for (Uint32 i = 0; i<(Uint32)tab->getNoOfColumns(); i++) { if (!tab->getColumn(i)->getPrimaryKey() && (tab->getColumn(i)->getNullable() || tab->getColumn(i)->getDefaultValue())) { values.push_back(pOp->getValue(i)); } } if (pTrans->execute(Commit) != 0) return NDBT_FAILED; bool defaultOk = true; for (unsigned int i = 0; igetColumn(); unsigned int defaultLen = 0; const char* def = (const char*) col->getDefaultValue(&defaultLen); if (def) { /* Column has a native default, check that it was set */ if (!recAttr->isNULL()) { if (memcmp(def, recAttr->aRef(), defaultLen) != 0) { defaultOk = false; ndbout_c("column %s does not have correct default value", recAttr->getColumn()->getName()); } } else { defaultOk = false; ndbout_c("column %s is null, should have default value", recAttr->getColumn()->getName()); } } else { /* Column has Null as its default */ if (!recAttr->isNULL()) { defaultOk = false; ndbout_c("column %s is not NULL", recAttr->getColumn()->getName()); } } } pTrans->close(); if (defaultOk) return NDBT_OK; else return NDBT_FAILED; } int runDDInsertFailUpdateBatch(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); NdbRestarter restarter; const NdbDictionary::Table * tab = ctx->getTab(); int errCode = 0; int expectedError = 0; { bool tabHasDD = false; for(int i = 0; igetNoOfColumns(); i++) { tabHasDD |= (tab->getColumn(i)->getStorageType() == NdbDictionary::Column::StorageTypeDisk); } if (tabHasDD) { errCode = 4021; expectedError = 1601; } else { NdbDictionary::Dictionary::List l; pNdb->getDictionary()->listIndexes(l, tab->getName()); for (Uint32 i = 0; igetName()); return NDBT_OK; } } HugoOperations hugoOps(*ctx->getTab()); int result = NDBT_OK; for (Uint32 loop = 0; loop < 100; loop ++) { restarter.insertErrorInAllNodes(errCode); CHECK(hugoOps.startTransaction(pNdb) == 0); /* Create batch with insert op (which will fail due to disk allocation issue) * followed by update op on same pk * Transaction will abort due to insert failure, and reason should be * disk space exhaustion, not any issue with the update. */ CHECK(hugoOps.pkInsertRecord(pNdb, loop, 1, 0) == 0); /* Add up to 16 updates after the insert */ Uint32 numUpdates = 1 + (loop % 15); for (Uint32 updateCnt = 0; updateCnt < numUpdates; updateCnt++) CHECK(hugoOps.pkUpdateRecord(pNdb, loop, 1, 1+updateCnt) == 0); CHECK(hugoOps.execute_Commit(pNdb) != 0); /* Expect failure */ NdbError err= hugoOps.getTransaction()->getNdbError(); CHECK(err.code == expectedError); hugoOps.closeTransaction(pNdb); } restarter.insertErrorInAllNodes(0); return result; } // Bug34348 #define chk1(b) \ if (!(b)) { g_err << "ERR: " << step->getName() << " failed on line " << __LINE__ << endl; result = NDBT_FAILED; continue; } #define chk2(b, e) \ if (!(b)) { g_err << "ERR: " << step->getName() << " failed on line " << __LINE__ << ": " << e << endl; result = NDBT_FAILED; continue; } const char* tabname_bug34348 = "TBug34348"; int runBug34348insert(NDBT_Context* ctx, NDBT_Step* step, HugoOperations& ops, int i, bool* rangeFull) { const int rangeFullError = 633; Ndb* pNdb = GETNDB(step); int result = NDBT_OK; while (result == NDBT_OK) { int code = 0; chk2(ops.startTransaction(pNdb) == 0, ops.getNdbError()); chk2(ops.pkInsertRecord(pNdb, i, 1) == 0, ops.getNdbError()); chk2(ops.execute_Commit(pNdb) == 0 || (code = ops.getNdbError().code) == rangeFullError, ops.getNdbError()); ops.closeTransaction(pNdb); *rangeFull = (code == rangeFullError); break; } return result; } int runBug34348delete(NDBT_Context* ctx, NDBT_Step* step, HugoOperations& ops, int i) { Ndb* pNdb = GETNDB(step); int result = NDBT_OK; while (result == NDBT_OK) { chk2(ops.startTransaction(pNdb) == 0, ops.getNdbError()); chk2(ops.pkDeleteRecord(pNdb, i, 1) == 0, ops.getNdbError()); chk2(ops.execute_Commit(pNdb) == 0, ops.getNdbError()); ops.closeTransaction(pNdb); break; } return result; } int runBug34348(NDBT_Context* ctx, NDBT_Step* step) { myRandom48Init((long)NdbTick_CurrentMillisecond()); Ndb* pNdb = GETNDB(step); NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); NdbRestarter restarter; int result = NDBT_OK; const int loops = ctx->getNumLoops(); const int errInsDBACC = 3002; const int errInsCLEAR = 0; Uint32* rowmask = 0; while (result == NDBT_OK) { chk1(restarter.insertErrorInAllNodes(errInsDBACC) == 0); ndbout << "error insert " << errInsDBACC << " done" << endl; const NdbDictionary::Table* pTab = 0; while (result == NDBT_OK) { (void)pDict->dropTable(tabname_bug34348); NdbDictionary::Table tab(tabname_bug34348); { NdbDictionary::Column col("a"); col.setType(NdbDictionary::Column::Unsigned); col.setPrimaryKey(true); tab.addColumn(col); } { NdbDictionary::Column col("b"); col.setType(NdbDictionary::Column::Unsigned); col.setNullable(false); tab.addColumn(col); } chk2(pDict->createTable(tab) == 0, pDict->getNdbError()); chk2((pTab = pDict->getTable(tabname_bug34348)) != 0, pDict->getNdbError()); break; } HugoOperations ops(*pTab); ops.setQuiet(); int rowmaxprev = 0; int loop = 0; while (result == NDBT_OK && loop < loops) { ndbout << "loop:" << loop << endl; int rowcnt = 0; // fill up while (result == NDBT_OK) { bool rangeFull; chk1(runBug34348insert(ctx, step, ops, rowcnt, &rangeFull) == NDBT_OK); if (rangeFull) { // 360449 (1 fragment) ndbout << "dir range full at " << rowcnt << endl; break; } rowcnt++; } chk1(result == NDBT_OK); const int rowmax = rowcnt; if (loop == 0) rowmaxprev = rowmax; else chk2(rowmaxprev == rowmax, "rowmaxprev:" << rowmaxprev << " rowmax:" << rowmax); const int sz = (rowmax + 31) / 32; delete [] rowmask; rowmask = new Uint32 [sz]; BitmaskImpl::clear(sz, rowmask); { int i; for (i = 0; i < rowmax; i++) BitmaskImpl::set(sz, rowmask, i); } // random delete until insert succeeds while (result == NDBT_OK) { int i = myRandom48(rowmax); if (!BitmaskImpl::get(sz, rowmask, i)) continue; chk1(runBug34348delete(ctx, step, ops, i) == NDBT_OK); BitmaskImpl::clear(sz, rowmask, i); rowcnt--; bool rangeFull; chk1(runBug34348insert(ctx, step, ops, rowmax, &rangeFull) == NDBT_OK); if (!rangeFull) { chk1(runBug34348delete(ctx, step, ops, rowmax) == NDBT_OK); // 344063 (1 fragment) ndbout << "dir range released at " << rowcnt << endl; break; } } chk1(result == NDBT_OK); require(BitmaskImpl::count(sz, rowmask)== (Uint32)rowcnt); // delete about 1/2 remaining while (result == NDBT_OK) { int i; for (i = 0; result == NDBT_OK && i < rowmax; i++) { if (!BitmaskImpl::get(sz, rowmask, i)) continue; if (myRandom48(100) < 50) continue; chk1(runBug34348delete(ctx, step, ops, i) == NDBT_OK); BitmaskImpl::clear(sz, rowmask, i); rowcnt--; } ndbout << "deleted down to " << rowcnt << endl; break; } chk1(result == NDBT_OK); require(BitmaskImpl::count(sz, rowmask)== (Uint32)rowcnt); // insert until full again while (result == NDBT_OK) { int i; for (i = 0; result == NDBT_OK && i < rowmax; i++) { if (BitmaskImpl::get(sz, rowmask, i)) continue; bool rangeFull; chk1(runBug34348insert(ctx, step, ops, i, &rangeFull) == NDBT_OK); // assume all can be inserted back chk2(!rangeFull, "dir range full too early at " << rowcnt); BitmaskImpl::set(sz, rowmask, i); rowcnt++; } chk1(result == NDBT_OK); ndbout << "inserted all back to " << rowcnt << endl; break; } chk1(result == NDBT_OK); require(BitmaskImpl::count(sz, rowmask)== (Uint32)rowcnt); // delete all while (result == NDBT_OK) { int i; for (i = 0; result == NDBT_OK && i < rowmax; i++) { if (!BitmaskImpl::get(sz, rowmask, i)) continue; chk1(runBug34348delete(ctx, step, ops, i) == NDBT_OK); BitmaskImpl::clear(sz, rowmask, i); rowcnt--; } ndbout << "deleted all" << endl; break; } chk1(result == NDBT_OK); require(BitmaskImpl::count(sz, rowmask)== (Uint32)rowcnt); require(rowcnt == 0); loop++; } chk2(pDict->dropTable(tabname_bug34348) == 0, pDict->getNdbError()); chk1(restarter.insertErrorInAllNodes(errInsCLEAR) == 0); ndbout << "error insert clear done" << endl; break; } if (result != NDBT_OK && restarter.insertErrorInAllNodes(errInsCLEAR) != 0) g_err << "error insert clear failed" << endl; delete [] rowmask; rowmask = 0; return result; } #define check(b, e) \ if (!(b)) { g_err << "ERR: " << step->getName() << " failed on line " << __LINE__ << ": " << e.getNdbError() << endl; return NDBT_FAILED; } int runUnlocker(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int batchSize = ctx->getProperty("Batchsize", 1); int doubleUnlock = ctx->getProperty("DoubleUnlock", (Uint32)0); int lm = ctx->getProperty("LockMode", NdbOperation::LM_Read); int i = 0; HugoOperations hugoOps(*ctx->getTab()); Ndb* ndb = GETNDB(step); g_err << "Unlocker : "; g_err << "Loops = " << loops << " Records = " << records << " Batchsize = " << batchSize << endl; while(i++ < loops) { g_err << i << " "; check(hugoOps.startTransaction(ndb) == 0, (*ndb)); const int maxRetries = 10; int retryAttempt = 0; int r = records; Vector lockHandles; while(r > 0) { int batchContents = MIN(r, batchSize); check(hugoOps.pkReadRecordLockHandle(ndb, lockHandles, records - r, batchContents, (NdbOperation::LockMode)lm) == 0, hugoOps); r-= batchContents; if (hugoOps.execute_NoCommit(ndb) != 0) { NdbError err = hugoOps.getNdbError(); if ((err.status == NdbError::TemporaryError) && retryAttempt < maxRetries){ NDB_ERR(err); NdbSleep_MilliSleep(50); retryAttempt++; lockHandles.clear(); check(hugoOps.closeTransaction(ndb) == 0, hugoOps); check(hugoOps.startTransaction(ndb) == 0, (*ndb)); continue; } NDB_ERR(err); return NDBT_FAILED; } check(hugoOps.pkUnlockRecord(ndb, lockHandles) == 0, hugoOps); check(hugoOps.execute_NoCommit(ndb) == 0, hugoOps); if (doubleUnlock) { NdbOperation::AbortOption ao; switch(rand() % 2) { case 0: ao = NdbOperation::AbortOnError; break; case 1: default: ao = NdbOperation::AO_IgnoreError; break; } g_err << "Double unlock, abort option is " << ao << endl; /* Failure scenario */ check(hugoOps.pkUnlockRecord(ndb, lockHandles, 0, // offset ~(0), // NumRecords ao) == 0, hugoOps); check(hugoOps.execute_NoCommit(ndb, DefaultAbortOption) != 0, hugoOps); /* 417 = Bad operation reference */ check(hugoOps.getNdbError().code == 417, hugoOps); if (ao == NdbOperation::AbortOnError) { /* Restart transaction and continue with next loop iteration */ r = 0; lockHandles.clear(); check(hugoOps.closeTransaction(ndb) == 0, hugoOps); check(hugoOps.startTransaction(ndb) == 0, (*ndb)); continue; } /* Otherwise, IgnoreError, so let's attempt to * continue */ } check(hugoOps.releaseLockHandles(ndb, lockHandles) == 0, hugoOps); lockHandles.clear(); } switch(rand() % 3) { case 0: check(hugoOps.execute_Commit(ndb) == 0, hugoOps); break; case 1: check(hugoOps.execute_Rollback(ndb) == 0, hugoOps); break; default: /* Do nothing, just close */ break; } check(hugoOps.closeTransaction(ndb) == 0, hugoOps); } g_err << endl; return NDBT_OK; } template class Vector; int runBug54986(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter restarter; Ndb* pNdb = GETNDB(step); NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); const NdbDictionary::Table * pTab = ctx->getTab(); NdbDictionary::Table copy = *pTab; int result = NDBT_OK; BaseString name; name.assfmt("%s_COPY", copy.getName()); copy.setName(name.c_str()); pDict->createTable(copy); const NdbDictionary::Table * copyTab = pDict->getTable(copy.getName()); HugoTransactions hugoTrans(*pTab); hugoTrans.loadTable(pNdb, 20); hugoTrans.clearTable(pNdb); const Uint32 rows = 5000; HugoTransactions hugoTransCopy(*copyTab); hugoTransCopy.loadTable(pNdb, rows); ndbout << "Waiting for 3 LCPs" << endl; { restarter.getNumDbNodes(); // connect int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_CHECKPOINT, 0 }; NdbLogEventHandle handle = ndb_mgm_create_logevent_handle(restarter.handle, filter); for (Uint32 i = 0; i<3; i++) { int dump[] = { DumpStateOrd::DihStartLcpImmediately }; struct ndb_logevent event; restarter.dumpStateAllNodes(dump, 1); while(ndb_logevent_get_next(handle, &event, 0) >= 0 && event.type != NDB_LE_LocalCheckpointStarted); while(ndb_logevent_get_next(handle, &event, 0) >= 0 && event.type != NDB_LE_LocalCheckpointCompleted); ndbout << "LCP" << i << endl; } ndb_mgm_destroy_logevent_handle(&handle); } for (int i = 0; i<5; i++) { ndbout << "loop: " << i << endl; int val1 = DumpStateOrd::DihMaxTimeBetweenLCP; int val2 = DumpStateOrd::DihStartLcpImmediately; // Force start ndbout << " ... dumpState set 'MaxTimeBetweenLCP'" << endl; CHK1(restarter.dumpStateAllNodes(&val1, 1) == 0); int val[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; ndbout << " ... dumpState set 'RestartOnErrorInsert = NoStart'" << endl; CHK1(restarter.dumpStateAllNodes(val, 2) == 0); ndbout << " ... insert error 932" << endl; CHK1(restarter.insertErrorInAllNodes(932) ==0); // prevent arbit shutdown HugoTransactions hugoTrans(*pTab); ndbout << " ... loadTable" << endl; CHK1(hugoTrans.loadTable(pNdb, 20) == 0); ndbout << " ... dumpState set 'StartLcpImmediately'" << endl; CHK1(restarter.dumpStateAllNodes(&val2, 1) == 0); ndbout << " ... sleep for 15 sec" << endl; NdbSleep_SecSleep(15); ndbout << " ... clearTable" << endl; CHK1(hugoTrans.clearTable(pNdb) == 0); ndbout << " ... Hugo txn" << endl; CHK1(hugoTransCopy.pkReadRecords(pNdb, rows) == 0); HugoOperations hugoOps(*pTab); CHK1(hugoOps.startTransaction(pNdb) == 0); CHK1(hugoOps.pkInsertRecord(pNdb, 1) == 0); CHK1(hugoOps.execute_NoCommit(pNdb) == 0); ndbout << " ... insert error 5056 (Crash on LCP_COMPLETE_REP)" << endl; CHK1(restarter.insertErrorInAllNodes(5056) == 0); ndbout << " ... dumpState set 'StartLcpImmediately'" << endl; CHK1(restarter.dumpStateAllNodes(&val2, 1) == 0); ndbout << " ... waitClusterNoStart" << endl; CHK1(restarter.waitClusterNoStart() == 0); int vall = 11009; CHK1(restarter.dumpStateAllNodes(&vall, 1) == 0); CHK1(restarter.startAll() == 0); CHK1(restarter.waitClusterStarted() == 0); CHK1(hugoOps.closeTransaction(pNdb) == 0); } pDict->dropTable(copy.getName()); // remove 25-page pgman restarter.restartAll(false, true, true); restarter.waitClusterNoStart(); restarter.startAll(); restarter.waitClusterStarted(); return result; } int runBug54944(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); const NdbDictionary::Table * pTab = ctx->getTab(); NdbRestarter res; int databuffer = ctx->getProperty("DATABUFFER"); for (Uint32 i = 0; i<5; i++) { Uint32 rows = 5000 + i * 2000; HugoOperations hugoOps(*pTab); hugoOps.startTransaction(pNdb); for (Uint32 r = 0; r < rows; r++) { for (Uint32 b = 0; b<100; b++, r++) { hugoOps.pkInsertRecord(pNdb, r); } hugoOps.execute_NoCommit(pNdb); } if (!databuffer) res.insertErrorInAllNodes(8087); else res.insertErrorInAllNodes(8096); HugoTransactions hugoTrans(*pTab); hugoTrans.loadTableStartFrom(pNdb, 50000, 100); hugoOps.execute_Rollback(pNdb); hugoTrans.clearTable(pNdb); res.insertErrorInAllNodes(0); } return NDBT_OK; } int runBug59496_scan(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); const NdbDictionary::Table * pTab = ctx->getTab(); NdbRestarter res; int rowcount = ctx->getProperty("CHECK_ROWCOUNT", Uint32(0)); int records = ctx->getNumRecords(); if (rowcount == 0) records = 0; HugoTransactions hugoTrans(*pTab); while (!ctx->isTestStopped()) { if (hugoTrans.scanReadRecords(pNdb, records, 0, 0, NdbOperation::LM_CommittedRead, (int)NdbScanOperation::SF_TupScan) != NDBT_OK) return NDBT_FAILED; } return NDBT_OK; } int runBug59496_case1(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); NdbRestarter res; int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); HugoOperations hugoOps(*ctx->getTab()); for (int i = 0; i < loops; i++) { hugoOps.startTransaction(pNdb); hugoOps.pkInsertRecord(pNdb, 0, records, 0); hugoOps.execute_NoCommit(pNdb); hugoOps.pkUpdateRecord(pNdb, 0, records, rand()); hugoOps.execute_NoCommit(pNdb); hugoOps.pkUpdateRecord(pNdb, 0, records, rand()); hugoOps.execute_NoCommit(pNdb); res.insertErrorInAllNodes(8089); hugoOps.execute_Commit(pNdb); res.insertErrorInAllNodes(0); hugoOps.closeTransaction(pNdb); hugoOps.clearTable(pNdb); } ctx->stopTest(); return NDBT_OK; } int runBug59496_case2(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); NdbRestarter res; int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); HugoOperations hugoOps(*ctx->getTab()); for (int i = 0; i < loops; i++) { hugoOps.startTransaction(pNdb); hugoOps.pkDeleteRecord(pNdb, 0, records); hugoOps.execute_NoCommit(pNdb); hugoOps.pkInsertRecord(pNdb, 0, records, 0); hugoOps.execute_NoCommit(pNdb); res.insertErrorInAllNodes(8089); hugoOps.execute_Rollback(pNdb); res.insertErrorInAllNodes(0); hugoOps.closeTransaction(pNdb); } ctx->stopTest(); return NDBT_OK; } #define CHK_RET_FAILED(x) if (!(x)) { ndbout_c("Failed on line: %u", __LINE__); return NDBT_FAILED; } int runTest899(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* pTab = ctx->getTab(); const int rows = ctx->getNumRecords(); const int loops = ctx->getNumLoops(); const int batch = ctx->getProperty("Batch", Uint32(50)); const int until_stopped = ctx->getProperty("UntilStopped"); const NdbRecord * pRowRecord = pTab->getDefaultRecord(); CHK_RET_FAILED(pRowRecord != 0); const Uint32 len = NdbDictionary::getRecordRowLength(pRowRecord); Uint8 * pRow = new Uint8[len]; int count_ok = 0; int count_failed = 0; int count_899 = 0; for (int i = 0; i < loops || (until_stopped && !ctx->isTestStopped()); i++) { ndbout_c("loop: %d",i); int result = 0; for (int rowNo = 0; rowNo < rows;) { NdbTransaction* pTrans = pNdb->startTransaction(); CHK_RET_FAILED(pTrans != 0); for (int b = 0; rowNo < rows && b < batch; rowNo++, b++) { bzero(pRow, len); HugoCalculator calc(* pTab); NdbOperation::OperationOptions opts; bzero(&opts, sizeof(opts)); const NdbOperation* pOp = 0; switch(i % 2){ case 0: calc.setValues(pRow, pRowRecord, rowNo, rand()); pOp = pTrans->writeTuple(pRowRecord, (char*)pRow, pRowRecord, (char*)pRow, 0, &opts, sizeof(opts)); result = pTrans->execute(NoCommit); break; case 1: calc.setValues(pRow, pRowRecord, rowNo, rand()); pOp = pTrans->deleteTuple(pRowRecord, (char*)pRow, pRowRecord, (char*)pRow, 0, &opts, sizeof(opts)); result = pTrans->execute(NoCommit, AO_IgnoreError); break; } CHK_RET_FAILED(pOp != 0); if (result != 0) { goto found_error; } } result = pTrans->execute(Commit); if (result != 0) { found_error: count_failed++; NdbError err = pTrans->getNdbError(); if (! (err.status == NdbError::TemporaryError || err.classification == NdbError::NoDataFound || err.classification == NdbError::ConstraintViolation)) { ndbout << err << endl; } CHK_RET_FAILED(err.status == NdbError::TemporaryError || err.classification == NdbError::NoDataFound || err.classification == NdbError::ConstraintViolation); if (err.code == 899) { count_899++; ndbout << err << endl; } } else { count_ok++; } pTrans->close(); } } ndbout_c("count_ok: %d count_failed: %d (899: %d)", count_ok, count_failed, count_899); delete [] pRow; return count_899 == 0 ? NDBT_OK : NDBT_FAILED; } int runInit899(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter restarter; int val = DumpStateOrd::DihMinTimeBetweenLCP; restarter.dumpStateAllNodes(&val, 1); Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* pTab = ctx->getTab(); const NdbDictionary::Table * pTab2 = pNdb->getDictionary()-> getTable(pTab->getName()); int tableId = pTab2->getObjectId(); int val2[] = { DumpStateOrd::BackupErrorInsert, 10042, tableId }; for (int i = 0; i < restarter.getNumDbNodes(); i++) { if (i & 1) { int nodeId = restarter.getDbNodeId(i); ndbout_c("Setting slow LCP of table %d on node %d", tableId, nodeId); restarter.dumpStateOneNode(nodeId, val2, 3); } } return NDBT_OK; } int runEnd899(NDBT_Context* ctx, NDBT_Step* step) { // reset LCP speed NdbRestarter restarter; int val[] = { DumpStateOrd::DihMinTimeBetweenLCP, 0 }; restarter.dumpStateAllNodes(val, 2); restarter.insertErrorInAllNodes(0); return NDBT_OK; } int initSubscription(NDBT_Context* ctx, NDBT_Step* step){ /* Subscribe to events on the table, and put access * to the subscription somewhere handy */ Ndb* pNdb = GETNDB(step); const NdbDictionary::Table& tab = *ctx->getTab(); bool merge_events = false; bool report = false; char eventName[1024]; sprintf(eventName,"%s_EVENT",tab.getName()); NdbDictionary::Dictionary *myDict = pNdb->getDictionary(); if (!myDict) { g_err << "Dictionary not found " << pNdb->getNdbError().code << " " << pNdb->getNdbError().message << endl; return NDBT_FAILED; } myDict->dropEvent(eventName); NdbDictionary::Event myEvent(eventName); myEvent.setTable(tab.getName()); myEvent.addTableEvent(NdbDictionary::Event::TE_ALL); for(int a = 0; a < tab.getNoOfColumns(); a++){ myEvent.addEventColumn(a); } myEvent.mergeEvents(merge_events); if (report) myEvent.setReport(NdbDictionary::Event::ER_SUBSCRIBE); int res = myDict->createEvent(myEvent); // Add event to database if (res == 0) myEvent.print(); else if (myDict->getNdbError().classification == NdbError::SchemaObjectExists) { g_info << "Event creation failed event exists\n"; res = myDict->dropEvent(eventName); if (res) { g_err << "Failed to drop event: " << myDict->getNdbError().code << " : " << myDict->getNdbError().message << endl; return NDBT_FAILED; } // try again res = myDict->createEvent(myEvent); // Add event to database if (res) { g_err << "Failed to create event (1): " << myDict->getNdbError().code << " : " << myDict->getNdbError().message << endl; return NDBT_FAILED; } } else { g_err << "Failed to create event (2): " << myDict->getNdbError().code << " : " << myDict->getNdbError().message << endl; return NDBT_FAILED; } return NDBT_OK; } int removeSubscription(NDBT_Context* ctx, NDBT_Step* step){ /* Remove subscription created above */ Ndb* pNdb = GETNDB(step); const NdbDictionary::Table& tab = *ctx->getTab(); char eventName[1024]; sprintf(eventName,"%s_EVENT",tab.getName()); NdbDictionary::Dictionary *myDict = pNdb->getDictionary(); if (!myDict) { g_err << "Dictionary not found " << pNdb->getNdbError().code << " " << pNdb->getNdbError().message << endl; return NDBT_FAILED; } myDict->dropEvent(eventName); return NDBT_OK; } int runVerifyRowCount(NDBT_Context* ctx, NDBT_Step* step) { Ndb* ndb = GETNDB(step); /* Check that number of results returned by a normal scan * and per-fragment rowcount sum are equal */ Uint32 rowCountSum = 0; Uint32 rowScanCount = 0; int result = NDBT_OK; do { NdbTransaction* trans = ndb->startTransaction(); CHECK(trans != NULL); NdbScanOperation* scan = trans->getNdbScanOperation(ctx->getTab()); CHECK(scan != NULL); CHECK(scan->readTuples(NdbScanOperation::LM_CommittedRead) == 0); NdbInterpretedCode code; CHECK(code.interpret_exit_last_row() == 0); CHECK(code.finalise() == 0); NdbRecAttr* rowCountRA = scan->getValue(NdbDictionary::Column::ROW_COUNT); CHECK(rowCountRA != NULL); CHECK(scan->setInterpretedCode(&code) == 0); CHECK(trans->execute(NoCommit) == 0); while (scan->nextResult() == 0) rowCountSum+= rowCountRA->u_32_value(); trans->close(); trans = ndb->startTransaction(); CHECK(trans != NULL); scan = trans->getNdbScanOperation(ctx->getTab()); CHECK(scan != NULL); CHECK(scan->readTuples(NdbScanOperation::LM_CommittedRead) == 0); rowCountRA = scan->getValue(NdbDictionary::Column::ROW_COUNT); CHECK(rowCountRA != NULL); CHECK(trans->execute(NoCommit) == 0); while (scan->nextResult() == 0) rowScanCount++; trans->close(); } while(0); if (result == NDBT_OK) { ndbout_c("Sum of fragment row counts : %u Number rows scanned : %u", rowCountSum, rowScanCount); if (rowCountSum != rowScanCount) { ndbout_c("MISMATCH"); result = NDBT_FAILED; } } return result; } enum ApiEventType { Insert, Update, Delete }; template class Vector; struct EventInfo { ApiEventType type; int id; Uint64 gci; }; template class Vector; int collectEvents(Ndb* ndb, HugoCalculator& calc, const NdbDictionary::Table& tab, Vector& receivedEvents, int idCol, int updateCol, Vector* beforeAttrs, Vector* afterAttrs) { int MaxTimeouts = 5; int MaxEmptyPollsAfterData = 10; bool some_event_data_received = false; while (true) { NdbEventOperation* pOp = NULL; int res = ndb->pollEvents(1000); if (res <= 0) { if (--MaxTimeouts == 0) break; } else { assert(res == 1); pOp = ndb->nextEvent(); if (!pOp) { /* pollEvents returning 1 and nextEvent returning 0 means * empty epochs found in the event queue. After we receive * some event data, we wait some empty epoch poll rounds * to make sure that no more event data arrives. */ if (some_event_data_received && --MaxEmptyPollsAfterData == 0) break; } } { while (pOp) { bool isDelete = (pOp->getEventType() == NdbDictionary::Event::TE_DELETE); Vector* whichVersion = isDelete? beforeAttrs : afterAttrs; int id = (*whichVersion)[idCol]->u_32_value(); Uint64 gci = pOp->getGCI(); Uint32 anyValue = pOp->getAnyValue(); Uint32 scenario = ((anyValue >> 24) & 0xff) -1; Uint32 optype = ((anyValue >> 16) & 0xff); Uint32 recNum = (anyValue & 0xffff); g_err << "# " << receivedEvents.size() << " GCI : " << (gci >> 32) << "/" << (gci & 0xffffffff) << " id : " << id << " scenario : " << scenario << " optype : " << optype << " record : " << recNum << " "; /* Check event has self-consistent data */ int updatesValue = (*whichVersion)[updateCol]->u_32_value(); if ((*whichVersion)[updateCol]->isNULL() || (*whichVersion)[idCol]->isNULL()) { g_err << "Null update/id cols : REFRESH of !EXISTS "; } g_err << "(Updates val = " << updatesValue << ")"; for (int i=0; i < (int) whichVersion->size(); i++) { /* Check PK columns and also other columns for non-delete */ if (!isDelete || tab.getColumn(i)->getPrimaryKey()) { NdbRecAttr* ra = (*whichVersion)[i]; if (calc.verifyRecAttr(recNum, updatesValue, ra) != 0) { g_err << "Verify failed on recNum : " << recNum << " with updates value " << updatesValue << " for column " << ra->getColumn()->getAttrId() << endl; return NDBT_FAILED; } } } EventInfo ei; switch (pOp->getEventType()) { case NdbDictionary::Event::TE_INSERT: g_err << " Insert event" << endl; ei.type = Insert; break; case NdbDictionary::Event::TE_DELETE: ei.type = Delete; g_err << " Delete event" << endl; break; case NdbDictionary::Event::TE_UPDATE: ei.type = Update; g_err << " Update event" << endl; break; default: g_err << " Event type : " << pOp->getEventType() << endl; abort(); break; } ei.id = recNum; ei.gci = gci; receivedEvents.push_back(ei); some_event_data_received = true; pOp = ndb->nextEvent(); } } } return NDBT_OK; } int verifyEvents(const Vector& receivedEvents, const Vector& expectedEvents, int records) { /* Now verify received events against expected * This is messy as events occurring in the same epoch are unordered * except via id, so we use id-duplicates to determine which event * sequence we're looking at. */ g_err << "Received total of " << receivedEvents.size() << " events" << endl; Vector keys; Vector gcis; Uint32 z = 0; Uint64 z2 = 0; keys.fill(records, z); gcis.fill(records, z2); Uint64 currGci = 0; for (Uint32 e=0; e < receivedEvents.size(); e++) { EventInfo ei = receivedEvents[e]; if (ei.gci != currGci) { if (ei.gci < currGci) abort(); /* Epoch boundary */ /* At this point, all id counts must be equal */ for (int i=0; i < records; i++) { if (keys[i] != keys[0]) { g_err << "Count for id " << i << " is " << keys[i] << " but should be " << keys[0] << endl; return NDBT_OK; } } currGci = ei.gci; } Uint32 eventIndex = keys[ei.id]; keys[ei.id]++; ApiEventType et = expectedEvents[eventIndex]; if (ei.type != et) { g_err << "Expected event of type " << et << " but found " << ei.type << " at expectedEvent " << eventIndex << " and event num " << e << endl; return NDBT_FAILED; } } return NDBT_OK; } int runRefreshTuple(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); Ndb* ndb = GETNDB(step); /* Now attempt to create EventOperation */ NdbEventOperation* pOp; const NdbDictionary::Table& tab = *ctx->getTab(); char eventName[1024]; sprintf(eventName,"%s_EVENT",tab.getName()); pOp = ndb->createEventOperation(eventName); if (pOp == NULL) { g_err << "Failed to create event operation\n"; return NDBT_FAILED; } HugoCalculator calc(tab); Vector eventAfterRecAttr; Vector eventBeforeRecAttr; int updateCol = -1; int idCol = -1; /* Now request all attributes */ for (int a = 0; a < tab.getNoOfColumns(); a++) { eventAfterRecAttr.push_back(pOp->getValue(tab.getColumn(a)->getName())); eventBeforeRecAttr.push_back(pOp->getPreValue(tab.getColumn(a)->getName())); if (calc.isIdCol(a)) idCol = a; if (calc.isUpdateCol(a)) updateCol = a; } /* Now execute the event */ if (pOp->execute()) { g_err << "Event operation execution failed : " << pOp->getNdbError() << endl; return NDBT_FAILED; } HugoOperations hugoOps(*ctx->getTab()); int scenario = 0; Vector expectedEvents; for (scenario = 0; scenario < 2; scenario++) { g_err << "Scenario = " << scenario << " ( Refresh " << ((scenario == 0)? "before":"after") << " operations )" << endl; int optype = 0; bool done = false; int expectedError = 0; do { check(hugoOps.startTransaction(ndb) == 0, hugoOps); if (scenario == 0) { g_err << "Refresh before operations" << endl; int anyValue = ((1) << 8) | optype; check(hugoOps.pkRefreshRecord(ndb, 0, records, anyValue) == 0, hugoOps); } switch(optype) { case 0: { /* Refresh with no data present */ g_err << " Do nothing" << endl; expectedError = 0; /* Single refresh should always be fine */ expectedEvents.push_back(Delete); break; } case 1: { /* [Refresh] Insert [Refresh] */ g_err << " Insert" << endl; check(hugoOps.pkInsertRecord(ndb, 0, records, 1) == 0, hugoOps); if (scenario == 0) { /* Tuple already existed error when we insert after refresh */ expectedError = 630; expectedEvents.push_back(Delete); } else { expectedError = 0; expectedEvents.push_back(Insert); } /* Tuple already existed error when we insert after refresh */ break; } case 2: { /* Refresh */ g_err << " Refresh" << endl; if (scenario == 0) { expectedEvents.push_back(Delete); } else { expectedEvents.push_back(Insert); } expectedError = 0; break; } case 3: { /* [Refresh] Update [Refresh] */ g_err << " Update" << endl; check(hugoOps.pkUpdateRecord(ndb, 0, records, 3) == 0, hugoOps); if (scenario == 0) { expectedError = 920; expectedEvents.push_back(Delete); } else { expectedError = 0; expectedEvents.push_back(Insert); } break; } case 4: { /* [Refresh] Delete [Refresh] */ g_err << " [Refresh] Delete [Refresh]" << endl; if (scenario == 0) { expectedError = 920; expectedEvents.push_back(Delete); } else { expectedError = 0; expectedEvents.push_back(Delete); } check(hugoOps.pkDeleteRecord(ndb, 0, records) == 0, hugoOps); break; } case 5: { g_err << " Refresh" << endl; expectedError = 0; expectedEvents.push_back(Delete); /* Refresh with no data present */ break; } case 6: { g_err << " Double refresh" << endl; int anyValue = ((2) << 8) | optype; check(hugoOps.pkRefreshRecord(ndb, 0, records, anyValue) == 0, hugoOps); expectedError = 920; /* Row operation defined after refreshTuple() */ expectedEvents.push_back(Delete); } default: done = true; break; } if (scenario == 1) { g_err << "Refresh after operations" << endl; int anyValue = ((4) << 8) | optype; check(hugoOps.pkRefreshRecord(ndb, 0, records, anyValue) == 0, hugoOps); } int rc = hugoOps.execute_Commit(ndb, AO_IgnoreError); check(rc == expectedError, hugoOps); check(hugoOps.closeTransaction(ndb) == 0, hugoOps); optype++; /* Now check fragment counts vs findable row counts */ if (runVerifyRowCount(ctx, step) != NDBT_OK) return NDBT_FAILED; } while (!done); } // for scenario... /* Now check fragment counts vs findable row counts */ if (runVerifyRowCount(ctx, step) != NDBT_OK) return NDBT_FAILED; /* Now let's dump and check the events */ g_err << "Expecting the following sequence..." << endl; for (Uint32 i=0; i < expectedEvents.size(); i++) { g_err << i << ". "; switch(expectedEvents[i]) { case Insert: g_err << "Insert" << endl; break; case Update: g_err << "Update" << endl; break; case Delete: g_err << "Delete" << endl; break; default: abort(); } } Vector receivedEvents; int rc = collectEvents(ndb, calc, tab, receivedEvents, idCol, updateCol, &eventBeforeRecAttr, &eventAfterRecAttr); if (rc == NDBT_OK) { rc = verifyEvents(receivedEvents, expectedEvents, records); } if (ndb->dropEventOperation(pOp) != 0) { g_err << "Drop Event Operation failed : " << ndb->getNdbError() << endl; return NDBT_FAILED; } return rc; }; // Regression test for bug #14208924 static int runLeakApiConnectObjects(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter restarter; /** * This error insert inc ombination with bug #14208924 will * cause TC to leak ApiConnectRecord objects. */ restarter.insertErrorInAllNodes(8094); Ndb* const ndb = GETNDB(step); Uint32 maxTrans = 0; NdbConfig conf; require(conf.getProperty(conf.getMasterNodeId(), NODE_TYPE_DB, CFG_DB_NO_TRANSACTIONS, &maxTrans)); require(maxTrans > 0); HugoOperations hugoOps(*ctx->getTab()); // One ApiConnectRecord object is leaked for each iteration. for (uint i = 0; i < maxTrans+1; i++) { require(hugoOps.startTransaction(ndb) == 0); require(hugoOps.pkInsertRecord(ndb, i) == 0); NdbTransaction* const trans = hugoOps.getTransaction(); /** * The error insert causes trans->execute(Commit) to fail with error code * 286 even if the bug is fixed. Therefore, we ignore this error code. */ if (trans->execute(Commit) != 0 && trans->getNdbError().code != 286) { g_err << "trans->execute() gave unexpected error : " << trans->getNdbError() << endl; restarter.insertErrorInAllNodes(0); return NDBT_FAILED; } require(hugoOps.closeTransaction(ndb) == 0); } restarter.insertErrorInAllNodes(0); UtilTransactions utilTrans(*ctx->getTab()); if (utilTrans.clearTable(ndb) != 0){ return NDBT_FAILED; } return NDBT_OK; } enum PreRefreshOps { PR_NONE, PR_INSERT, PR_INSERTDELETE, PR_DELETE }; struct RefreshScenario { const char* name; bool preExist; PreRefreshOps preRefreshOps; }; static RefreshScenario refreshTests[] = { { "No row, No pre-ops", false, PR_NONE }, { "No row, Insert pre-op", false, PR_INSERT }, { "No row, Insert-Del pre-op", false, PR_INSERTDELETE }, { "Row exists, No pre-ops", true, PR_NONE }, { "Row exists, Delete pre-op", true, PR_DELETE } }; enum OpTypes { OP_READ_C, OP_READ_S, OP_READ_E, OP_INSERT, OP_UPDATE, OP_WRITE, OP_DELETE, OP_LAST }; const char* opTypeNames[] = { "READ_C", "READ_S", "READ_E", "INSERT", "UPDATE", "WRITE", "DELETE" }; int runRefreshLocking(NDBT_Context* ctx, NDBT_Step* step) { /* Check that refresh in various situations has the * locks we expect it to * Scenario combinations : * Now row pre-existing | Row pre-existing * Trans1 : Refresh | Insert-Refresh | Insert-Delete-Refresh * Delete-Refresh * Trans2 : Read [Committed|Shared|Exclusive] | Insert | Update * Write | Delete * * Expectations : Read committed always non-blocking * Read committed sees pre-existing row * All other trans2 operations deadlock */ Ndb* ndb = GETNDB(step); Uint32 numScenarios = sizeof(refreshTests) / sizeof(refreshTests[0]); HugoTransactions hugoTrans(*ctx->getTab()); for (Uint32 s = 0; s < numScenarios; s++) { RefreshScenario& scenario = refreshTests[s]; if (scenario.preExist) { /* Create pre-existing tuple */ if (hugoTrans.loadTable(ndb, 1) != 0) { g_err << "Pre-exist failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } } if (hugoTrans.startTransaction(ndb) != 0) { g_err << "Start trans failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } g_err << "Scenario : " << scenario.name << endl; /* Do pre-refresh ops */ switch (scenario.preRefreshOps) { case PR_NONE: break; case PR_INSERT: case PR_INSERTDELETE: if (hugoTrans.pkInsertRecord(ndb, 0) != 0) { g_err << "Pre insert failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } if (scenario.preRefreshOps == PR_INSERT) break; case PR_DELETE: if (hugoTrans.pkDeleteRecord(ndb, 0) != 0) { g_err << "Pre delete failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } break; } /* Then refresh */ if (hugoTrans.pkRefreshRecord(ndb, 0) != 0) { g_err << "Refresh failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } /* Now execute */ if (hugoTrans.execute_NoCommit(ndb) != 0) { g_err << "Execute failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } { /* Now try ops from another transaction */ HugoOperations hugoOps(*ctx->getTab()); Uint32 ot = OP_READ_C; while (ot < OP_LAST) { if (hugoOps.startTransaction(ndb) != 0) { g_err << "Start trans2 failed : " << hugoOps.getNdbError() << endl; return NDBT_FAILED; } g_err << "Operation type : " << opTypeNames[ot] << endl; int res = 0; switch (ot) { case OP_READ_C: res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_CommittedRead); break; case OP_READ_S: res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_Read); break; case OP_READ_E: res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_Exclusive); break; case OP_INSERT: res = hugoOps.pkInsertRecord(ndb, 0); break; case OP_UPDATE: res = hugoOps.pkUpdateRecord(ndb, 0); break; case OP_WRITE: res = hugoOps.pkWriteRecord(ndb, 0); break; case OP_DELETE: res = hugoOps.pkDeleteRecord(ndb, 0); break; case OP_LAST: abort(); } hugoOps.execute_Commit(ndb); if ((ot == OP_READ_C) && (scenario.preExist)) { if (hugoOps.getNdbError().code == 0) { g_err << "Read committed succeeded" << endl; } else { g_err << "UNEXPECTED : Read committed failed. " << hugoOps.getNdbError() << endl; return NDBT_FAILED; } } else { if (hugoOps.getNdbError().code == 0) { g_err << opTypeNames[ot] << " succeeded, should not have" << endl; return NDBT_FAILED; } } hugoOps.closeTransaction(ndb); ot = ot + 1; } } /* Close refresh transaction */ hugoTrans.closeTransaction(ndb); if (scenario.preExist) { /* Cleanup pre-existing before next iteration */ if (hugoTrans.pkDelRecords(ndb, 0) != 0) { g_err << "Delete pre existing failed : " << hugoTrans.getNdbError() << endl; return NDBT_FAILED; } } } return NDBT_OK; } int runBugXXX_init(NDBT_Context* ctx, NDBT_Step* step) { return NDBT_OK; } int runBugXXX_trans(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter res; while (!ctx->isTestStopped()) { runLoadTable(ctx, step); ctx->getPropertyWait("CREATE_INDEX", 1); ctx->setProperty("CREATE_INDEX", Uint32(0)); res.insertErrorInAllNodes(8105); // randomly abort trigger ops with 218 runClearTable2(ctx, step); res.insertErrorInAllNodes(0); } return NDBT_OK; } int runBugXXX_createIndex(NDBT_Context* ctx, NDBT_Step* step) { NdbRestarter res; const int loops = ctx->getNumLoops(); Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* pTab = ctx->getTab(); BaseString name; name.assfmt("%s_PK_IDX", pTab->getName()); NdbDictionary::Index pIdx(name.c_str()); pIdx.setTable(pTab->getName()); pIdx.setType(NdbDictionary::Index::UniqueHashIndex); for (int c = 0; c < pTab->getNoOfColumns(); c++) { const NdbDictionary::Column * col = pTab->getColumn(c); if(col->getPrimaryKey()) { pIdx.addIndexColumn(col->getName()); } } pIdx.setStoredIndex(false); for (int i = 0; i < loops; i++) { res.insertErrorInAllNodes(18000); ctx->setProperty("CREATE_INDEX", 1); pNdb->getDictionary()->createIndex(pIdx); pNdb->getDictionary()->dropIndex(name.c_str(), pTab->getName()); } ctx->stopTest(); return NDBT_OK; } int runBug16834333(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); NdbDictionary::Dictionary* pDic = pNdb->getDictionary(); const int records = ctx->getNumRecords(); NdbRestarter restarter; int result = NDBT_OK; do { /* * Drop the pre-created table before initial restart to avoid invalid * dict cache. One symptom would be running the test twice and getting * abort() in final dict cache release due to non-existent version. * Also use a copy of the pre-created table struct to avoid accessing * invalid memory. */ const NdbDictionary::Table tab(* ctx->getTab()); CHK2(pDic->dropTable(tab.getName()) == 0, pDic->getNdbError()); ndbout_c("restart initial"); restarter.restartAll(true, /* initial */ true, /* nostart */ true /* abort */ ); ndbout_c("wait nostart"); restarter.waitClusterNoStart(); ndbout_c("startAll"); restarter.startAll(); ndbout_c("wait started"); restarter.waitClusterStarted(); ndbout_c("create tab"); CHK2(pDic->createTable(tab) == 0, pDic->getNdbError()); const NdbDictionary::Table* pTab = pDic->getTable(tab.getName()); CHK2(pTab != 0, pDic->getNdbError()); ndbout_c("load table"); HugoTransactions trans(* pTab); CHK2(trans.loadTable(pNdb, records) == 0, trans.getNdbError()); int codes[] = { 5080, 5081 }; for (int i = 0, j = 0; i < restarter.getNumDbNodes(); i++, j++) { int code = codes[j % NDB_ARRAY_SIZE(codes)]; int nodeId = restarter.getDbNodeId(i); ndbout_c("error %d node: %d", code, nodeId); restarter.insertErrorInNode(nodeId, code); } ndbout_c("running big trans"); HugoOperations ops(* pTab); CHK2(ops.startTransaction(pNdb) == 0, ops.getNdbError()); CHK2(ops.pkReadRecord(0, 16384) == 0, ops.getNdbError()); if (ops.execute_Commit(pNdb, AO_IgnoreError) != 0) { // XXX should this occur if AO_IgnoreError ? CHK2(ops.getNdbError().code == 1223, ops.getNdbError()); g_info << ops.getNdbError() << endl; } ops.closeTransaction(pNdb); } while (0); restarter.insertErrorInAllNodes(0); return result; } // bug#19031389 int runAccCommitOrder(NDBT_Context* ctx, NDBT_Step* step) { Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* pTab = ctx->getTab(); const int loops = ctx->getNumLoops(); const int records = ctx->getNumRecords(); require(records > 0); const int opsteps = ctx->getProperty("OPSTEPS"); int result = NDBT_OK; for (int loop = 0; loop < loops; loop++) { g_info << "loop " << loop << endl; { g_info << "load table" << endl; HugoTransactions trans(*pTab); CHK2(trans.loadTable(pNdb, records) == 0, trans.getNdbError()); } g_info << "start op steps" << endl; require(ctx->getProperty("RUNNING", (Uint32)opsteps) == 0); ctx->setProperty("RUN", (Uint32)1); if (ctx->getPropertyWait("RUNNING", (Uint32)opsteps)) break; g_info << "all op steps running" << endl; int mssleep = 10 + ndb_rand() % records; if (mssleep > 1000) mssleep = 1000; NdbSleep_MilliSleep(mssleep); g_info << "stop op steps" << endl; require(ctx->getProperty("RUNNING", (Uint32)0) == (Uint32)opsteps); ctx->setProperty("RUN", (Uint32)0); if (ctx->getPropertyWait("RUNNING", (Uint32)0)) break; g_info << "all op steps stopped" << endl; { g_info << "clear table" << endl; UtilTransactions trans(*pTab); CHK1(trans.clearTable(pNdb, records) == 0); } } g_info << "stop test" << endl; ctx->stopTest(); return result; } int runAccCommitOrderOps(NDBT_Context* ctx, NDBT_Step* step) { const int stepNo = step->getStepNo(); Ndb* pNdb = GETNDB(step); const NdbDictionary::Table* pTab = ctx->getTab(); const int records = ctx->getNumRecords(); int result = NDBT_OK; unsigned seed = (unsigned)(getpid() ^ stepNo); ndb_srand(seed); int loop = 0; while (!ctx->isTestStopped()) { if (ctx->getPropertyWait("RUN", (Uint32)1)) break; g_info << "step " << stepNo << ": loop " << loop << endl; ctx->incProperty("RUNNING"); g_info << "step " << stepNo << ": running" << endl; int opscount = 0; int n = 0; // steps should hit about same records while (ctx->getProperty("RUN", (Uint32)0) == (Uint32)1) { HugoOperations ops(*pTab); ops.setQuiet(); CHK2(ops.startTransaction(pNdb) == 0, ops.getNdbError()); const int numreads = 2 + ndb_rand_r(&seed) % 3; for (int i = 0; i < numreads; i++) { NdbOperation::LockMode lm = NdbOperation::LM_Read; CHK2(ops.pkReadRecord(pNdb, n, 1, lm) == 0, ops.getNdbError()); opscount++; } CHK1(result == NDBT_OK); CHK2(ops.pkDeleteRecord(pNdb, n, 1) == 0, ops.getNdbError()); CHK2(ops.execute_Commit(pNdb) == 0 || ops.getNdbError().code == 626 || ( ops.getNdbError().status == NdbError::TemporaryError && ops.getNdbError().classification != NdbError::NodeRecoveryError ), ops.getNdbError()); ops.closeTransaction(pNdb); n = (n + 1) % records; } CHK1(result == NDBT_OK); g_info << "step " << stepNo << ": ops count " << opscount << endl; ctx->decProperty("RUNNING"); g_info << "step " << stepNo << ": stopped" << endl; loop++; } ctx->stopTest(); return result; } /** * TESTCASE DeleteNdbWhilePoll: Delete an Ndb object while it(trp_clnt) * is in poll q. * runInsertOneTuple : inserts one tuple in table. * runLockTuple : A thread runs transaction 1 (Txn1) which locks the * tuple with exclusive lock and signals another thread running * transaction 2 (Txn2). * runReadLockedTuple : Txn2 issues an exclusive read of the tuple * locked by Txn1 (and waits for lock), and signals the delete thread. * deleteNdbWhileWaiting : deletes the ndb object used by Txn2. * Tx1 commits and Tx2 commits and provokes consequences from deleted Ndb. * * The most probable consequence, is : * TransporterFacade.cpp:1674: require((clnt->m_poll.m_locked == true)) failed */ // Candidate for deleteNdbWhileWaiting(). static Ndb* ndbToDelete = NULL; int runInsertOneTuple(NDBT_Context *ctx, NDBT_Step* step) { int result = NDBT_OK; const NdbDictionary::Table *table= ctx->getTab(); HugoOperations hugoOp1(*table); Ndb* pNdb = GETNDB(step); CHECK2(hugoOp1.startTransaction(pNdb) == 0); CHECK2(hugoOp1.pkInsertRecord(pNdb, 1, 1) == 0); CHECK2(hugoOp1.execute_Commit(pNdb) == 0); CHECK2(hugoOp1.closeTransaction(pNdb) == 0); g_info << "Rec inserted, ndb " << pNdb <getTab(); HugoOperations hugoOp1(*table); Ndb* pNdb = GETNDB(step); CHECK2(hugoOp1.startTransaction(pNdb) == 0); // read the inserted tuple (Txn1). CHECK2(hugoOp1.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK2(hugoOp1.execute_NoCommit(pNdb) == 0); g_info << "Txn1 readlocked tuple, ndb "<setProperty("Txn1-LockedTuple", 1); // Wait until ndb of Txn2 is deleted by deleteNdbWhileWaiting(). while(ctx->getProperty("NdbDeleted", (Uint32)0) == 0 && !ctx->isTestStopped()){ NdbSleep_MilliSleep(20); } // Now commit Txn1. /* Intention is when this commits, Txn1's trp_clnt will relinquish the * poll rights it had to trp_clnt to Txn2, which is deleted. * However this is not determisnistic. Sometimes, the poll right * is owned by Txn2's trp_clnt, causing test to assert-fail in do_poll. */ g_info << "Txn1 commits, ndb " << pNdb << endl; if (!ctx->isTestStopped()) CHECK2(hugoOp1.execute_Commit(pNdb) == 0); g_info << "Txn1 commited, ndb " << pNdb << endl; if (!ctx->isTestStopped()) CHECK2(hugoOp1.closeTransaction(pNdb) == 0); return result; } // Read the tuple locked by Txn1, see runLockTuple(). int runReadLockedTuple(NDBT_Context *ctx, NDBT_Step* step) { int result = NDBT_OK; const NdbDictionary::Table *table= ctx->getTab(); HugoOperations hugoOp2(*table); Ndb* pNdb = GETNDB(step); // Wait until the tuple is locked by Txn1 while(ctx->getProperty("Txn1-LockedTuple", (Uint32)0) == 0 && !ctx->isTestStopped()){ NdbSleep_MilliSleep(20); } CHECK2(hugoOp2.startTransaction(pNdb) == 0); // Txn2 reads the locked tuple. CHECK2(hugoOp2.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); // Flag deleteNdbWhileWaiting() to delete my ndb object ndbToDelete = pNdb; // candidate for deleteNdbWhileWaiting() ctx->setProperty("Txn2-SendCommit", 1); // Now commit Txn2 g_info << "Txn2 commits, ndb " << pNdb << ", Ndb to delete " << ndbToDelete << endl << endl; CHECK2(hugoOp2.execute_Commit(pNdb) == 0); CHECK2(hugoOp2.closeTransaction(pNdb) == 0); ctx->stopTest(); return result; } // Delete ndb of Txn2. int deleteNdbWhileWaiting(NDBT_Context* ctx, NDBT_Step* step) { // Wait until Txn2 sends the read of the locked tuple. while(ctx->getProperty("Txn2-SendCommit", (Uint32)0) == 0 && !ctx->isTestStopped()){ g_info << "|- Waiting for read" << endl; NdbSleep_MilliSleep(20); } // Delete ndb of Txn2 while it is waiting in the poll queue. g_info << "deleteNdbWhileWaiting deletes ndb " << ndbToDelete << endl << endl; delete ndbToDelete; // Signal Txn1 to commit ctx->setProperty("NdbDeleted", 1); return NDBT_OK; } /******* end TESTCASE DeleteNdbWhilePoll*******/ NDBT_TESTSUITE(testBasic); TESTCASE("PkInsert", "Verify that we can insert and delete from this table using PK" "NOTE! No errors are allowed!" ){ INITIALIZER(runInsert); VERIFIER(runVerifyInsert); } TESTCASE("PkRead", "Verify that we can insert, read and delete from this table using PK"){ TC_PROPERTY("LockMode", NdbOperation::LM_Read); INITIALIZER(runLoadTable); STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("PkDirtyRead", "Verify that we can insert, dirty read and delete from this table using PK"){ TC_PROPERTY("LockMode", NdbOperation::LM_Dirty); INITIALIZER(runLoadTable); STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("PkSimpleRead", "Verify that we can insert, simple read and delete from this table using PK"){ TC_PROPERTY("LockMode", NdbOperation::LM_SimpleRead); INITIALIZER(runLoadTable); STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("PkUpdate", "Verify that we can insert, update and delete from this table using PK"){ INITIALIZER(runLoadTable); STEP(runPkUpdate); FINALIZER(runClearTable); } TESTCASE("PkDelete", "Verify that we can delete from this table using PK"){ INITIALIZER(runLoadTable); STEP(runPkDelete); FINALIZER(runClearTable); } TESTCASE("UpdateAndRead", "Verify that we can read and update at the same time"){ INITIALIZER(runLoadTable); STEP(runPkRead); STEP(runPkRead); STEP(runPkRead); STEP(runPkUpdate); STEP(runPkUpdate); STEP(runPkUpdate); FINALIZER(runClearTable); } TESTCASE("PkReadAndLocker", "Verify that we can read although there are "\ " a number of 1 second locks in the table"){ INITIALIZER(runLoadTable); STEP(runPkReadUntilStopped); STEP(runLocker); FINALIZER(runClearTable); } TESTCASE("PkReadAndLocker2", "Verify that we can read and update although there are "\ " a number of 1 second locks in the table"){ INITIALIZER(runLoadTable); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runLocker); FINALIZER(runClearTable); } TESTCASE("PkReadUpdateAndLocker", "Verify that we can read and update although there are "\ " a number of 1 second locks in the table"){ INITIALIZER(runLoadTable); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkUpdateUntilStopped); STEP(runPkUpdateUntilStopped); STEP(runLocker); FINALIZER(runClearTable); } TESTCASE("ReadWithLocksAndInserts", "TR457: This test is added to verify that an insert of a records "\ "that is already in the database does not delete the record"){ INITIALIZER(runLoadTable); STEP(runPkReadUntilStopped); STEP(runPkReadUntilStopped); STEP(runLocker); STEP(runInsertUntilStopped); FINALIZER(runClearTable); } TESTCASE("PkInsertTwice", "Verify that we can't insert an already inserted record." "Error should be returned" ){ INITIALIZER(runLoadTable); STEP(runInsertTwice); FINALIZER(runClearTable); } TESTCASE("NoCommitSleep", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the application is sleeping" ){ INITIALIZER(runLoadTable); INITIALIZER(runNoCommitSleep); FINALIZER(runClearTable2); } TESTCASE("Commit626", "Verify what happens when a Commit transaction is aborted by " "NDB because the record does no exist" ){ INITIALIZER(runClearTable2); INITIALIZER(runCommit626); FINALIZER(runClearTable2); } TESTCASE("CommitTry626", "Verify what happens when a Commit(TryCommit) \n" "transaction is aborted by " "NDB because the record does no exist" ){ INITIALIZER(runClearTable2); INITIALIZER(runCommit_TryCommit626); FINALIZER(runClearTable2); } TESTCASE("CommitAsMuch626", "Verify what happens when a Commit(CommitAsMuchAsPossible) \n" "transaction is aborted by\n" "NDB because the record does no exist" ){ INITIALIZER(runClearTable2); INITIALIZER(runCommit_CommitAsMuchAsPossible626); FINALIZER(runClearTable2); } TESTCASE("NoCommit626", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the record does no exist" ){ INITIALIZER(runClearTable2); INITIALIZER(runNoCommit626); FINALIZER(runClearTable2); } TESTCASE("NoCommitRollback626", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the record does no exist and then we try to rollback\n" "the transaction" ){ INITIALIZER(runClearTable2); INITIALIZER(runNoCommitRollback626); FINALIZER(runClearTable2); } TESTCASE("Commit630", "Verify what happens when a Commit transaction is aborted by " "NDB because the record already exist" ){ INITIALIZER(runLoadTable); INITIALIZER(runCommit630); FINALIZER(runClearTable2); } TESTCASE("CommitTry630", "Verify what happens when a Commit(TryCommit) \n" "transaction is aborted by " "NDB because the record already exist" ){ INITIALIZER(runLoadTable); INITIALIZER(runCommit_TryCommit630); FINALIZER(runClearTable2); } TESTCASE("CommitAsMuch630", "Verify what happens when a Commit(CommitAsMuchAsPossible) \n" "transaction is aborted by\n" "NDB because the record already exist" ){ INITIALIZER(runLoadTable); INITIALIZER(runCommit_CommitAsMuchAsPossible630); FINALIZER(runClearTable2); } TESTCASE("NoCommit630", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the record already exist" ){ INITIALIZER(runLoadTable); INITIALIZER(runNoCommit630); FINALIZER(runClearTable2); } TESTCASE("NoCommitRollback630", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the record already exist and then we try to rollback\n" "the transaction" ){ INITIALIZER(runLoadTable); INITIALIZER(runNoCommitRollback630); FINALIZER(runClearTable2); } TESTCASE("NoCommitAndClose", "Verify what happens when a NoCommit transaction is closed " "without rolling back the transaction " ){ INITIALIZER(runLoadTable); INITIALIZER(runNoCommitAndClose); FINALIZER(runClearTable2); } TESTCASE("RollbackDelete", "Test rollback of a no committed delete"){ INITIALIZER(runLoadTable); INITIALIZER(runCheckRollbackDelete); FINALIZER(runClearTable2); } TESTCASE("RollbackUpdate", "Test rollback of a no committed update"){ INITIALIZER(runLoadTable); INITIALIZER(runCheckRollbackUpdate); FINALIZER(runClearTable2); } TESTCASE("RollbackDeleteMultiple", "Test rollback of 10 non committed delete"){ INITIALIZER(runLoadTable); INITIALIZER(runCheckRollbackDeleteMultiple); FINALIZER(runClearTable2); } TESTCASE("ImplicitRollbackDelete", "Test close transaction after a no commited delete\n" "this would give an implicit rollback of the delete\n"){ INITIALIZER(runLoadTable); INITIALIZER(runCheckImplicitRollbackDelete); FINALIZER(runClearTable2); } TESTCASE("CommitDelete", "Test close transaction after a no commited delete\n" "this would give an implicit rollback of the delete\n"){ INITIALIZER(runLoadTable); INITIALIZER(runCheckCommitDelete); FINALIZER(runClearTable2); } TESTCASE("RollbackNothing", "Test rollback of nothing"){ INITIALIZER(runLoadTable); INITIALIZER(runRollbackNothing); FINALIZER(runClearTable2); } TESTCASE("MassiveRollback", "Test rollback of 4096 operations"){ INITIALIZER(runClearTable2); INITIALIZER(runMassiveRollback); FINALIZER(runClearTable2); } TESTCASE("MassiveRollback2", "Test rollback of 4096 operations"){ INITIALIZER(runClearTable2); INITIALIZER(runMassiveRollback2); FINALIZER(runClearTable2); } TESTCASE("MassiveRollback3", "Test rollback of 4096 operations"){ INITIALIZER(runClearTable2); STEP(runMassiveRollback3); STEP(runMassiveRollback3); FINALIZER(runClearTable2); } TESTCASE("MassiveRollback4", "Test rollback of 4096 operations"){ INITIALIZER(runClearTable2); STEP(runMassiveRollback4); STEP(runMassiveRollback4); FINALIZER(runClearTable2); } TESTCASE("MassiveTransaction", "Test very large insert transaction"){ INITIALIZER(runLoadTable2); FINALIZER(runClearTable2); } TESTCASE("TupError", "Verify what happens when we fill the db" ){ INITIALIZER(runTupErrors); } TESTCASE("InsertError", "" ){ INITIALIZER(runInsertError); } TESTCASE("InsertError2", "" ){ INITIALIZER(runInsertError2); } TESTCASE("Fill", "Verify what happens when we fill the db" ){ STEP(runFillTable); } TESTCASE("Bug25090", "Verify what happens when we fill the db" ){ STEP(runBug25090); } TESTCASE("DeleteRead", "Verify Delete+Read" ){ INITIALIZER(runLoadTable); INITIALIZER(runDeleteRead); FINALIZER(runClearTable2); } TESTCASE("Bug27756", "Verify what happens when we fill the db" ){ STEP(runBug27756); } TESTCASE("Bug28073", "Infinite loop in lock queue" ){ STEP(runBug28073); } TESTCASE("Bug20535", "Verify what happens when we fill the db" ){ STEP(runBug20535); } TESTCASE("DDInsertFailUpdateBatch", "Verify DD insert failure effect on other ops in batch on same PK"){ STEP(runDDInsertFailUpdateBatch); } TESTCASE("Bug34348", "Test fragment directory range full in ACC.\n" "NOTE: If interrupted, must clear error insert 3002 manually"){ STEP(runBug34348); } TESTCASE("UnlockBatch", "Test that batched unlock operations work ok"){ TC_PROPERTY("Batchsize", 33); INITIALIZER(runLoadTable); STEP(runUnlocker); FINALIZER(runClearTable); } TESTCASE("DoubleUnlock", "Test that batched unlock operations work ok"){ TC_PROPERTY("DoubleUnlock", 1); INITIALIZER(runLoadTable); STEP(runUnlocker); FINALIZER(runClearTable); } TESTCASE("UnlockUpdateBatch", "Test Unlock mixed with Update"){ TC_PROPERTY("Batchsize", 32); INITIALIZER(runLoadTable); STEP(runUnlocker); STEP(runUnlocker); STEP(runLocker); STEP(runPkUpdate); STEP(runPkUpdate); STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("RefreshTuple", "Test refreshTuple() operation properties"){ INITIALIZER(initSubscription); INITIALIZER(runRefreshTuple); FINALIZER(removeSubscription); } TESTCASE("Bug54986", "") { INITIALIZER(runBug54986); } TESTCASE("Bug54944", "") { TC_PROPERTY("DATABUFFER", (Uint32)0); INITIALIZER(runBug54944); } TESTCASE("Bug54944DATABUFFER", "") { TC_PROPERTY("DATABUFFER", (Uint32)1); INITIALIZER(runBug54944); } TESTCASE("Bug59496_case1", "") { STEP(runBug59496_case1); STEPS(runBug59496_scan, 10); } TESTCASE("Bug59496_case2", "") { TC_PROPERTY("CHECK_ROWCOUNT", 1); INITIALIZER(runLoadTable); STEP(runBug59496_case2); STEPS(runBug59496_scan, 10); } TESTCASE("899", "") { INITIALIZER(runLoadTable); INITIALIZER(runInit899); STEP(runTest899); FINALIZER(runEnd899); } TESTCASE("LeakApiConnectObjects", "") { INITIALIZER(runLeakApiConnectObjects); } TESTCASE("RefreshLocking", "Test Refresh locking properties") { INITIALIZER(runRefreshLocking); } TESTCASE("BugXXX","") { INITIALIZER(runBugXXX_init); STEP(runBugXXX_createIndex); STEP(runBugXXX_trans); } TESTCASE("Bug16834333","") { INITIALIZER(runBug16834333); } TESTCASE("FillQueueREDOLog", "Verify that we can handle a REDO log queue situation") { INITIALIZER(insertError5083); STEP(runLoadTableFail); FINALIZER(clearError5083); } TESTCASE("AccCommitOrder", "Bug19031389. MT kernel crash on deleted tuple in read*-delete.") { TC_PROPERTY("OPSTEPS", (Uint32)2); TC_PROPERTY("RUN", (Uint32)0); TC_PROPERTY("RUNNING", (Uint32)0); STEP(runAccCommitOrder); STEPS(runAccCommitOrderOps, 2); } TESTCASE("DeleteNdbWhilePoll", "Delete an Ndb while it(trp_clnt) is in poll queue. Will crash the test, and thus not to be run in a regular test" ){ INITIALIZER(runInsertOneTuple); STEP(runLockTuple); STEP(runReadLockedTuple); STEP(deleteNdbWhileWaiting); FINALIZER(runClearTable2); } NDBT_TESTSUITE_END(testBasic); #if 0 TESTCASE("ReadConsistency", "Check that a read within a transaction returns the " \ "same result no matter"){ STEP(runInsertOne); STEP(runReadOne); FINALIZER(runClearTable2); } TESTCASE("Fill", "Verify what happens when we fill the db" ){ INITIALIZER(runFillTable); INITIALIZER(runPkRead); FINALIZER(runClearTable2); } #endif int main(int argc, const char** argv){ ndb_init(); NDBT_TESTSUITE_INSTANCE(testBasic); return testBasic.execute(argc, argv); }