int HugoOperations::pkReadRecordLockHandle(Ndb* pNdb, Vector<const NdbLockHandle*>& lockHandles, int recordNo, int numRecords, NdbOperation::LockMode lm, NdbOperation::LockMode *lmused){ if (idx) { g_err << "ERROR : Cannot call pkReadRecordLockHandle on an index" << endl; return NDBT_FAILED; } /* If something other than LM_Read or LM_Exclusive is * passed in then we'll choose, and PkReadRecord * will update lm_used */ while (lm != NdbOperation::LM_Read && lm != NdbOperation::LM_Exclusive) { lm = (NdbOperation::LockMode)((rand() >> 16) & 1); } const NdbOperation* prevOp = pTrans->getLastDefinedOperation(); int readRc = pkReadRecord(pNdb, recordNo, numRecords, lm, lmused); if (readRc == NDBT_OK) { /* Now traverse operations added, requesting * LockHandles */ const NdbOperation* definedOp = (prevOp)? prevOp->next() : pTrans->getFirstDefinedOperation(); while (definedOp) { /* Look away now */ const NdbLockHandle* lh = (const_cast<NdbOperation*>(definedOp))->getLockHandle(); if (lh == NULL) { ERR(definedOp->getNdbError()); setNdbError(definedOp->getNdbError()); return NDBT_FAILED; } lockHandles.push_back(lh); definedOp = definedOp->next(); } } return readRc; }
int HugoTransactions::pkUpdateRecords(Ndb* pNdb, int records, int batch, int doSleep){ int updated = 0; int r = 0; int retryAttempt = 0; int check, b; allocRows(batch); g_info << "|- Updating records (batch=" << batch << ")..." << endl; int batch_no = 0; while (r < records){ if(r + batch > records) batch = records - r; if (m_thr_count != 0 && m_thr_no != batch_no % m_thr_count) { r += batch; batch_no++; continue; } if (retryAttempt >= m_retryMax){ g_info << "ERROR: has retried this operation " << retryAttempt << " times, failing!" << endl; return NDBT_FAILED; } if (doSleep > 0) NdbSleep_MilliSleep(doSleep); pTrans = pNdb->startTransaction(); if (pTrans == NULL) { const NdbError err = pNdb->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); return NDBT_FAILED; } if(pkReadRecord(pNdb, r, batch, NdbOperation::LM_Exclusive) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } check = pTrans->execute(NoCommit, AbortOnError); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); closeTransaction(pNdb); return NDBT_FAILED; } MicroSecondTimer timer_start; MicroSecondTimer timer_stop; bool timer_active = m_stats_latency != 0 && r >= batch && // first batch is "warmup" r + batch != records; // last batch is usually partial if (timer_active) NdbTick_getMicroTimer(&timer_start); if(pIndexScanOp) { int rows_found = 0; while((check = pIndexScanOp->nextResult(true)) == 0) { do { if (calc.verifyRowValues(rows[0]) != 0){ closeTransaction(pNdb); return NDBT_FAILED; } int updates = calc.getUpdatesValue(rows[0]) + 1; if(pkUpdateRecord(pNdb, r+rows_found, 1, updates) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } rows_found++; } while((check = pIndexScanOp->nextResult(false)) == 0); if(check != 2) break; if((check = pTrans->execute(NoCommit, AbortOnError)) != 0) break; } if(check != 1 || rows_found != batch) { closeTransaction(pNdb); return NDBT_FAILED; } } else { for(b = 0; b<batch && (b+r)<records; b++) { if (calc.verifyRowValues(rows[b]) != 0) { closeTransaction(pNdb); return NDBT_FAILED; } int updates = calc.getUpdatesValue(rows[b]) + 1; if(pkUpdateRecord(pNdb, r+b, 1, updates) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } } check = pTrans->execute(Commit, AbortOnError); } if( check == -1 ) { const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); ndbout << "r = " << r << endl; closeTransaction(pNdb); return NDBT_FAILED; } else{ updated += batch; m_latest_gci = pTrans->getGCI(); } closeTransaction(pNdb); if (timer_active) { NdbTick_getMicroTimer(&timer_stop); NDB_TICKS ticks = NdbTick_getMicrosPassed(timer_start, timer_stop); m_stats_latency->addObservation((double)ticks); } r += batch; // Read next record batch_no++; } deallocRows(); g_info << "|- " << updated << " records updated" << endl; return NDBT_OK; }
int HugoTransactions::pkReadRecords(Ndb* pNdb, int records, int batch, NdbOperation::LockMode lm){ int reads = 0; int r = 0; int retryAttempt = 0; int check; if (batch == 0) { g_info << "ERROR: Argument batch == 0 in pkReadRecords(). Not allowed." << endl; return NDBT_FAILED; } while (r < records){ if(r + batch > records) batch = records - r; if (retryAttempt >= m_retryMax){ g_info << "ERROR: has retried this operation " << retryAttempt << " times, failing!" << endl; return NDBT_FAILED; } pTrans = pNdb->startTransaction(); if (pTrans == NULL) { const NdbError err = pNdb->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); return NDBT_FAILED; } MicroSecondTimer timer_start; MicroSecondTimer timer_stop; bool timer_active = m_stats_latency != 0 && r >= batch && // first batch is "warmup" r + batch != records; // last batch is usually partial if (timer_active) NdbTick_getMicroTimer(&timer_start); if(pkReadRecord(pNdb, r, batch, lm) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } check = pTrans->execute(Commit, AbortOnError); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } switch(err.code){ case 626: // Tuple did not exist g_info << r << ": " << err.code << " " << err.message << endl; r++; break; default: ERR(err); closeTransaction(pNdb); return NDBT_FAILED; } } else { if(pIndexScanOp) { int rows_found = 0; while((check = pIndexScanOp->nextResult()) == 0) { rows_found++; if (calc.verifyRowValues(rows[0]) != 0){ closeTransaction(pNdb); return NDBT_FAILED; } } if(check != 1 || rows_found > batch) { closeTransaction(pNdb); return NDBT_FAILED; } else if(rows_found < batch) { if(batch == 1){ g_info << r << ": not found" << endl; abort(); } else g_info << "Found " << rows_found << " of " << batch << " rows" << endl; } r += batch; reads += rows_found; } else { for (int b=0; (b<batch) && (r+b<records); b++){ if (calc.verifyRowValues(rows[b]) != 0){ closeTransaction(pNdb); return NDBT_FAILED; } reads++; r++; } } } closeTransaction(pNdb); if (timer_active) { NdbTick_getMicroTimer(&timer_stop); NDB_TICKS ticks = NdbTick_getMicrosPassed(timer_start, timer_stop); m_stats_latency->addObservation((double)ticks); } } deallocRows(); g_info << reads << " records read" << endl; return NDBT_OK; }
int HugoTransactions::lockRecords(Ndb* pNdb, int records, int percentToLock, int lockTime){ // Place a lock on percentToLock% of the records in the Db // Keep the locks for lockTime ms, commit operation // and lock som other records int r = 0; int retryAttempt = 0; int check; NdbOperation::LockMode lm = NdbOperation::LM_Exclusive; // Calculate how many records to lock in each batch if (percentToLock <= 0) percentToLock = 1; double percentVal = (double)percentToLock / 100; int lockBatch = (int)(records * percentVal); if (lockBatch <= 0) lockBatch = 1; allocRows(lockBatch); while (r < records){ if(r + lockBatch > records) lockBatch = records - r; g_info << "|- Locking " << lockBatch << " records..." << endl; if (retryAttempt >= m_retryMax){ g_info << "ERROR: has retried this operation " << retryAttempt << " times, failing!" << endl; return NDBT_FAILED; } pTrans = pNdb->startTransaction(); if (pTrans == NULL) { const NdbError err = pNdb->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); return NDBT_FAILED; } if(pkReadRecord(pNdb, r, lockBatch, lm) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } // NoCommit lockTime times with 100 millis interval int sleepInterval = 50; int lockCount = lockTime / sleepInterval; int commitCount = 0; do { check = pTrans->execute(NoCommit, AbortOnError); if( check == -1) { const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); closeTransaction(pNdb); return NDBT_FAILED; } for (int b=0; (b<lockBatch) && (r+b<records); b++){ if (calc.verifyRowValues(rows[b]) != 0){ closeTransaction(pNdb); return NDBT_FAILED; } } commitCount++; NdbSleep_MilliSleep(sleepInterval); } while (commitCount < lockCount); // Really commit the trans, puuh! check = pTrans->execute(Commit, AbortOnError); if( check == -1) { const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); closeTransaction(pNdb); return NDBT_FAILED; } else{ for (int b=0; (b<lockBatch) && (r<records); b++){ if (calc.verifyRowValues(rows[b]) != 0){ closeTransaction(pNdb); return NDBT_FAILED; } r++; // Read next record } } closeTransaction(pNdb); } deallocRows(); g_info << "|- Record locking completed" << endl; return NDBT_OK; }