From: jon
Date: September 5 2006 2:45am
Subject: svn commit - mysqldoc@docsrva: r3218 - trunk/ndbapi
List-Archive: http://lists.mysql.com/commits/11372
Message-Id: <200609050245.k852jCCn017416@docsrva.mysql.com>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Author: jstephens
Date: 2006-09-05 04:45:07 +0200 (Tue, 05 Sep 2006)
New Revision: 3218
Log:
Added new example - using transactions & accessing multple clusters
Modified:
trunk/ndbapi/examples.xml
trunk/ndbapi/ndb-classes.xml
Modified: trunk/ndbapi/examples.xml
===================================================================
--- trunk/ndbapi/examples.xml 2006-09-04 17:30:05 UTC (rev 3217)
+++ trunk/ndbapi/examples.xml 2006-09-05 02:45:07 UTC (rev 3218)
Changed blocks: 1, Lines Added: 371, Lines Deleted: 0; 12171 bytes
@@ -2246,4 +2246,375 @@
+
+
+ Using Synchronous Transactions and Multiple Clusters
+
+
+ transactions
+ example
+
+
+
+ connecting to multiple clusters
+ example
+
+
+
+ multiple clusters, connecting to
+ example
+
+
+
+
+
+ This example demonstrates synchronous transactions and
+ connecting to multiple clusters in a single NDB API application.
+
+
+
+ The source code for this program may be found in the MySQL 5.1
+ source tree, in the file
+ storage/ndb/ndbapi-examples/ndbapi_simple_dual/ndbapi_simple_dual.cpp.
+
+
+
+
+
+/*
+ * ndbapi_simple_dual.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
+ * 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 &, const char* table, const char* db);
+
+#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(int argc, char** argv)
+{
+ if (argc != 5)
+ {
+ std::cout << "Arguments are <socket mysqld1> <connect_string cluster 1> <socket mysqld2> <connect_string cluster 2>.\n";
+ exit(-1);
+ }
+ // ndb_init must be called first
+ ndb_init();
+ {
+ char * mysqld1_sock = argv[1];
+ const char *connectstring1 = argv[2];
+ char * mysqld2_sock = argv[3];
+ const char *connectstring2 = argv[4];
+
+ // Object representing the cluster 1
+ Ndb_cluster_connection cluster1_connection(connectstring1);
+ MYSQL mysql1;
+ // Object representing the cluster 2
+ Ndb_cluster_connection cluster2_connection(connectstring2);
+ MYSQL mysql2;
+
+ // connect to mysql server and cluster 1 and run application
+ // Connect to cluster 1 management server (ndb_mgmd)
+ if (cluster1_connection.connect(4 /* retries */,
+ 5 /* delay between retries */,
+ 1 /* verbose */))
+ {
+ std::cout << "Cluster 1 management server was not ready within 30 secs.\n";
+ exit(-1);
+ }
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster1_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster 1 was not ready within 30 secs.\n";
+ exit(-1);
+ }
+ // connect to mysql server in cluster 1
+ if ( !mysql_init(&mysql1) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql1, "localhost", "root", "", "",
+ 0, mysqld1_sock, 0) )
+ MYSQLERROR(mysql1);
+
+
+ // connect to mysql server and cluster 2 and run application
+
+ // Connect to cluster management server (ndb_mgmd)
+ if (cluster2_connection.connect(4 /* retries */,
+ 5 /* delay between retries */,
+ 1 /* verbose */))
+ {
+ std::cout << "Cluster 2 management server was not ready within 30 secs.\n";
+ exit(-1);
+ }
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster2_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster 2 was not ready within 30 secs.\n";
+ exit(-1);
+ }
+ // connect to mysql server in cluster 2
+ if ( !mysql_init(&mysql2) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql2, "localhost", "root", "", "",
+ 0, mysqld2_sock, 0) )
+ MYSQLERROR(mysql2);
+
+ // run the application code
+ run_application(mysql1, cluster1_connection, "MYTABLENAME1", "TEST_DB_1");
+ run_application(mysql2, cluster2_connection, "MYTABLENAME2", "TEST_DB_2");
+ }
+ // Note: all connections must have been destroyed before calling ndb_end()
+ ndb_end(0);
+
+ return 0;
+}
+
+static void create_table(MYSQL &, const char* table);
+static void drop_table(MYSQL &, const char* table);
+static void do_insert(Ndb &, const char* table);
+static void do_update(Ndb &, const char* table);
+static void do_delete(Ndb &, const char* table);
+static void do_read(Ndb &, const char* table);
+
+static void run_application(MYSQL &mysql,
+ Ndb_cluster_connection &cluster_connection,
+ const char* table,
+ const char* db)
+{
+ /********************************************
+ * Connect to database via mysql-c *
+ ********************************************/
+ char db_stmt[256];
+ sprintf(db_stmt, "CREATE DATABASE %s\n", db);
+ mysql_query(&mysql, db_stmt);
+ sprintf(db_stmt, "USE %s", db);
+ if (mysql_query(&mysql, db_stmt) != 0) MYSQLERROR(mysql);
+ create_table(mysql, table);
+
+ /********************************************
+ * Connect to database via NdbApi *
+ ********************************************/
+ // Object representing the database
+ Ndb myNdb( &cluster_connection, db );
+ if (myNdb.init()) APIERROR(myNdb.getNdbError());
+
+ /*
+ * Do different operations on database
+ */
+ do_insert(myNdb, table);
+ do_update(myNdb, table);
+ do_delete(myNdb, table);
+ do_read(myNdb, table);
+ /*
+ * Drop the table
+ */
+ drop_table(mysql, table);
+ sprintf(db_stmt, "DROP DATABASE %s\n", db);
+ mysql_query(&mysql, db_stmt);
+}
+
+/*********************************************************
+ * Create a table named by table if it does not exist *
+ *********************************************************/
+static void create_table(MYSQL &mysql, const char* table)
+{
+ char create_stmt[256];
+
+ sprintf(create_stmt, "CREATE TABLE %s \
+ (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,\
+ ATTR2 INT UNSIGNED NOT NULL)\
+ ENGINE=NDB", table);
+ if (mysql_query(&mysql, create_stmt))
+ MYSQLERROR(mysql);
+}
+
+/*******************************
+ * Drop a table named by table
+ *******************************/
+static void drop_table(MYSQL &mysql, const char* table)
+{
+ char drop_stmt[256];
+
+ sprintf(drop_stmt, "DROP TABLE IF EXISTS %s", table);
+ if (mysql_query(&mysql, drop_stmt))
+ MYSQLERROR(mysql);
+}
+
+/**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+static void do_insert(Ndb &myNdb, const char* table)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable(table);
+
+ 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 char* table)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable(table);
+
+ 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 char* table)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable(table);
+
+ 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 char* table)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable(table);
+
+ 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);
+ }
+}
+
+
+
+
Modified: trunk/ndbapi/ndb-classes.xml
===================================================================
--- trunk/ndbapi/ndb-classes.xml 2006-09-04 17:30:05 UTC (rev 3217)
+++ trunk/ndbapi/ndb-classes.xml 2006-09-05 02:45:07 UTC (rev 3218)
Changed blocks: 2, Lines Added: 7, Lines Deleted: 1; 1004 bytes
@@ -1652,6 +1652,12 @@
cluster, and any movement of data between clusters must be
accomplished on the application level.
+
+
+ For an example demonstrating how connections to two different
+ clusters can be made in a single application, see
+ .
+
@@ -8699,7 +8705,7 @@
defined as the number of significant digits; for more
information, see the discussion of the
DECIMAL datatype in
- , in the MySQL Manual.
+ , in the MySQL Manual.