mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
merge error
This commit is contained in:
140
storage/ndb/ndbapi-examples/mgmapi_logevent/mgmapi_logevent.cpp
Normal file
140
storage/ndb/ndbapi-examples/mgmapi_logevent/mgmapi_logevent.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/* 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 */
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <ndbapi/NdbApi.hpp>
|
||||||
|
#include <mgmapi.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* export LD_LIBRARY_PATH=../../../libmysql_r/.libs:../../../ndb/src/.libs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MGMERROR(h) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "code: %d msg: %s\n", \
|
||||||
|
ndb_mgm_get_latest_error(h), \
|
||||||
|
ndb_mgm_get_latest_error_msg(h)); \
|
||||||
|
exit(-1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOGEVENTERROR(h) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "code: %d msg: %s\n", \
|
||||||
|
ndb_logevent_get_latest_error(h), \
|
||||||
|
ndb_logevent_get_latest_error_msg(h)); \
|
||||||
|
exit(-1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
NdbMgmHandle h;
|
||||||
|
NdbLogEventHandle le;
|
||||||
|
int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
|
||||||
|
15, NDB_MGM_EVENT_CATEGORY_CONNECTION,
|
||||||
|
15, NDB_MGM_EVENT_CATEGORY_NODE_RESTART,
|
||||||
|
15, NDB_MGM_EVENT_CATEGORY_STARTUP,
|
||||||
|
15, NDB_MGM_EVENT_CATEGORY_ERROR,
|
||||||
|
0 };
|
||||||
|
struct ndb_logevent event;
|
||||||
|
|
||||||
|
ndb_init();
|
||||||
|
|
||||||
|
h= ndb_mgm_create_handle();
|
||||||
|
if ( h == 0)
|
||||||
|
{
|
||||||
|
printf("Unable to create handle\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (ndb_mgm_connect(h,0,0,0)) MGMERROR(h);
|
||||||
|
|
||||||
|
le= ndb_mgm_create_logevent_handle(h, filter);
|
||||||
|
if ( le == 0 ) MGMERROR(h);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int timeout= 5000;
|
||||||
|
int r= ndb_logevent_get_next(le,&event,timeout);
|
||||||
|
if (r == 0)
|
||||||
|
printf("No event within %d milliseconds\n", timeout);
|
||||||
|
else if (r < 0)
|
||||||
|
LOGEVENTERROR(le)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (event.type) {
|
||||||
|
case NDB_LE_BackupStarted:
|
||||||
|
printf("Node %d: BackupStarted\n", event.source_nodeid);
|
||||||
|
printf(" Starting node ID: %d\n", event.BackupStarted.starting_node);
|
||||||
|
printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
|
||||||
|
break;
|
||||||
|
case NDB_LE_BackupCompleted:
|
||||||
|
printf("Node %d: BackupCompleted\n", event.source_nodeid);
|
||||||
|
printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
|
||||||
|
break;
|
||||||
|
case NDB_LE_BackupAborted:
|
||||||
|
printf("Node %d: BackupAborted\n", event.source_nodeid);
|
||||||
|
break;
|
||||||
|
case NDB_LE_BackupFailedToStart:
|
||||||
|
printf("Node %d: BackupFailedToStart\n", event.source_nodeid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NDB_LE_NodeFailCompleted:
|
||||||
|
printf("Node %d: NodeFailCompleted\n", event.source_nodeid);
|
||||||
|
break;
|
||||||
|
case NDB_LE_ArbitResult:
|
||||||
|
printf("Node %d: ArbitResult\n", event.source_nodeid);
|
||||||
|
printf(" code %d, arbit_node %d\n",
|
||||||
|
event.ArbitResult.code & 0xffff,
|
||||||
|
event.ArbitResult.arbit_node);
|
||||||
|
break;
|
||||||
|
case NDB_LE_DeadDueToHeartbeat:
|
||||||
|
printf("Node %d: DeadDueToHeartbeat\n", event.source_nodeid);
|
||||||
|
printf(" node %d\n", event.DeadDueToHeartbeat.node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NDB_LE_Connected:
|
||||||
|
printf("Node %d: Connected\n", event.source_nodeid);
|
||||||
|
printf(" node %d\n", event.Connected.node);
|
||||||
|
break;
|
||||||
|
case NDB_LE_Disconnected:
|
||||||
|
printf("Node %d: Disconnected\n", event.source_nodeid);
|
||||||
|
printf(" node %d\n", event.Disconnected.node);
|
||||||
|
break;
|
||||||
|
case NDB_LE_NDBStartCompleted:
|
||||||
|
printf("Node %d: StartCompleted\n", event.source_nodeid);
|
||||||
|
printf(" version %d.%d.%d\n",
|
||||||
|
event.NDBStartCompleted.version >> 16 & 0xff,
|
||||||
|
event.NDBStartCompleted.version >> 8 & 0xff,
|
||||||
|
event.NDBStartCompleted.version >> 0 & 0xff);
|
||||||
|
break;
|
||||||
|
case NDB_LE_ArbitState:
|
||||||
|
printf("Node %d: ArbitState\n", event.source_nodeid);
|
||||||
|
printf(" code %d, arbit_node %d\n",
|
||||||
|
event.ArbitState.code & 0xffff,
|
||||||
|
event.ArbitResult.arbit_node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ndb_mgm_destroy_logevent_handle(&le);
|
||||||
|
ndb_mgm_destroy_handle(&h);
|
||||||
|
ndb_end(0);
|
||||||
|
return 0;
|
||||||
|
}
|
476
storage/ndb/ndbapi-examples/ndbapi_async/ndbapi_async.cpp
Normal file
476
storage/ndb/ndbapi-examples/ndbapi_async/ndbapi_async.cpp
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/* 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_async.cpp:
|
||||||
|
* Illustrates how to use callbacks and error handling using the asynchronous
|
||||||
|
* part of the NDBAPI.
|
||||||
|
*
|
||||||
|
* Classes and methods in NDBAPI used in this example:
|
||||||
|
*
|
||||||
|
* Ndb_cluster_connection
|
||||||
|
* connect()
|
||||||
|
* wait_until_ready()
|
||||||
|
*
|
||||||
|
* Ndb
|
||||||
|
* init()
|
||||||
|
* startTransaction()
|
||||||
|
* closeTransaction()
|
||||||
|
* sendPollNdb()
|
||||||
|
* getNdbError()
|
||||||
|
*
|
||||||
|
* NdbConnection
|
||||||
|
* getNdbOperation()
|
||||||
|
* executeAsynchPrepare()
|
||||||
|
* getNdbError()
|
||||||
|
*
|
||||||
|
* NdbOperation
|
||||||
|
* insertTuple()
|
||||||
|
* equal()
|
||||||
|
* setValue()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <mysqld_error.h>
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
|
||||||
|
#include <iostream> // Used for cout
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper sleep function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
milliSleep(int milliseconds){
|
||||||
|
struct timeval sleeptime;
|
||||||
|
sleeptime.tv_sec = milliseconds / 1000;
|
||||||
|
sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
|
||||||
|
select(0, 0, 0, 0, &sleeptime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error printout macro
|
||||||
|
*/
|
||||||
|
#define PRINT_ERROR(code,msg) \
|
||||||
|
std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
|
||||||
|
<< ", code: " << code \
|
||||||
|
<< ", msg: " << msg << "." << std::endl
|
||||||
|
#define MYSQLERROR(mysql) { \
|
||||||
|
PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
|
||||||
|
exit(-1); }
|
||||||
|
#define APIERROR(error) { \
|
||||||
|
PRINT_ERROR(error.code,error.message); \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
|
||||||
|
/**
|
||||||
|
* callback struct.
|
||||||
|
* transaction : index of the transaction in transaction[] array below
|
||||||
|
* data : the data that the transaction was modifying.
|
||||||
|
* retries : counter for how many times the trans. has been retried
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Ndb * ndb;
|
||||||
|
int transaction;
|
||||||
|
int data;
|
||||||
|
int retries;
|
||||||
|
} async_callback_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure used in "free list" to a NdbTransaction
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
NdbTransaction* conn;
|
||||||
|
int used;
|
||||||
|
} transaction_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free list holding transactions
|
||||||
|
*/
|
||||||
|
transaction_t transaction[1024]; //1024 - max number of outstanding
|
||||||
|
//transaction in one Ndb object
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare and send transaction
|
||||||
|
*/
|
||||||
|
int populate(Ndb * myNdb, int data, async_callback_t * cbData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler.
|
||||||
|
*/
|
||||||
|
bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit function
|
||||||
|
*/
|
||||||
|
void asynchExitHandler(Ndb * m_ndb) ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function used in callback(...)
|
||||||
|
*/
|
||||||
|
void closeTransaction(Ndb * ndb , async_callback_t * cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to create table
|
||||||
|
*/
|
||||||
|
int create_table(Ndb * myNdb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stat. variables
|
||||||
|
*/
|
||||||
|
int tempErrors = 0;
|
||||||
|
int permErrors = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
closeTransaction(Ndb * ndb , async_callback_t * cb)
|
||||||
|
{
|
||||||
|
ndb->closeTransaction(transaction[cb->transaction].conn);
|
||||||
|
transaction[cb->transaction].conn = 0;
|
||||||
|
transaction[cb->transaction].used = 0;
|
||||||
|
cb->retries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create table "GARAGE"
|
||||||
|
*/
|
||||||
|
int create_table(MYSQL &mysql)
|
||||||
|
{
|
||||||
|
while (mysql_query(&mysql,
|
||||||
|
"CREATE TABLE"
|
||||||
|
" GARAGE"
|
||||||
|
" (REG_NO INT UNSIGNED NOT NULL,"
|
||||||
|
" BRAND CHAR(20) NOT NULL,"
|
||||||
|
" COLOR CHAR(20) NOT NULL,"
|
||||||
|
" PRIMARY KEY USING HASH (REG_NO))"
|
||||||
|
" ENGINE=NDB"))
|
||||||
|
{
|
||||||
|
if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
std::cout << "MySQL Cluster already has example table: GARAGE. "
|
||||||
|
<< "Dropping it..." << std::endl;
|
||||||
|
/**************
|
||||||
|
* Drop table *
|
||||||
|
**************/
|
||||||
|
if (mysql_query(&mysql, "DROP TABLE GARAGE"))
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void asynchExitHandler(Ndb * m_ndb)
|
||||||
|
{
|
||||||
|
if (m_ndb != NULL)
|
||||||
|
delete m_ndb;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns true if is recoverable (temporary),
|
||||||
|
* false if it is an error that is permanent.
|
||||||
|
*/
|
||||||
|
bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb)
|
||||||
|
{
|
||||||
|
NdbError error = trans->getNdbError();
|
||||||
|
switch(error.status)
|
||||||
|
{
|
||||||
|
case NdbError::Success:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NdbError::TemporaryError:
|
||||||
|
/**
|
||||||
|
* The error code indicates a temporary error.
|
||||||
|
* The application should typically retry.
|
||||||
|
* (Includes classifications: NdbError::InsufficientSpace,
|
||||||
|
* NdbError::TemporaryResourceError, NdbError::NodeRecoveryError,
|
||||||
|
* NdbError::OverloadError, NdbError::NodeShutdown
|
||||||
|
* and NdbError::TimeoutExpired.)
|
||||||
|
*
|
||||||
|
* We should sleep for a while and retry, except for insufficient space
|
||||||
|
*/
|
||||||
|
if(error.classification == NdbError::InsufficientSpace)
|
||||||
|
return false;
|
||||||
|
milliSleep(10);
|
||||||
|
tempErrors++;
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case NdbError::UnknownResult:
|
||||||
|
std::cout << error.message << std::endl;
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case NdbError::PermanentError:
|
||||||
|
switch (error.code)
|
||||||
|
{
|
||||||
|
case 499:
|
||||||
|
case 250:
|
||||||
|
milliSleep(10);
|
||||||
|
return true; // SCAN errors that can be retried. Requires restart of scan.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//ERROR
|
||||||
|
std::cout << error.message << std::endl;
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nPreparedTransactions = 0;
|
||||||
|
static int MAX_RETRIES = 10;
|
||||||
|
static int parallelism = 100;
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* 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("GARAGE");
|
||||||
|
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) {
|
||||||
|
if (asynchErrorHandler(transaction[current].conn, myNdb))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* no transaction to close since conn == null
|
||||||
|
*/
|
||||||
|
milliSleep(10);
|
||||||
|
retries++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
asynchExitHandler(myNdb);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ndb_init();
|
||||||
|
MYSQL mysql;
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to mysql server and create table *
|
||||||
|
**************************************************************/
|
||||||
|
{
|
||||||
|
if ( !mysql_init(&mysql) ) {
|
||||||
|
std::cout << "mysql_init failed\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
|
||||||
|
3306, "/tmp/mysql.sock", 0) )
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
mysql_query(&mysql, "CREATE DATABASE TEST_DB");
|
||||||
|
if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
create_table(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to ndb cluster *
|
||||||
|
**************************************************************/
|
||||||
|
Ndb_cluster_connection cluster_connection;
|
||||||
|
if (cluster_connection.connect(4, 5, 1))
|
||||||
|
{
|
||||||
|
std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
// Optionally connect and wait for the storage nodes (ndbd's)
|
||||||
|
if (cluster_connection.wait_until_ready(30,0) < 0)
|
||||||
|
{
|
||||||
|
std::cout << "Cluster was not ready within 30 secs.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ndb* myNdb = new Ndb( &cluster_connection,
|
||||||
|
"TEST_DB" ); // Object representing the database
|
||||||
|
if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
|
||||||
|
APIERROR(myNdb->getNdbError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise transaction array
|
||||||
|
*/
|
||||||
|
for(int i = 0 ; i < 1024 ; i++)
|
||||||
|
{
|
||||||
|
transaction[i].used = 0;
|
||||||
|
transaction[i].conn = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
int i=0;
|
||||||
|
/**
|
||||||
|
* Do 20000 insert transactions.
|
||||||
|
*/
|
||||||
|
while(i < 20000)
|
||||||
|
{
|
||||||
|
while(populate(myNdb,i,0)<0) // <0, no space on free list. Sleep and try again.
|
||||||
|
milliSleep(10);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
std::cout << "Number of temporary errors: " << tempErrors << std::endl;
|
||||||
|
delete myNdb;
|
||||||
|
}
|
3
storage/ndb/ndbapi-examples/ndbapi_async/readme.txt
Normal file
3
storage/ndb/ndbapi-examples/ndbapi_async/readme.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
1. Set NDB_OS in Makefile
|
||||||
|
2. Add path to libNDB_API.so in LD_LIBRARY_PATH
|
||||||
|
3. Set NDB_CONNECTSTRING
|
144
storage/ndb/ndbapi-examples/ndbapi_async1/ndbapi_async1.cpp
Normal file
144
storage/ndb/ndbapi-examples/ndbapi_async1/ndbapi_async1.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/* 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_async1.cpp: Using asynchronous transactions in NDB API
|
||||||
|
//
|
||||||
|
// Execute ndbapi_example1 to create the table "MYTABLENAME"
|
||||||
|
// before executing this program.
|
||||||
|
//
|
||||||
|
// Correct output from this program is:
|
||||||
|
//
|
||||||
|
// Successful insert.
|
||||||
|
// Successful insert.
|
||||||
|
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
|
||||||
|
// Used for cout
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define APIERROR(error) \
|
||||||
|
{ std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
|
||||||
|
<< error.code << ", msg: " << error.message << "." << std::endl; \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
static void callback(int result, NdbTransaction* NdbObject, void* aObject);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ndb_init();
|
||||||
|
|
||||||
|
Ndb_cluster_connection *cluster_connection=
|
||||||
|
new Ndb_cluster_connection(); // Object representing the cluster
|
||||||
|
|
||||||
|
if (cluster_connection->wait_until_ready(30,30))
|
||||||
|
{
|
||||||
|
std::cout << "Cluster was not ready within 30 secs." << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_2" ); // Object representing the database
|
||||||
|
|
||||||
|
NdbTransaction* myNdbTransaction[2]; // For transactions
|
||||||
|
NdbOperation* myNdbOperation; // For operations
|
||||||
|
|
||||||
|
if (myNdb->init(2) == -1) { // Want two parallel insert transactions
|
||||||
|
APIERROR(myNdb->getNdbError());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* Insert (we do two insert transactions in parallel) *
|
||||||
|
******************************************************/
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
myNdbTransaction[i] = myNdb->startTransaction();
|
||||||
|
if (myNdbTransaction[i] == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
myNdbOperation = myNdbTransaction[i]->getNdbOperation(myTable);
|
||||||
|
if (myNdbOperation == NULL) APIERROR(myNdbTransaction[i]->getNdbError());
|
||||||
|
|
||||||
|
myNdbOperation->insertTuple();
|
||||||
|
myNdbOperation->equal("ATTR1", 20 + i);
|
||||||
|
myNdbOperation->setValue("ATTR2", 20 + i);
|
||||||
|
|
||||||
|
// Prepare transaction (the transaction is NOT yet sent to NDB)
|
||||||
|
myNdbTransaction[i]->executeAsynchPrepare(NdbTransaction::Commit,
|
||||||
|
&callback, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all transactions to NDB
|
||||||
|
myNdb->sendPreparedTransactions(0);
|
||||||
|
|
||||||
|
// Poll all transactions
|
||||||
|
myNdb->pollNdb(3000, 2);
|
||||||
|
|
||||||
|
// Close all transactions
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
myNdb->closeTransaction(myNdbTransaction[i]);
|
||||||
|
|
||||||
|
delete myNdb;
|
||||||
|
delete cluster_connection;
|
||||||
|
|
||||||
|
ndb_end(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* callback : This is called when the transaction is polled
|
||||||
|
*
|
||||||
|
* (This function must have three arguments:
|
||||||
|
* - The result of the transaction,
|
||||||
|
* - The NdbTransaction object, and
|
||||||
|
* - A pointer to an arbitrary object.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
callback(int result, NdbTransaction* myTrans, void* aObject)
|
||||||
|
{
|
||||||
|
if (result == -1) {
|
||||||
|
std::cout << "Poll error: " << std::endl;
|
||||||
|
APIERROR(myTrans->getNdbError());
|
||||||
|
} else {
|
||||||
|
std::cout << "Successful insert." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
264
storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp
Normal file
264
storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/* 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_event.cpp: Using API level events in NDB API
|
||||||
|
*
|
||||||
|
* Classes and methods used in this example:
|
||||||
|
*
|
||||||
|
* Ndb_cluster_connection
|
||||||
|
* connect()
|
||||||
|
* wait_until_ready()
|
||||||
|
*
|
||||||
|
* Ndb
|
||||||
|
* init()
|
||||||
|
* getDictionary()
|
||||||
|
* createEventOperation()
|
||||||
|
* dropEventOperation()
|
||||||
|
* pollEvents()
|
||||||
|
* nextEvent()
|
||||||
|
*
|
||||||
|
* NdbDictionary
|
||||||
|
* createEvent()
|
||||||
|
* dropEvent()
|
||||||
|
*
|
||||||
|
* NdbDictionary::Event
|
||||||
|
* setTable()
|
||||||
|
* addTableEvent()
|
||||||
|
* addEventColumn()
|
||||||
|
*
|
||||||
|
* NdbEventOperation
|
||||||
|
* getValue()
|
||||||
|
* getPreValue()
|
||||||
|
* execute()
|
||||||
|
* getEventType()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
|
||||||
|
// Used for cout
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Assume that there is a table TAB0 which is being updated by
|
||||||
|
* another process (e.g. flexBench -l 0 -stdtables).
|
||||||
|
* We want to monitor what happens with columns COL0, COL2, COL11
|
||||||
|
*
|
||||||
|
* or together with the mysql client;
|
||||||
|
*
|
||||||
|
* shell> mysql -u root
|
||||||
|
* mysql> create database TEST_DB;
|
||||||
|
* mysql> use TEST_DB;
|
||||||
|
* mysql> create table TAB0 (COL0 int primary key, COL1 int, COL11 int) engine=ndb;
|
||||||
|
*
|
||||||
|
* In another window start ndbapi_event, wait until properly started
|
||||||
|
*
|
||||||
|
insert into TAB0 values (1,2,3);
|
||||||
|
insert into TAB0 values (2,2,3);
|
||||||
|
insert into TAB0 values (3,2,9);
|
||||||
|
update TAB0 set COL1=10 where COL0=1;
|
||||||
|
delete from TAB0 where COL0=1;
|
||||||
|
*
|
||||||
|
* you should see the data popping up in the example window
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define APIERROR(error) \
|
||||||
|
{ std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
|
||||||
|
<< error.code << ", msg: " << error.message << "." << std::endl; \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
int myCreateEvent(Ndb* myNdb,
|
||||||
|
const char *eventName,
|
||||||
|
const char *eventTableName,
|
||||||
|
const char **eventColumnName,
|
||||||
|
const int noEventColumnName);
|
||||||
|
|
||||||
|
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"); // Object representing the database
|
||||||
|
|
||||||
|
if (myNdb->init() == -1) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
const char *eventName= "CHNG_IN_TAB0";
|
||||||
|
const char *eventTableName= "TAB0";
|
||||||
|
const int noEventColumnName= 3;
|
||||||
|
const char *eventColumnName[noEventColumnName]=
|
||||||
|
{"COL0",
|
||||||
|
"COL1",
|
||||||
|
"COL11"};
|
||||||
|
|
||||||
|
// Create events
|
||||||
|
myCreateEvent(myNdb,
|
||||||
|
eventName,
|
||||||
|
eventTableName,
|
||||||
|
eventColumnName,
|
||||||
|
noEventColumnName);
|
||||||
|
|
||||||
|
int j= 0;
|
||||||
|
while (j < 5) {
|
||||||
|
|
||||||
|
// Start "transaction" for handling events
|
||||||
|
NdbEventOperation* op;
|
||||||
|
printf("create EventOperation\n");
|
||||||
|
if ((op = myNdb->createEventOperation(eventName)) == NULL)
|
||||||
|
APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
printf("get values\n");
|
||||||
|
NdbRecAttr* recAttr[noEventColumnName];
|
||||||
|
NdbRecAttr* recAttrPre[noEventColumnName];
|
||||||
|
// primary keys should always be a part of the result
|
||||||
|
for (int i = 0; i < noEventColumnName; i++) {
|
||||||
|
recAttr[i] = op->getValue(eventColumnName[i]);
|
||||||
|
recAttrPre[i] = op->getPreValue(eventColumnName[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the callbacks
|
||||||
|
printf("execute\n");
|
||||||
|
// This starts changes to "start flowing"
|
||||||
|
if (op->execute())
|
||||||
|
APIERROR(op->getNdbError());
|
||||||
|
|
||||||
|
int i= 0;
|
||||||
|
while(i < 40) {
|
||||||
|
// printf("now waiting for event...\n");
|
||||||
|
int r= myNdb->pollEvents(1000); // wait for event or 1000 ms
|
||||||
|
if (r > 0) {
|
||||||
|
// printf("got data! %d\n", r);
|
||||||
|
while ((op= myNdb->nextEvent())) {
|
||||||
|
i++;
|
||||||
|
switch (op->getEventType()) {
|
||||||
|
case NdbDictionary::Event::TE_INSERT:
|
||||||
|
printf("%u INSERT: ", i);
|
||||||
|
break;
|
||||||
|
case NdbDictionary::Event::TE_DELETE:
|
||||||
|
printf("%u DELETE: ", i);
|
||||||
|
break;
|
||||||
|
case NdbDictionary::Event::TE_UPDATE:
|
||||||
|
printf("%u UPDATE: ", i);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort(); // should not happen
|
||||||
|
}
|
||||||
|
for (int i = 1; i < noEventColumnName; i++) {
|
||||||
|
if (recAttr[i]->isNULL() >= 0) { // we have a value
|
||||||
|
printf(" post[%u]=", i);
|
||||||
|
if (recAttr[i]->isNULL() == 0) // we have a non-null value
|
||||||
|
printf("%u", recAttr[i]->u_32_value());
|
||||||
|
else // we have a null value
|
||||||
|
printf("NULL");
|
||||||
|
}
|
||||||
|
if (recAttrPre[i]->isNULL() >= 0) { // we have a value
|
||||||
|
printf(" pre[%u]=", i);
|
||||||
|
if (recAttrPre[i]->isNULL() == 0) // we have a non-null value
|
||||||
|
printf("%u", recAttrPre[i]->u_32_value());
|
||||||
|
else // we have a null value
|
||||||
|
printf("NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
;//printf("timed out\n");
|
||||||
|
}
|
||||||
|
// don't want to listen to events anymore
|
||||||
|
if (myNdb->dropEventOperation(op)) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
NdbDictionary::Dictionary *myDict = myNdb->getDictionary();
|
||||||
|
if (!myDict) APIERROR(myNdb->getNdbError());
|
||||||
|
// remove event from database
|
||||||
|
if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete myNdb;
|
||||||
|
delete cluster_connection;
|
||||||
|
ndb_end(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int myCreateEvent(Ndb* myNdb,
|
||||||
|
const char *eventName,
|
||||||
|
const char *eventTableName,
|
||||||
|
const char **eventColumnNames,
|
||||||
|
const int noEventColumnNames)
|
||||||
|
{
|
||||||
|
NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
|
||||||
|
if (!myDict) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
const NdbDictionary::Table *table= myDict->getTable(eventTableName);
|
||||||
|
if (!table) APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
NdbDictionary::Event myEvent(eventName, *table);
|
||||||
|
myEvent.addTableEvent(NdbDictionary::Event::TE_ALL);
|
||||||
|
// myEvent.addTableEvent(NdbDictionary::Event::TE_INSERT);
|
||||||
|
// myEvent.addTableEvent(NdbDictionary::Event::TE_UPDATE);
|
||||||
|
// myEvent.addTableEvent(NdbDictionary::Event::TE_DELETE);
|
||||||
|
|
||||||
|
myEvent.addEventColumns(noEventColumnNames, eventColumnNames);
|
||||||
|
|
||||||
|
// Add event to database
|
||||||
|
if (myDict->createEvent(myEvent) == 0)
|
||||||
|
myEvent.print();
|
||||||
|
else if (myDict->getNdbError().classification ==
|
||||||
|
NdbError::SchemaObjectExists) {
|
||||||
|
printf("Event creation failed, event exists\n");
|
||||||
|
printf("dropping Event...\n");
|
||||||
|
if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
|
||||||
|
// try again
|
||||||
|
// Add event to database
|
||||||
|
if ( myDict->createEvent(myEvent)) APIERROR(myDict->getNdbError());
|
||||||
|
} else
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
236
storage/ndb/ndbapi-examples/ndbapi_retries/ndbapi_retries.cpp
Normal file
236
storage/ndb/ndbapi-examples/ndbapi_retries/ndbapi_retries.cpp
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/* 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 myTable Table to insert into
|
||||||
|
// @param error NdbError object returned in case of errors
|
||||||
|
// @return -1 in case of failures, 0 otherwise
|
||||||
|
//
|
||||||
|
int insert(int transactionId, NdbTransaction* myTransaction,
|
||||||
|
const NdbDictionary::Table *myTable) {
|
||||||
|
NdbOperation *myOperation; // For other operations
|
||||||
|
|
||||||
|
myOperation = myTransaction->getNdbOperation(myTable);
|
||||||
|
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,
|
||||||
|
const NdbDictionary::Table *myTable) {
|
||||||
|
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, myTable) ||
|
||||||
|
insert(10000+transactionId, myTransaction, myTable) ||
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
if (myTable == NULL)
|
||||||
|
{
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/************************************
|
||||||
|
* Execute some insert transactions *
|
||||||
|
************************************/
|
||||||
|
for (int i = 10000; i < 20000; i++) {
|
||||||
|
executeInsertTransaction(i, myNdb, myTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete myNdb;
|
||||||
|
delete cluster_connection;
|
||||||
|
|
||||||
|
ndb_end(0);
|
||||||
|
return 0;
|
||||||
|
}
|
825
storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp
Normal file
825
storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
|
||||||
|
/* 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_scan.cpp:
|
||||||
|
* Illustrates how to use the scan api in the NDBAPI.
|
||||||
|
* The example shows how to do scan, scan for update and scan for delete
|
||||||
|
* using NdbScanFilter and NdbScanOperation
|
||||||
|
*
|
||||||
|
* Classes and methods used in this example:
|
||||||
|
*
|
||||||
|
* Ndb_cluster_connection
|
||||||
|
* connect()
|
||||||
|
* wait_until_ready()
|
||||||
|
*
|
||||||
|
* Ndb
|
||||||
|
* init()
|
||||||
|
* getDictionary()
|
||||||
|
* startTransaction()
|
||||||
|
* closeTransaction()
|
||||||
|
*
|
||||||
|
* NdbTransaction
|
||||||
|
* getNdbScanOperation()
|
||||||
|
* execute()
|
||||||
|
*
|
||||||
|
* NdbScanOperation
|
||||||
|
* getValue()
|
||||||
|
* readTuples()
|
||||||
|
* nextResult()
|
||||||
|
* deleteCurrentTuple()
|
||||||
|
* updateCurrentTuple()
|
||||||
|
*
|
||||||
|
* const NdbDictionary::Dictionary
|
||||||
|
* getTable()
|
||||||
|
*
|
||||||
|
* const NdbDictionary::Table
|
||||||
|
* getColumn()
|
||||||
|
*
|
||||||
|
* const NdbDictionary::Column
|
||||||
|
* getLength()
|
||||||
|
*
|
||||||
|
* NdbOperation
|
||||||
|
* insertTuple()
|
||||||
|
* equal()
|
||||||
|
* setValue()
|
||||||
|
*
|
||||||
|
* NdbScanFilter
|
||||||
|
* begin()
|
||||||
|
* eq()
|
||||||
|
* end()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <mysqld_error.h>
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
// Used for cout
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper sleep function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
milliSleep(int milliseconds){
|
||||||
|
struct timeval sleeptime;
|
||||||
|
sleeptime.tv_sec = milliseconds / 1000;
|
||||||
|
sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
|
||||||
|
select(0, 0, 0, 0, &sleeptime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper sleep function
|
||||||
|
*/
|
||||||
|
#define PRINT_ERROR(code,msg) \
|
||||||
|
std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
|
||||||
|
<< ", code: " << code \
|
||||||
|
<< ", msg: " << msg << "." << std::endl
|
||||||
|
#define MYSQLERROR(mysql) { \
|
||||||
|
PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
|
||||||
|
exit(-1); }
|
||||||
|
#define APIERROR(error) { \
|
||||||
|
PRINT_ERROR(error.code,error.message); \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
struct Car
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Note memset, so that entire char-fields are cleared
|
||||||
|
* as all 20 bytes are significant (as type is char)
|
||||||
|
*/
|
||||||
|
Car() { memset(this, 0, sizeof(* this)); }
|
||||||
|
|
||||||
|
unsigned int reg_no;
|
||||||
|
char brand[20];
|
||||||
|
char color[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to create table
|
||||||
|
*/
|
||||||
|
int create_table(MYSQL &mysql)
|
||||||
|
{
|
||||||
|
while (mysql_query(&mysql,
|
||||||
|
"CREATE TABLE"
|
||||||
|
" GARAGE"
|
||||||
|
" (REG_NO INT UNSIGNED NOT NULL,"
|
||||||
|
" BRAND CHAR(20) NOT NULL,"
|
||||||
|
" COLOR CHAR(20) NOT NULL,"
|
||||||
|
" PRIMARY KEY USING HASH (REG_NO))"
|
||||||
|
" ENGINE=NDB"))
|
||||||
|
{
|
||||||
|
if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
std::cout << "MySQL Cluster already has example table: GARAGE. "
|
||||||
|
<< "Dropping it..." << std::endl;
|
||||||
|
/**************
|
||||||
|
* Drop table *
|
||||||
|
**************/
|
||||||
|
if (mysql_query(&mysql, "DROP TABLE GARAGE"))
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int populate(Ndb * myNdb)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Car cars[15];
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Five blue mercedes
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
cars[i].reg_no = i;
|
||||||
|
sprintf(cars[i].brand, "Mercedes");
|
||||||
|
sprintf(cars[i].color, "Blue");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Five black bmw
|
||||||
|
*/
|
||||||
|
for (i = 5; i < 10; i++)
|
||||||
|
{
|
||||||
|
cars[i].reg_no = i;
|
||||||
|
sprintf(cars[i].brand, "BMW");
|
||||||
|
sprintf(cars[i].color, "Black");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Five pink toyotas
|
||||||
|
*/
|
||||||
|
for (i = 10; i < 15; i++)
|
||||||
|
{
|
||||||
|
cars[i].reg_no = i;
|
||||||
|
sprintf(cars[i].brand, "Toyota");
|
||||||
|
sprintf(cars[i].color, "Pink");
|
||||||
|
}
|
||||||
|
|
||||||
|
NdbTransaction* myTrans = myNdb->startTransaction();
|
||||||
|
if (myTrans == NULL)
|
||||||
|
APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
for (i = 0; i < 15; i++)
|
||||||
|
{
|
||||||
|
NdbOperation* myNdbOperation = myTrans->getNdbOperation(myTable);
|
||||||
|
if (myNdbOperation == NULL)
|
||||||
|
APIERROR(myTrans->getNdbError());
|
||||||
|
myNdbOperation->insertTuple();
|
||||||
|
myNdbOperation->equal("REG_NO", cars[i].reg_no);
|
||||||
|
myNdbOperation->setValue("BRAND", cars[i].brand);
|
||||||
|
myNdbOperation->setValue("COLOR", cars[i].color);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check = myTrans->execute(NdbTransaction::Commit);
|
||||||
|
|
||||||
|
myTrans->close();
|
||||||
|
|
||||||
|
return check != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scan_delete(Ndb* myNdb,
|
||||||
|
int column,
|
||||||
|
const char * color)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
// Scan all records exclusive and delete
|
||||||
|
// them one by one
|
||||||
|
int retryAttempt = 0;
|
||||||
|
const int retryMax = 10;
|
||||||
|
int deletedRows = 0;
|
||||||
|
int check;
|
||||||
|
NdbError err;
|
||||||
|
NdbTransaction *myTrans;
|
||||||
|
NdbScanOperation *myScanOp;
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop as long as :
|
||||||
|
* retryMax not reached
|
||||||
|
* failed operations due to TEMPORARY erros
|
||||||
|
*
|
||||||
|
* Exit loop;
|
||||||
|
* retyrMax reached
|
||||||
|
* Permanent error (return -1)
|
||||||
|
*/
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (retryAttempt >= retryMax)
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: has retried this operation " << retryAttempt
|
||||||
|
<< " times, failing!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
myTrans = myNdb->startTransaction();
|
||||||
|
if (myTrans == NULL)
|
||||||
|
{
|
||||||
|
const NdbError err = myNdb->getNdbError();
|
||||||
|
|
||||||
|
if (err.status == NdbError::TemporaryError)
|
||||||
|
{
|
||||||
|
milliSleep(50);
|
||||||
|
retryAttempt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << err.message << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a scan operation.
|
||||||
|
*/
|
||||||
|
myScanOp = myTrans->getNdbScanOperation(myTable);
|
||||||
|
if (myScanOp == NULL)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a result set for the scan.
|
||||||
|
*/
|
||||||
|
if(myScanOp->readTuples(NdbOperation::LM_Exclusive) != 0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use NdbScanFilter to define a search critera
|
||||||
|
*/
|
||||||
|
NdbScanFilter filter(myScanOp) ;
|
||||||
|
if(filter.begin(NdbScanFilter::AND) < 0 ||
|
||||||
|
filter.cmp(NdbScanFilter::COND_EQ, column, color) < 0 ||
|
||||||
|
filter.end() < 0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start scan (NoCommit since we are only reading at this stage);
|
||||||
|
*/
|
||||||
|
if(myTrans->execute(NdbTransaction::NoCommit) != 0){
|
||||||
|
err = myTrans->getNdbError();
|
||||||
|
if(err.status == NdbError::TemporaryError){
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << err.code << std::endl;
|
||||||
|
std::cout << myTrans->getNdbError().code << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start of loop: nextResult(true) means that "parallelism" number of
|
||||||
|
* rows are fetched from NDB and cached in NDBAPI
|
||||||
|
*/
|
||||||
|
while((check = myScanOp->nextResult(true)) == 0){
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (myScanOp->deleteCurrentTuple() != 0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
deletedRows++;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nextResult(false) means that the records
|
||||||
|
* cached in the NDBAPI are modified before
|
||||||
|
* fetching more rows from NDB.
|
||||||
|
*/
|
||||||
|
} while((check = myScanOp->nextResult(false)) == 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit when all cached tuple have been marked for deletion
|
||||||
|
*/
|
||||||
|
if(check != -1)
|
||||||
|
{
|
||||||
|
check = myTrans->execute(NdbTransaction::Commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(check == -1)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new transaction, while keeping scan open
|
||||||
|
*/
|
||||||
|
check = myTrans->restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for errors
|
||||||
|
*/
|
||||||
|
err = myTrans->getNdbError();
|
||||||
|
if(check == -1)
|
||||||
|
{
|
||||||
|
if(err.status == NdbError::TemporaryError)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* End of loop
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(myTrans!=0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int scan_update(Ndb* myNdb,
|
||||||
|
int update_column,
|
||||||
|
const char * before_color,
|
||||||
|
const char * after_color)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
// Scan all records exclusive and update
|
||||||
|
// them one by one
|
||||||
|
int retryAttempt = 0;
|
||||||
|
const int retryMax = 10;
|
||||||
|
int updatedRows = 0;
|
||||||
|
int check;
|
||||||
|
NdbError err;
|
||||||
|
NdbTransaction *myTrans;
|
||||||
|
NdbScanOperation *myScanOp;
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop as long as :
|
||||||
|
* retryMax not reached
|
||||||
|
* failed operations due to TEMPORARY erros
|
||||||
|
*
|
||||||
|
* Exit loop;
|
||||||
|
* retyrMax reached
|
||||||
|
* Permanent error (return -1)
|
||||||
|
*/
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (retryAttempt >= retryMax)
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: has retried this operation " << retryAttempt
|
||||||
|
<< " times, failing!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
myTrans = myNdb->startTransaction();
|
||||||
|
if (myTrans == NULL)
|
||||||
|
{
|
||||||
|
const NdbError err = myNdb->getNdbError();
|
||||||
|
|
||||||
|
if (err.status == NdbError::TemporaryError)
|
||||||
|
{
|
||||||
|
milliSleep(50);
|
||||||
|
retryAttempt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << err.message << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a scan operation.
|
||||||
|
*/
|
||||||
|
myScanOp = myTrans->getNdbScanOperation(myTable);
|
||||||
|
if (myScanOp == NULL)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a result set for the scan.
|
||||||
|
*/
|
||||||
|
if( myScanOp->readTuples(NdbOperation::LM_Exclusive) )
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use NdbScanFilter to define a search critera
|
||||||
|
*/
|
||||||
|
NdbScanFilter filter(myScanOp) ;
|
||||||
|
if(filter.begin(NdbScanFilter::AND) < 0 ||
|
||||||
|
filter.cmp(NdbScanFilter::COND_EQ, update_column, before_color) <0||
|
||||||
|
filter.end() <0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start scan (NoCommit since we are only reading at this stage);
|
||||||
|
*/
|
||||||
|
if(myTrans->execute(NdbTransaction::NoCommit) != 0)
|
||||||
|
{
|
||||||
|
err = myTrans->getNdbError();
|
||||||
|
if(err.status == NdbError::TemporaryError){
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << myTrans->getNdbError().code << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start of loop: nextResult(true) means that "parallelism" number of
|
||||||
|
* rows are fetched from NDB and cached in NDBAPI
|
||||||
|
*/
|
||||||
|
while((check = myScanOp->nextResult(true)) == 0){
|
||||||
|
do {
|
||||||
|
/**
|
||||||
|
* Get update operation
|
||||||
|
*/
|
||||||
|
NdbOperation * myUpdateOp = myScanOp->updateCurrentTuple();
|
||||||
|
if (myUpdateOp == 0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
updatedRows++;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do the update
|
||||||
|
*/
|
||||||
|
myUpdateOp->setValue(update_column, after_color);
|
||||||
|
/**
|
||||||
|
* nextResult(false) means that the records
|
||||||
|
* cached in the NDBAPI are modified before
|
||||||
|
* fetching more rows from NDB.
|
||||||
|
*/
|
||||||
|
} while((check = myScanOp->nextResult(false)) == 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NoCommit when all cached tuple have been updated
|
||||||
|
*/
|
||||||
|
if(check != -1)
|
||||||
|
{
|
||||||
|
check = myTrans->execute(NdbTransaction::NoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for errors
|
||||||
|
*/
|
||||||
|
err = myTrans->getNdbError();
|
||||||
|
if(check == -1)
|
||||||
|
{
|
||||||
|
if(err.status == NdbError::TemporaryError){
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* End of loop
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit all prepared operations
|
||||||
|
*/
|
||||||
|
if(myTrans->execute(NdbTransaction::Commit) == -1)
|
||||||
|
{
|
||||||
|
if(err.status == NdbError::TemporaryError){
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(myTrans!=0)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int scan_print(Ndb * myNdb)
|
||||||
|
{
|
||||||
|
// Scan all records exclusive and update
|
||||||
|
// them one by one
|
||||||
|
int retryAttempt = 0;
|
||||||
|
const int retryMax = 10;
|
||||||
|
int fetchedRows = 0;
|
||||||
|
int check;
|
||||||
|
NdbError err;
|
||||||
|
NdbTransaction *myTrans;
|
||||||
|
NdbScanOperation *myScanOp;
|
||||||
|
/* Result of reading attribute value, three columns:
|
||||||
|
REG_NO, BRAND, and COLOR
|
||||||
|
*/
|
||||||
|
NdbRecAttr * myRecAttr[3];
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop as long as :
|
||||||
|
* retryMax not reached
|
||||||
|
* failed operations due to TEMPORARY erros
|
||||||
|
*
|
||||||
|
* Exit loop;
|
||||||
|
* retyrMax reached
|
||||||
|
* Permanent error (return -1)
|
||||||
|
*/
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (retryAttempt >= retryMax)
|
||||||
|
{
|
||||||
|
std::cout << "ERROR: has retried this operation " << retryAttempt
|
||||||
|
<< " times, failing!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
myTrans = myNdb->startTransaction();
|
||||||
|
if (myTrans == NULL)
|
||||||
|
{
|
||||||
|
const NdbError err = myNdb->getNdbError();
|
||||||
|
|
||||||
|
if (err.status == NdbError::TemporaryError)
|
||||||
|
{
|
||||||
|
milliSleep(50);
|
||||||
|
retryAttempt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << err.message << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Define a scan operation.
|
||||||
|
* NDBAPI.
|
||||||
|
*/
|
||||||
|
myScanOp = myTrans->getNdbScanOperation(myTable);
|
||||||
|
if (myScanOp == NULL)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read without locks, without being placed in lock queue
|
||||||
|
*/
|
||||||
|
if( myScanOp->readTuples(NdbOperation::LM_CommittedRead) == -1)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define storage for fetched attributes.
|
||||||
|
* E.g., the resulting attributes of executing
|
||||||
|
* myOp->getValue("REG_NO") is placed in myRecAttr[0].
|
||||||
|
* No data exists in myRecAttr until transaction has commited!
|
||||||
|
*/
|
||||||
|
myRecAttr[0] = myScanOp->getValue("REG_NO");
|
||||||
|
myRecAttr[1] = myScanOp->getValue("BRAND");
|
||||||
|
myRecAttr[2] = myScanOp->getValue("COLOR");
|
||||||
|
if(myRecAttr[0] ==NULL || myRecAttr[1] == NULL || myRecAttr[2]==NULL)
|
||||||
|
{
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start scan (NoCommit since we are only reading at this stage);
|
||||||
|
*/
|
||||||
|
if(myTrans->execute(NdbTransaction::NoCommit) != 0){
|
||||||
|
err = myTrans->getNdbError();
|
||||||
|
if(err.status == NdbError::TemporaryError){
|
||||||
|
std::cout << myTrans->getNdbError().message << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
milliSleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cout << err.code << std::endl;
|
||||||
|
std::cout << myTrans->getNdbError().code << std::endl;
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start of loop: nextResult(true) means that "parallelism" number of
|
||||||
|
* rows are fetched from NDB and cached in NDBAPI
|
||||||
|
*/
|
||||||
|
while((check = myScanOp->nextResult(true)) == 0){
|
||||||
|
do {
|
||||||
|
|
||||||
|
fetchedRows++;
|
||||||
|
/**
|
||||||
|
* print REG_NO unsigned int
|
||||||
|
*/
|
||||||
|
std::cout << myRecAttr[0]->u_32_value() << "\t";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print BRAND character string
|
||||||
|
*/
|
||||||
|
std::cout << myRecAttr[1]->aRef() << "\t";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print COLOR character string
|
||||||
|
*/
|
||||||
|
std::cout << myRecAttr[2]->aRef() << std::endl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nextResult(false) means that the records
|
||||||
|
* cached in the NDBAPI are modified before
|
||||||
|
* fetching more rows from NDB.
|
||||||
|
*/
|
||||||
|
} while((check = myScanOp->nextResult(false)) == 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
myNdb->closeTransaction(myTrans);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ndb_init();
|
||||||
|
MYSQL mysql;
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to mysql server and create table *
|
||||||
|
**************************************************************/
|
||||||
|
{
|
||||||
|
if ( !mysql_init(&mysql) ) {
|
||||||
|
std::cout << "mysql_init failed\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
|
||||||
|
3306, "/tmp/mysql.sock", 0) )
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
mysql_query(&mysql, "CREATE DATABASE TEST_DB");
|
||||||
|
if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
create_table(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to ndb cluster *
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
Ndb_cluster_connection cluster_connection;
|
||||||
|
if (cluster_connection.connect(4, 5, 1))
|
||||||
|
{
|
||||||
|
std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
// Optionally connect and wait for the storage nodes (ndbd's)
|
||||||
|
if (cluster_connection.wait_until_ready(30,0) < 0)
|
||||||
|
{
|
||||||
|
std::cout << "Cluster was not ready within 30 secs.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ndb myNdb(&cluster_connection,"TEST_DB");
|
||||||
|
if (myNdb.init(1024) == -1) { // Set max 1024 parallel transactions
|
||||||
|
APIERROR(myNdb.getNdbError());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* Check table definition *
|
||||||
|
*******************************************/
|
||||||
|
int column_color;
|
||||||
|
{
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
|
||||||
|
const NdbDictionary::Table *t= myDict->getTable("GARAGE");
|
||||||
|
|
||||||
|
Car car;
|
||||||
|
if (t->getColumn("COLOR")->getLength() != sizeof(car.color) ||
|
||||||
|
t->getColumn("BRAND")->getLength() != sizeof(car.brand))
|
||||||
|
{
|
||||||
|
std::cout << "Wrong table definition" << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
column_color= t->getColumn("COLOR")->getColumnNo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(populate(&myNdb) > 0)
|
||||||
|
std::cout << "populate: Success!" << std::endl;
|
||||||
|
|
||||||
|
if(scan_print(&myNdb) > 0)
|
||||||
|
std::cout << "scan_print: Success!" << std::endl << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Going to delete all pink cars!" << std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Note! color needs to be of exact the same size as column defined
|
||||||
|
*/
|
||||||
|
Car tmp;
|
||||||
|
sprintf(tmp.color, "Pink");
|
||||||
|
if(scan_delete(&myNdb, column_color, tmp.color) > 0)
|
||||||
|
std::cout << "scan_delete: Success!" << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scan_print(&myNdb) > 0)
|
||||||
|
std::cout << "scan_print: Success!" << std::endl << std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Note! color1 & 2 need to be of exact the same size as column defined
|
||||||
|
*/
|
||||||
|
Car tmp1, tmp2;
|
||||||
|
sprintf(tmp1.color, "Blue");
|
||||||
|
sprintf(tmp2.color, "Black");
|
||||||
|
std::cout << "Going to update all " << tmp1.color
|
||||||
|
<< " cars to " << tmp2.color << " cars!" << std::endl;
|
||||||
|
if(scan_update(&myNdb, column_color, tmp1.color, tmp2.color) > 0)
|
||||||
|
std::cout << "scan_update: Success!" << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
if(scan_print(&myNdb) > 0)
|
||||||
|
std::cout << "scan_print: Success!" << std::endl << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
3
storage/ndb/ndbapi-examples/ndbapi_scan/readme.txt
Normal file
3
storage/ndb/ndbapi-examples/ndbapi_scan/readme.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
1. Set NDB_OS in Makefile
|
||||||
|
2. Add path to libNDB_API.so in LD_LIBRARY_PATH
|
||||||
|
3. Set NDB_CONNECTSTRING
|
278
storage/ndb/ndbapi-examples/ndbapi_simple/ndbapi_simple.cpp
Normal file
278
storage/ndb/ndbapi-examples/ndbapi_simple/ndbapi_simple.cpp
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
/* 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_simple.cpp: Using synchronous transactions in NDB API
|
||||||
|
*
|
||||||
|
* Correct output from this program is:
|
||||||
|
*
|
||||||
|
* ATTR1 ATTR2
|
||||||
|
* 0 10
|
||||||
|
* 1 1
|
||||||
|
* 2 12
|
||||||
|
* Detected that deleted tuple doesn't exist!
|
||||||
|
* 4 14
|
||||||
|
* 5 5
|
||||||
|
* 6 16
|
||||||
|
* 7 7
|
||||||
|
* 8 18
|
||||||
|
* 9 9
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
// Used for cout
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static void run_application(MYSQL &, Ndb_cluster_connection &);
|
||||||
|
|
||||||
|
#define PRINT_ERROR(code,msg) \
|
||||||
|
std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
|
||||||
|
<< ", code: " << code \
|
||||||
|
<< ", msg: " << msg << "." << std::endl
|
||||||
|
#define MYSQLERROR(mysql) { \
|
||||||
|
PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
|
||||||
|
exit(-1); }
|
||||||
|
#define APIERROR(error) { \
|
||||||
|
PRINT_ERROR(error.code,error.message); \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// ndb_init must be called first
|
||||||
|
ndb_init();
|
||||||
|
|
||||||
|
// connect to mysql server and cluster and run application
|
||||||
|
{
|
||||||
|
// Object representing the cluster
|
||||||
|
Ndb_cluster_connection cluster_connection;
|
||||||
|
|
||||||
|
// Connect to cluster management server (ndb_mgmd)
|
||||||
|
if (cluster_connection.connect(4 /* retries */,
|
||||||
|
5 /* delay between retries */,
|
||||||
|
1 /* verbose */))
|
||||||
|
{
|
||||||
|
std::cout << "Cluster management server was not ready within 30 secs.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally connect and wait for the storage nodes (ndbd's)
|
||||||
|
if (cluster_connection.wait_until_ready(30,0) < 0)
|
||||||
|
{
|
||||||
|
std::cout << "Cluster was not ready within 30 secs.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to mysql server
|
||||||
|
MYSQL mysql;
|
||||||
|
if ( !mysql_init(&mysql) ) {
|
||||||
|
std::cout << "mysql_init failed\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
|
||||||
|
3306, "/tmp/mysql.sock", 0) )
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
// run the application code
|
||||||
|
run_application(mysql, cluster_connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
ndb_end(0);
|
||||||
|
|
||||||
|
std::cout << "\nTo drop created table use:\n"
|
||||||
|
<< "echo \"drop table MYTABLENAME\" | mysql TEST_DB_1 -u root\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_table(MYSQL &);
|
||||||
|
static void do_insert(Ndb &);
|
||||||
|
static void do_update(Ndb &);
|
||||||
|
static void do_delete(Ndb &);
|
||||||
|
static void do_read(Ndb &);
|
||||||
|
|
||||||
|
static void run_application(MYSQL &mysql,
|
||||||
|
Ndb_cluster_connection &cluster_connection)
|
||||||
|
{
|
||||||
|
/********************************************
|
||||||
|
* Connect to database via mysql-c *
|
||||||
|
********************************************/
|
||||||
|
mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
|
||||||
|
if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
|
||||||
|
create_table(mysql);
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Connect to database via NdbApi *
|
||||||
|
********************************************/
|
||||||
|
// Object representing the database
|
||||||
|
Ndb myNdb( &cluster_connection, "TEST_DB_1" );
|
||||||
|
if (myNdb.init()) APIERROR(myNdb.getNdbError());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do different operations on database
|
||||||
|
*/
|
||||||
|
do_insert(myNdb);
|
||||||
|
do_update(myNdb);
|
||||||
|
do_delete(myNdb);
|
||||||
|
do_read(myNdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************
|
||||||
|
* Create a table named MYTABLENAME if it does not exist *
|
||||||
|
*********************************************************/
|
||||||
|
static void create_table(MYSQL &mysql)
|
||||||
|
{
|
||||||
|
if (mysql_query(&mysql,
|
||||||
|
"CREATE TABLE"
|
||||||
|
" MYTABLENAME"
|
||||||
|
" (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
|
||||||
|
" ATTR2 INT UNSIGNED NOT NULL)"
|
||||||
|
" ENGINE=NDB"))
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
|
||||||
|
**************************************************************************/
|
||||||
|
static void do_insert(Ndb &myNdb)
|
||||||
|
{
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
NdbTransaction *myTransaction= myNdb.startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->insertTuple();
|
||||||
|
myOperation->equal("ATTR1", i);
|
||||||
|
myOperation->setValue("ATTR2", i);
|
||||||
|
|
||||||
|
myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->insertTuple();
|
||||||
|
myOperation->equal("ATTR1", i+5);
|
||||||
|
myOperation->setValue("ATTR2", i+5);
|
||||||
|
|
||||||
|
if (myTransaction->execute( NdbTransaction::Commit ) == -1)
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb.closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* Update the second attribute in half of the tuples (adding 10) *
|
||||||
|
*****************************************************************/
|
||||||
|
static void do_update(Ndb &myNdb)
|
||||||
|
{
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i+=2) {
|
||||||
|
NdbTransaction *myTransaction= myNdb.startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->updateTuple();
|
||||||
|
myOperation->equal( "ATTR1", i );
|
||||||
|
myOperation->setValue( "ATTR2", i+10);
|
||||||
|
|
||||||
|
if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb.closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
* Delete one tuple (the one with primary key 3) *
|
||||||
|
*************************************************/
|
||||||
|
static void do_delete(Ndb &myNdb)
|
||||||
|
{
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
NdbTransaction *myTransaction= myNdb.startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->deleteTuple();
|
||||||
|
myOperation->equal( "ATTR1", 3 );
|
||||||
|
|
||||||
|
if (myTransaction->execute(NdbTransaction::Commit) == -1)
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb.closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Read and print all tuples *
|
||||||
|
*****************************/
|
||||||
|
static void do_read(Ndb &myNdb)
|
||||||
|
{
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
std::cout << "ATTR1 ATTR2" << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
NdbTransaction *myTransaction= myNdb.startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->readTuple(NdbOperation::LM_Read);
|
||||||
|
myOperation->equal("ATTR1", i);
|
||||||
|
|
||||||
|
NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
|
||||||
|
if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
if(myTransaction->execute( NdbTransaction::Commit ) == -1)
|
||||||
|
if (i == 3) {
|
||||||
|
std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
|
||||||
|
} else {
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != 3) {
|
||||||
|
printf(" %2d %2d\n", i, myRecAttr->u_32_value());
|
||||||
|
}
|
||||||
|
myNdb.closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,254 @@
|
|||||||
|
/* 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_simple_index.cpp: Using secondary indexes in NDB API
|
||||||
|
//
|
||||||
|
// Correct output from this program is:
|
||||||
|
//
|
||||||
|
// ATTR1 ATTR2
|
||||||
|
// 0 10
|
||||||
|
// 1 1
|
||||||
|
// 2 12
|
||||||
|
// Detected that deleted tuple doesn't exist!
|
||||||
|
// 4 14
|
||||||
|
// 5 5
|
||||||
|
// 6 16
|
||||||
|
// 7 7
|
||||||
|
// 8 18
|
||||||
|
// 9 9
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
|
||||||
|
// Used for cout
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define PRINT_ERROR(code,msg) \
|
||||||
|
std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
|
||||||
|
<< ", code: " << code \
|
||||||
|
<< ", msg: " << msg << "." << std::endl
|
||||||
|
#define MYSQLERROR(mysql) { \
|
||||||
|
PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
|
||||||
|
exit(-1); }
|
||||||
|
#define APIERROR(error) { \
|
||||||
|
PRINT_ERROR(error.code,error.message); \
|
||||||
|
exit(-1); }
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ndb_init();
|
||||||
|
MYSQL mysql;
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to mysql server and create table *
|
||||||
|
**************************************************************/
|
||||||
|
{
|
||||||
|
if ( !mysql_init(&mysql) ) {
|
||||||
|
std::cout << "mysql_init failed\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
|
||||||
|
3306, "/tmp/mysql.sock", 0) )
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
|
||||||
|
if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
if (mysql_query(&mysql,
|
||||||
|
"CREATE TABLE"
|
||||||
|
" MYTABLENAME"
|
||||||
|
" (ATTR1 INT UNSIGNED,"
|
||||||
|
" ATTR2 INT UNSIGNED NOT NULL,"
|
||||||
|
" PRIMARY KEY USING HASH (ATTR1),"
|
||||||
|
" UNIQUE MYINDEXNAME USING HASH (ATTR2))"
|
||||||
|
" ENGINE=NDB"))
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Connect to ndb cluster *
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
Ndb_cluster_connection *cluster_connection=
|
||||||
|
new Ndb_cluster_connection(); // Object representing the cluster
|
||||||
|
|
||||||
|
if (cluster_connection->connect(5,3,1))
|
||||||
|
{
|
||||||
|
std::cout << "Connect to cluster management server failed.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cluster_connection->wait_until_ready(30,30))
|
||||||
|
{
|
||||||
|
std::cout << "Cluster was not ready within 30 secs.\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ndb* myNdb = new Ndb( cluster_connection,
|
||||||
|
"TEST_DB_1" ); // Object representing the database
|
||||||
|
if (myNdb->init() == -1) {
|
||||||
|
APIERROR(myNdb->getNdbError());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
|
||||||
|
const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
|
||||||
|
if (myTable == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
const NdbDictionary::Index *myIndex= myDict->getIndex("MYINDEXNAME","MYTABLENAME");
|
||||||
|
if (myIndex == NULL)
|
||||||
|
APIERROR(myDict->getNdbError());
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
|
||||||
|
**************************************************************************/
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
NdbTransaction *myTransaction= myNdb->startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->insertTuple();
|
||||||
|
myOperation->equal("ATTR1", i);
|
||||||
|
myOperation->setValue("ATTR2", i);
|
||||||
|
|
||||||
|
myOperation = myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->insertTuple();
|
||||||
|
myOperation->equal("ATTR1", i+5);
|
||||||
|
myOperation->setValue("ATTR2", i+5);
|
||||||
|
|
||||||
|
if (myTransaction->execute( NdbTransaction::Commit ) == -1)
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb->closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************
|
||||||
|
* Read and print all tuples using index *
|
||||||
|
*****************************************/
|
||||||
|
std::cout << "ATTR1 ATTR2" << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
NdbTransaction *myTransaction= myNdb->startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
NdbIndexOperation *myIndexOperation=
|
||||||
|
myTransaction->getNdbIndexOperation(myIndex);
|
||||||
|
if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myIndexOperation->readTuple(NdbOperation::LM_Read);
|
||||||
|
myIndexOperation->equal("ATTR2", i);
|
||||||
|
|
||||||
|
NdbRecAttr *myRecAttr= myIndexOperation->getValue("ATTR1", NULL);
|
||||||
|
if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
if(myTransaction->execute( NdbTransaction::Commit ) != -1)
|
||||||
|
printf(" %2d %2d\n", myRecAttr->u_32_value(), i);
|
||||||
|
|
||||||
|
myNdb->closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* Update the second attribute in half of the tuples (adding 10) *
|
||||||
|
*****************************************************************/
|
||||||
|
for (int i = 0; i < 10; i+=2) {
|
||||||
|
NdbTransaction *myTransaction= myNdb->startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
NdbIndexOperation *myIndexOperation=
|
||||||
|
myTransaction->getNdbIndexOperation(myIndex);
|
||||||
|
if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myIndexOperation->updateTuple();
|
||||||
|
myIndexOperation->equal( "ATTR2", i );
|
||||||
|
myIndexOperation->setValue( "ATTR2", i+10);
|
||||||
|
|
||||||
|
if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb->closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
* Delete one tuple (the one with primary key 3) *
|
||||||
|
*************************************************/
|
||||||
|
{
|
||||||
|
NdbTransaction *myTransaction= myNdb->startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
NdbIndexOperation *myIndexOperation=
|
||||||
|
myTransaction->getNdbIndexOperation(myIndex);
|
||||||
|
if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myIndexOperation->deleteTuple();
|
||||||
|
myIndexOperation->equal( "ATTR2", 3 );
|
||||||
|
|
||||||
|
if (myTransaction->execute(NdbTransaction::Commit) == -1)
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myNdb->closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Read and print all tuples *
|
||||||
|
*****************************/
|
||||||
|
{
|
||||||
|
std::cout << "ATTR1 ATTR2" << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
NdbTransaction *myTransaction= myNdb->startTransaction();
|
||||||
|
if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
|
||||||
|
|
||||||
|
NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
|
||||||
|
if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
myOperation->readTuple(NdbOperation::LM_Read);
|
||||||
|
myOperation->equal("ATTR1", i);
|
||||||
|
|
||||||
|
NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
|
||||||
|
if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
|
||||||
|
|
||||||
|
if(myTransaction->execute( NdbTransaction::Commit ) == -1)
|
||||||
|
if (i == 3) {
|
||||||
|
std::cout << "Detected that deleted tuple doesn't exist!\n";
|
||||||
|
} else {
|
||||||
|
APIERROR(myTransaction->getNdbError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != 3) {
|
||||||
|
printf(" %2d %2d\n", i, myRecAttr->u_32_value());
|
||||||
|
}
|
||||||
|
myNdb->closeTransaction(myTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* Drop table *
|
||||||
|
**************/
|
||||||
|
if (mysql_query(&mysql, "DROP TABLE MYTABLENAME"))
|
||||||
|
MYSQLERROR(mysql);
|
||||||
|
|
||||||
|
delete myNdb;
|
||||||
|
delete cluster_connection;
|
||||||
|
|
||||||
|
ndb_end(0);
|
||||||
|
return 0;
|
||||||
|
}
|
19
storage/ndb/test/run-test/conf-daily-basic-ndb08.txt
Normal file
19
storage/ndb/test/run-test/conf-daily-basic-ndb08.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
baseport: 14000
|
||||||
|
basedir: /space/autotest
|
||||||
|
mgm: CHOOSE_host1
|
||||||
|
ndb: CHOOSE_host2 CHOOSE_host3 CHOOSE_host2 CHOOSE_host3
|
||||||
|
api: CHOOSE_host1 CHOOSE_host1 CHOOSE_host1
|
||||||
|
-- cluster config
|
||||||
|
[DB DEFAULT]
|
||||||
|
NoOfReplicas: 2
|
||||||
|
IndexMemory: 100M
|
||||||
|
DataMemory: 300M
|
||||||
|
BackupMemory: 64M
|
||||||
|
MaxNoOfConcurrentScans: 100
|
||||||
|
DataDir: .
|
||||||
|
FileSystemPath: /space/autotest/run
|
||||||
|
|
||||||
|
[MGM DEFAULT]
|
||||||
|
PortNumber: 14000
|
||||||
|
ArbitrationRank: 1
|
||||||
|
DataDir: .
|
19
storage/ndb/test/run-test/conf-daily-devel-ndb08.txt
Normal file
19
storage/ndb/test/run-test/conf-daily-devel-ndb08.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
baseport: 16000
|
||||||
|
basedir: /space/autotest
|
||||||
|
mgm: CHOOSE_host1
|
||||||
|
ndb: CHOOSE_host2 CHOOSE_host3 CHOOSE_host2 CHOOSE_host3
|
||||||
|
api: CHOOSE_host1 CHOOSE_host1 CHOOSE_host1
|
||||||
|
-- cluster config
|
||||||
|
[DB DEFAULT]
|
||||||
|
NoOfReplicas: 2
|
||||||
|
IndexMemory: 100M
|
||||||
|
DataMemory: 300M
|
||||||
|
BackupMemory: 64M
|
||||||
|
MaxNoOfConcurrentScans: 100
|
||||||
|
DataDir: .
|
||||||
|
FileSystemPath: /space/autotest/run
|
||||||
|
|
||||||
|
[MGM DEFAULT]
|
||||||
|
PortNumber: 16000
|
||||||
|
ArbitrationRank: 1
|
||||||
|
DataDir: .
|
20
storage/ndb/test/run-test/conf-daily-sql-ndb08.txt
Normal file
20
storage/ndb/test/run-test/conf-daily-sql-ndb08.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
baseport: 16000
|
||||||
|
basedir: /space/autotest
|
||||||
|
mgm: CHOOSE_host1
|
||||||
|
ndb: CHOOSE_host2 CHOOSE_host3
|
||||||
|
mysqld: CHOOSE_host1 CHOOSE_host4
|
||||||
|
mysql: CHOOSE_host1 CHOOSE_host1 CHOOSE_host1 CHOOSE_host1 CHOOSE_host1 CHOOSE_host1 CHOOSE_host4 CHOOSE_host4 CHOOSE_host4 CHOOSE_host4 CHOOSE_host4 CHOOSE_host4
|
||||||
|
-- cluster config
|
||||||
|
[DB DEFAULT]
|
||||||
|
NoOfReplicas: 2
|
||||||
|
IndexMemory: 100M
|
||||||
|
DataMemory: 300M
|
||||||
|
BackupMemory: 64M
|
||||||
|
MaxNoOfConcurrentScans: 100
|
||||||
|
DataDir: .
|
||||||
|
FileSystemPath: /space/autotest/run
|
||||||
|
|
||||||
|
[MGM DEFAULT]
|
||||||
|
PortNumber: 16000
|
||||||
|
ArbitrationRank: 1
|
||||||
|
DataDir: .
|
44
storage/ndb/test/sql/BANK.sql
Normal file
44
storage/ndb/test/sql/BANK.sql
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
CREATE DATABASE IF NOT EXISTS BANK default charset=latin1 default collate=latin1_bin;
|
||||||
|
USE BANK;
|
||||||
|
DROP TABLE IF EXISTS GL;
|
||||||
|
CREATE TABLE GL ( TIME BIGINT UNSIGNED NOT NULL,
|
||||||
|
ACCOUNT_TYPE INT UNSIGNED NOT NULL,
|
||||||
|
BALANCE INT UNSIGNED NOT NULL,
|
||||||
|
DEPOSIT_COUNT INT UNSIGNED NOT NULL,
|
||||||
|
DEPOSIT_SUM INT UNSIGNED NOT NULL,
|
||||||
|
WITHDRAWAL_COUNT INT UNSIGNED NOT NULL,
|
||||||
|
WITHDRAWAL_SUM INT UNSIGNED NOT NULL,
|
||||||
|
PURGED INT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY USING HASH (TIME,ACCOUNT_TYPE))
|
||||||
|
ENGINE = NDB;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS ACCOUNT;
|
||||||
|
CREATE TABLE ACCOUNT ( ACCOUNT_ID INT UNSIGNED NOT NULL,
|
||||||
|
OWNER INT UNSIGNED NOT NULL,
|
||||||
|
BALANCE INT UNSIGNED NOT NULL,
|
||||||
|
ACCOUNT_TYPE INT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY USING HASH (ACCOUNT_ID))
|
||||||
|
ENGINE = NDB;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS TRANSACTION;
|
||||||
|
CREATE TABLE TRANSACTION ( TRANSACTION_ID BIGINT UNSIGNED NOT NULL,
|
||||||
|
ACCOUNT INT UNSIGNED NOT NULL,
|
||||||
|
ACCOUNT_TYPE INT UNSIGNED NOT NULL,
|
||||||
|
OTHER_ACCOUNT INT UNSIGNED NOT NULL,
|
||||||
|
TRANSACTION_TYPE INT UNSIGNED NOT NULL,
|
||||||
|
TIME BIGINT UNSIGNED NOT NULL,
|
||||||
|
AMOUNT INT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY USING HASH (TRANSACTION_ID,ACCOUNT))
|
||||||
|
ENGINE = NDB;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS SYSTEM_VALUES;
|
||||||
|
CREATE TABLE SYSTEM_VALUES ( SYSTEM_VALUES_ID INT UNSIGNED NOT NULL,
|
||||||
|
VALUE BIGINT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY USING HASH (SYSTEM_VALUES_ID))
|
||||||
|
ENGINE = NDB;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS ACCOUNT_TYPE;
|
||||||
|
CREATE TABLE ACCOUNT_TYPE ( ACCOUNT_TYPE_ID INT UNSIGNED NOT NULL,
|
||||||
|
DESCRIPTION CHAR(64) NOT NULL,
|
||||||
|
PRIMARY KEY USING HASH (ACCOUNT_TYPE_ID))
|
||||||
|
ENGINE = NDB;
|
9
storage/ndb/test/sql/T1.sql
Normal file
9
storage/ndb/test/sql/T1.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
create database if not exists TEST_DB;
|
||||||
|
use TEST_DB;
|
||||||
|
drop table if exists T1;
|
||||||
|
create table T1 (KOL1 int unsigned not null,
|
||||||
|
KOL2 int unsigned not null,
|
||||||
|
KOL3 int unsigned not null,
|
||||||
|
KOL4 int unsigned not null,
|
||||||
|
KOL5 int unsigned not null,
|
||||||
|
primary key using hash(KOL1)) engine=ndb;
|
169
storage/ndb/test/tools/listen.cpp
Normal file
169
storage/ndb/test/tools/listen.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/* 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 */
|
||||||
|
|
||||||
|
|
||||||
|
#include <NdbOut.hpp>
|
||||||
|
#include <NdbApi.hpp>
|
||||||
|
#include <NdbSleep.h>
|
||||||
|
#include <NDBT.hpp>
|
||||||
|
#include <HugoTransactions.hpp>
|
||||||
|
#include <getarg.h>
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char** argv){
|
||||||
|
ndb_init();
|
||||||
|
|
||||||
|
|
||||||
|
int _help = 0;
|
||||||
|
const char* db = 0;
|
||||||
|
|
||||||
|
struct getargs args[] = {
|
||||||
|
{ "database", 'd', arg_string, &db, "Database", "" },
|
||||||
|
{ "usage", '?', arg_flag, &_help, "Print help", "" }
|
||||||
|
};
|
||||||
|
int num_args = sizeof(args) / sizeof(args[0]);
|
||||||
|
int optind = 0, i;
|
||||||
|
char desc[] =
|
||||||
|
"<tabname>+ \nThis program listen to events on specified tables\n";
|
||||||
|
|
||||||
|
if(getarg(args, num_args, argc, argv, &optind) ||
|
||||||
|
argv[optind] == NULL || _help) {
|
||||||
|
arg_printusage(args, num_args, argv[0], desc);
|
||||||
|
return NDBT_ProgramExit(NDBT_WRONGARGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to Ndb
|
||||||
|
Ndb_cluster_connection con;
|
||||||
|
if(con.connect(12, 5, 1) != 0)
|
||||||
|
{
|
||||||
|
return NDBT_ProgramExit(NDBT_FAILED);
|
||||||
|
}
|
||||||
|
Ndb MyNdb( &con, db ? db : "TEST_DB" );
|
||||||
|
|
||||||
|
if(MyNdb.init() != 0){
|
||||||
|
ERR(MyNdb.getNdbError());
|
||||||
|
return NDBT_ProgramExit(NDBT_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to Ndb and wait for it to become ready
|
||||||
|
while(MyNdb.waitUntilReady() != 0)
|
||||||
|
ndbout << "Waiting for ndb to become ready..." << endl;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
Uint64 last_gci= 0, cnt= 0;
|
||||||
|
|
||||||
|
NdbDictionary::Dictionary *myDict = MyNdb.getDictionary();
|
||||||
|
Vector<NdbDictionary::Event*> events;
|
||||||
|
Vector<NdbEventOperation*> event_ops;
|
||||||
|
for(i= optind; i<argc; i++)
|
||||||
|
{
|
||||||
|
const NdbDictionary::Table* table= myDict->getTable(argv[i]);
|
||||||
|
if(!table)
|
||||||
|
{
|
||||||
|
ndbout_c("Could not find table: %s, skipping", argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseString name;
|
||||||
|
name.appfmt("EV-%s", argv[i]);
|
||||||
|
NdbDictionary::Event *myEvent= new NdbDictionary::Event(name.c_str());
|
||||||
|
myEvent->setTable(table->getName());
|
||||||
|
myEvent->addTableEvent(NdbDictionary::Event::TE_ALL);
|
||||||
|
for(int a = 0; a < table->getNoOfColumns(); a++){
|
||||||
|
myEvent->addEventColumn(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myDict->createEvent(* myEvent))
|
||||||
|
{
|
||||||
|
if(myDict->getNdbError().classification == NdbError::SchemaObjectExists)
|
||||||
|
{
|
||||||
|
g_info << "Event creation failed event exists\n";
|
||||||
|
if (myDict->dropEvent(name.c_str()))
|
||||||
|
{
|
||||||
|
g_err << "Failed to drop event: " << myDict->getNdbError() << endl;
|
||||||
|
result = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
// try again
|
||||||
|
if (myDict->createEvent(* myEvent))
|
||||||
|
{
|
||||||
|
g_err << "Failed to create event: " << myDict->getNdbError() << endl;
|
||||||
|
result = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_err << "Failed to create event: " << myDict->getNdbError() << endl;
|
||||||
|
result = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.push_back(myEvent);
|
||||||
|
|
||||||
|
NdbEventOperation* pOp = MyNdb.createEventOperation(name.c_str());
|
||||||
|
if ( pOp == NULL ) {
|
||||||
|
g_err << "Event operation creation failed" << endl;
|
||||||
|
result = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int a = 0; a < table->getNoOfColumns(); a++)
|
||||||
|
{
|
||||||
|
pOp->getValue(table->getColumn(a)->getName());
|
||||||
|
pOp->getPreValue(table->getColumn(a)->getName());
|
||||||
|
}
|
||||||
|
event_ops.push_back(pOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i= 0; i<(int)event_ops.size(); i++)
|
||||||
|
{
|
||||||
|
if (event_ops[i]->execute())
|
||||||
|
{
|
||||||
|
g_err << "operation execution failed: " << event_ops[i]->getNdbError()
|
||||||
|
<< endl;
|
||||||
|
result = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
while(MyNdb.pollEvents(100) == 0);
|
||||||
|
|
||||||
|
NdbEventOperation* pOp;
|
||||||
|
while((pOp= MyNdb.nextEvent()) != 0)
|
||||||
|
{
|
||||||
|
if(pOp->getGCI() != last_gci)
|
||||||
|
{
|
||||||
|
if(cnt) ndbout_c("GCI: %lld events: %lld", last_gci, cnt);
|
||||||
|
cnt= 1;
|
||||||
|
last_gci= pOp->getGCI();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
return NDBT_ProgramExit(NDBT_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
template class Vector<NdbDictionary::Event*>;
|
||||||
|
template class Vector<NdbEventOperation*>;
|
Reference in New Issue
Block a user