diff options
Diffstat (limited to 'ndb/examples/ndbapi_retries_example/ndbapi_retries.cpp')
-rw-r--r-- | ndb/examples/ndbapi_retries_example/ndbapi_retries.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/ndb/examples/ndbapi_retries_example/ndbapi_retries.cpp b/ndb/examples/ndbapi_retries_example/ndbapi_retries.cpp new file mode 100644 index 00000000000..d14e0cf4553 --- /dev/null +++ b/ndb/examples/ndbapi_retries_example/ndbapi_retries.cpp @@ -0,0 +1,226 @@ +/* Copyright (C) 2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// +// ndbapi_retries.cpp: Error handling and transaction retries +// +// Execute ndbapi_simple to create the table "MYTABLENAME" +// before executing this program. +// +// There are many ways to program using the NDB API. In this example +// we execute two inserts in the same transaction using +// NdbConnection::execute(NoCommit). +// +// Transaction failing is handled by re-executing the transaction +// in case of non-permanent transaction errors. +// Application errors (i.e. errors at points marked with APIERROR) +// should be handled by the application programmer. + +#include <NdbApi.hpp> + +// Used for cout +#include <iostream> + +// Used for sleep (use your own version of sleep) +#include <unistd.h> +#define TIME_TO_SLEEP_BETWEEN_TRANSACTION_RETRIES 1 + +// +// APIERROR prints an NdbError object +// +#define APIERROR(error) \ + { std::cout << "API ERROR: " << error.code << " " << error.message \ + << std::endl \ + << " " << "Status: " << error.status \ + << ", Classification: " << error.classification << std::endl\ + << " " << "File: " << __FILE__ \ + << " (Line: " << __LINE__ << ")" << std::endl \ + ; \ + } + +// +// TRANSERROR prints all error info regarding an NdbTransaction +// +#define TRANSERROR(ndbTransaction) \ + { NdbError error = ndbTransaction->getNdbError(); \ + std::cout << "TRANS ERROR: " << error.code << " " << error.message \ + << std::endl \ + << " " << "Status: " << error.status \ + << ", Classification: " << error.classification << std::endl \ + << " " << "File: " << __FILE__ \ + << " (Line: " << __LINE__ << ")" << std::endl \ + ; \ + printTransactionError(ndbTransaction); \ + } + +void printTransactionError(NdbTransaction *ndbTransaction) { + const NdbOperation *ndbOp = NULL; + int i=0; + + /**************************************************************** + * Print NdbError object of every operations in the transaction * + ****************************************************************/ + while ((ndbOp = ndbTransaction->getNextCompletedOperation(ndbOp)) != NULL) { + NdbError error = ndbOp->getNdbError(); + std::cout << " OPERATION " << i+1 << ": " + << error.code << " " << error.message << std::endl + << " Status: " << error.status + << ", Classification: " << error.classification << std::endl; + i++; + } +} + + +// +// Example insert +// @param myNdb Ndb object representing NDB Cluster +// @param myTransaction NdbTransaction used for transaction +// @param error NdbError object returned in case of errors +// @return -1 in case of failures, 0 otherwise +// +int insert(int transactionId, NdbTransaction* myTransaction) { + NdbOperation *myOperation; // For other operations + + myOperation = myTransaction->getNdbOperation("MYTABLENAME"); + if (myOperation == NULL) return -1; + + if (myOperation->insertTuple() || + myOperation->equal("ATTR1", transactionId) || + myOperation->setValue("ATTR2", transactionId)) { + APIERROR(myOperation->getNdbError()); + exit(-1); + } + + return myTransaction->execute(NdbTransaction::NoCommit); +} + + +// +// Execute function which re-executes (tries 10 times) the transaction +// if there are temporary errors (e.g. the NDB Cluster is overloaded). +// @return -1 failure, 1 success +// +int executeInsertTransaction(int transactionId, Ndb* myNdb) { + int result = 0; // No result yet + int noOfRetriesLeft = 10; + NdbTransaction *myTransaction; // For other transactions + NdbError ndberror; + + while (noOfRetriesLeft > 0 && !result) { + + /********************************* + * Start and execute transaction * + *********************************/ + myTransaction = myNdb->startTransaction(); + if (myTransaction == NULL) { + APIERROR(myNdb->getNdbError()); + ndberror = myNdb->getNdbError(); + result = -1; // Failure + } else if (insert(transactionId, myTransaction) || + insert(10000+transactionId, myTransaction) || + myTransaction->execute(NdbTransaction::Commit)) { + TRANSERROR(myTransaction); + ndberror = myTransaction->getNdbError(); + result = -1; // Failure + } else { + result = 1; // Success + } + + /********************************** + * If failure, then analyze error * + **********************************/ + if (result == -1) { + switch (ndberror.status) { + case NdbError::Success: + break; + case NdbError::TemporaryError: + std::cout << "Retrying transaction..." << std::endl; + sleep(TIME_TO_SLEEP_BETWEEN_TRANSACTION_RETRIES); + --noOfRetriesLeft; + result = 0; // No completed transaction yet + break; + + case NdbError::UnknownResult: + case NdbError::PermanentError: + std::cout << "No retry of transaction..." << std::endl; + result = -1; // Permanent failure + break; + } + } + + /********************* + * Close transaction * + *********************/ + if (myTransaction != NULL) { + myNdb->closeTransaction(myTransaction); + } + } + + if (result != 1) exit(-1); + return result; +} + + +int main() +{ + ndb_init(); + + Ndb_cluster_connection *cluster_connection= + new Ndb_cluster_connection(); // Object representing the cluster + + int r= cluster_connection->connect(5 /* retries */, + 3 /* delay between retries */, + 1 /* verbose */); + if (r > 0) + { + std::cout + << "Cluster connect failed, possibly resolved with more retries.\n"; + exit(-1); + } + else if (r < 0) + { + std::cout + << "Cluster connect failed.\n"; + exit(-1); + } + + if (cluster_connection->wait_until_ready(30,30)) + { + std::cout << "Cluster was not ready within 30 secs." << std::endl; + exit(-1); + } + + Ndb* myNdb= new Ndb( cluster_connection, + "TEST_DB_1" ); // Object representing the database + + if (myNdb->init() == -1) { + APIERROR(myNdb->getNdbError()); + exit(-1); + } + + /************************************ + * Execute some insert transactions * + ************************************/ + for (int i = 10000; i < 20000; i++) { + executeInsertTransaction(i, myNdb); + } + + delete myNdb; + delete cluster_connection; + + ndb_end(0); + return 0; +} |