/** * Callback executed when transaction has return from NDB */ static void callback(int result, NdbTransaction* trans, void* aObject) { async_callback_t * cbData = (async_callback_t *)aObject; if (result<0) { /** * Error: Temporary or permanent? */ if (asynchErrorHandler(trans, (Ndb*)cbData->ndb)) { closeTransaction((Ndb*)cbData->ndb, cbData); while(populate((Ndb*)cbData->ndb, cbData->data, cbData) < 0) milliSleep(10); } else { std::cout << "Restore: Failed to restore data " << "due to a unrecoverable error. Exiting..." << std::endl; delete cbData; asynchExitHandler((Ndb*)cbData->ndb); } } else { /** * OK! close transaction */ closeTransaction((Ndb*)cbData->ndb, cbData); delete cbData; } }
void BackupRestore::tuple_a(restore_callback_t *cb) { while (cb->retries < 10) { /** * start transactions */ cb->connection = m_ndb->startTransaction(); if (cb->connection == NULL) { /* if (asynchErrorHandler(cb->connection, m_ndb)) { cb->retries++; continue; } */ asynchExitHandler(); } // if const TupleS &tup = *(cb->tup); const TableS * table = tup.getTable(); NdbOperation * op = cb->connection->getNdbOperation(table->getTableName()); if (op == NULL) { if (asynchErrorHandler(cb->connection, m_ndb)) { cb->retries++; continue; } asynchExitHandler(); } // if if (op->writeTuple() == -1) { if (asynchErrorHandler(cb->connection, m_ndb)) { cb->retries++; continue; } asynchExitHandler(); } // if Uint32 ret = 0; for (int i = 0; i < tup.getNoOfAttributes(); i++) { const AttributeS * attr = tup[i]; int size = attr->Desc->size; int arraySize = attr->Desc->arraySize; char * dataPtr = attr->Data.string_value; Uint32 length = (size * arraySize) / 8; if (attr->Desc->m_column->getPrimaryKey()) { ret = op->equal(i, dataPtr, length); } else { if (attr->Data.null) ret = op->setValue(i, NULL, 0); else ret = op->setValue(i, dataPtr, length); } if (ret<0) { ndbout_c("Column: %d type %d",i, tup.getTable()->m_dictTable->getColumn(i)->getType()); if (asynchErrorHandler(cb->connection, m_ndb)) { cb->retries++; break; } asynchExitHandler(); } } if (ret < 0) continue; // Prepare transaction (the transaction is NOT yet sent to NDB) cb->connection->executeAsynchPrepare(Commit, &callback, cb); m_transactions++; } ndbout_c("Unable to recover from errors. Exiting..."); asynchExitHandler(); }
/************************************************************************ * populate() * 1. Prepare 'parallelism' number of insert transactions. * 2. Send transactions to NDB and wait for callbacks to execute */ int populate(Ndb * myNdb, int data, async_callback_t * cbData) { NdbOperation* myNdbOperation; // For operations const NdbDictionary::Dictionary* myDict= myNdb->getDictionary(); const NdbDictionary::Table *myTable= myDict->getTable("api_async"); if (myTable == NULL) APIERROR(myDict->getNdbError()); async_callback_t * cb; int retries = 0; int current = 0; for(int i=0; i<1024; i++) { if(transaction[i].used == 0) { current = i; if (cbData == 0) { /** * We already have a callback * This is an absolutely new transaction */ cb = new async_callback_t; cb->retries = 0; } else { /** * We already have a callback */ cb =cbData; retries = cbData->retries; } /** * Set data used by the callback */ cb->ndb = myNdb; //handle to Ndb object so that we can close transaction // in the callback (alt. make myNdb global). cb->data = data; //this is the data we want to insert cb->transaction = current; //This is the number (id) of this transaction transaction[current].used = 1 ; //Mark the transaction as used break; } } if(!current) return -1; while(retries < MAX_RETRIES) { transaction[current].conn = myNdb->startTransaction(); if (transaction[current].conn == NULL) { /** * no transaction to close since conn == null */ milliSleep(10); retries++; continue; } myNdbOperation = transaction[current].conn->getNdbOperation(myTable); if (myNdbOperation == NULL) { if (asynchErrorHandler(transaction[current].conn, myNdb)) { myNdb->closeTransaction(transaction[current].conn); transaction[current].conn = 0; milliSleep(10); retries++; continue; } asynchExitHandler(myNdb); } // if if(myNdbOperation->insertTuple() < 0 || myNdbOperation->equal("REG_NO", data) < 0 || myNdbOperation->setValue("BRAND", "Mercedes") <0 || myNdbOperation->setValue("COLOR", "Blue") < 0) { if (asynchErrorHandler(transaction[current].conn, myNdb)) { myNdb->closeTransaction(transaction[current].conn); transaction[current].conn = 0; retries++; milliSleep(10); continue; } asynchExitHandler(myNdb); } /*Prepare transaction (the transaction is NOT yet sent to NDB)*/ transaction[current].conn->executeAsynchPrepare(NdbTransaction::Commit, &callback, cb); /** * When we have prepared parallelism number of transactions -> * send the transaction to ndb. * Next time we will deal with the transactions are in the * callback. There we will see which ones that were successful * and which ones to retry. */ if (nPreparedTransactions == parallelism-1) { // send-poll all transactions // close transaction is done in callback myNdb->sendPollNdb(3000, parallelism ); nPreparedTransactions=0; } else nPreparedTransactions++; return 1; } std::cout << "Unable to recover from errors. Exiting..." << std::endl; asynchExitHandler(myNdb); return -1; }