diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index 33744cc0f5110ad3115cc0b8fae59ac566cfe50a..0c84db8c068978927f93c39f5ec3ed4e0f2a78ef 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -30,7 +30,8 @@ testSystemRestart \
 testTimeout \
 testTransactions \
 testDeadlock \
-test_event ndbapi_slow_select testReadPerf testLcp
+test_event ndbapi_slow_select testReadPerf testLcp \
+DbCreate DbAsyncGenerator
 
 #flexTimedAsynch
 #testBlobs
@@ -69,6 +70,8 @@ test_event_SOURCES = test_event.cpp
 ndbapi_slow_select_SOURCES = slow_select.cpp
 testReadPerf_SOURCES = testReadPerf.cpp
 testLcp_SOURCES = testLcp.cpp
+DbCreate_SOURCES= bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp
+DbAsyncGenerator_SOURCES= bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp
 
 INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
 
diff --git a/ndb/test/ndbapi/bench/asyncGenerator.cpp b/ndb/test/ndbapi/bench/asyncGenerator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d91e38dff1a9542fea3cb62c4e28f7c3937d2cce
--- /dev/null
+++ b/ndb/test/ndbapi/bench/asyncGenerator.cpp
@@ -0,0 +1,571 @@
+/* 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 */
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include <ndb_global.h>
+
+#include "dbGenerator.h"
+#include <NdbApi.hpp>
+#include <NdbOut.hpp>
+#include <NdbSleep.h>
+
+/***************************************************************
+* L O C A L   C O N S T A N T S                                *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   D A T A   S T R U C T U R E S                    *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   F U N C T I O N S                                *
+***************************************************************/
+
+static void getRandomSubscriberNumber(SubscriberNumber number);
+static void getRandomServerId(ServerId *serverId);
+static void getRandomChangedBy(ChangedBy changedBy);
+static void getRandomChangedTime(ChangedTime changedTime);
+
+static void clearTransaction(TransactionDefinition *trans);
+static void initGeneratorStatistics(GeneratorStatistics *gen);
+
+static void doOneTransaction(ThreadData * td, 
+			     int parallellism,
+			     int millisSendPoll,
+			     int minEventSendPoll,
+			     int forceSendPoll);
+static void doTransaction_T1(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T2(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T3(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T4(Ndb * pNDB, ThreadData * td, int async);
+static void doTransaction_T5(Ndb * pNDB, ThreadData * td, int async);
+
+/***************************************************************
+* L O C A L   D A T A                                          *
+***************************************************************/
+
+static SequenceValues transactionDefinition[] = {
+   {25, 1},
+   {25, 2},
+   {20, 3},
+   {15, 4},
+   {15, 5},
+   {0,  0}
+};
+
+static SequenceValues rollbackDefinition[] = {
+   {98, 0},
+   {2 , 1},
+   {0,  0}
+};
+
+static int maxsize = 0;
+
+/***************************************************************
+* P U B L I C   D A T A                                        *
+***************************************************************/
+
+/***************************************************************
+****************************************************************
+* L O C A L   F U N C T I O N S   C O D E   S E C T I O N      *
+****************************************************************
+***************************************************************/
+
+static void getRandomSubscriberNumber(SubscriberNumber number)
+{
+   uint32 tmp;
+   char sbuf[SUBSCRIBER_NUMBER_LENGTH + 1];
+   tmp = myRandom48(NO_OF_SUBSCRIBERS);
+   sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_LENGTH, tmp);
+   memcpy(number, sbuf, SUBSCRIBER_NUMBER_LENGTH);
+}
+
+static void getRandomServerId(ServerId *serverId)
+{
+   *serverId = myRandom48(NO_OF_SERVERS);
+}
+
+static void getRandomChangedBy(ChangedBy changedBy)
+{
+   memset(changedBy, myRandom48(26)+'A', CHANGED_BY_LENGTH);
+   changedBy[CHANGED_BY_LENGTH] = 0;
+}
+
+static void getRandomChangedTime(ChangedTime changedTime)
+{
+   memset(changedTime, myRandom48(26)+'A', CHANGED_TIME_LENGTH);
+   changedTime[CHANGED_TIME_LENGTH] = 0;
+}
+
+static void clearTransaction(TransactionDefinition *trans)
+{
+  trans->count            = 0;
+  trans->branchExecuted   = 0;
+  trans->rollbackExecuted = 0;
+  trans->latencyCounter   = myRandom48(127);
+  trans->latency.reset();
+}
+
+static int listFull(SessionList *list)
+{
+   return(list->numberInList == SESSION_LIST_LENGTH);
+}
+
+static int listEmpty(SessionList *list)
+{
+   return(list->numberInList == 0);
+}
+
+static void insertSession(SessionList     *list, 
+                          SubscriberNumber number,
+                          ServerId         serverId)
+{
+   SessionElement *e;
+   if( listFull(list) ) return;
+
+   e = &list->list[list->writeIndex];
+
+   strcpy(e->subscriberNumber, number);
+   e->serverId = serverId;
+
+   list->writeIndex = (list->writeIndex + 1) % SESSION_LIST_LENGTH;
+   list->numberInList++;
+
+   if( list->numberInList > maxsize )
+     maxsize = list->numberInList;
+}
+
+static SessionElement *getNextSession(SessionList *list)
+{
+   if( listEmpty(list) ) return(0);
+
+   return(&list->list[list->readIndex]);
+}
+
+static void deleteSession(SessionList *list)
+{
+   if( listEmpty(list) ) return;
+
+   list->readIndex = (list->readIndex + 1) % SESSION_LIST_LENGTH;
+   list->numberInList--;
+}
+
+static void initGeneratorStatistics(GeneratorStatistics *gen)
+{
+   int i;
+
+   if( initSequence(&gen->transactionSequence,
+                    transactionDefinition) != 0 ) {
+      ndbout_c("could not set the transaction types");
+      exit(0);
+   }
+
+   if( initSequence(&gen->rollbackSequenceT4,
+                    rollbackDefinition) != 0 ) {
+      ndbout_c("could not set the rollback sequence");
+      exit(0);
+   }
+
+   if( initSequence(&gen->rollbackSequenceT5,
+                    rollbackDefinition) != 0 ) {
+      ndbout_c("could not set the rollback sequence");
+      exit(0);
+   }
+
+   for(i = 0; i < NUM_TRANSACTION_TYPES; i++ )
+      clearTransaction(&gen->transactions[i]);
+
+   gen->totalTransactions = 0;
+
+   gen->activeSessions.numberInList = 0;
+   gen->activeSessions.readIndex    = 0;
+   gen->activeSessions.writeIndex   = 0;
+}
+
+
+static 
+void 
+doOneTransaction(ThreadData * td, int p, int millis, int minEvents, int force)
+{
+  int i;
+  unsigned int transactionType;
+  int async = 1;
+  if (p == 1) {
+    async = 0;
+  }//if
+  for(i = 0; i<p; i++){
+    if(td[i].runState == Runnable){
+      transactionType = getNextRandom(&td[i].generator.transactionSequence);
+
+      switch(transactionType) {
+      case 1:
+	doTransaction_T1(td[i].pNDB, &td[i], async);
+	break;
+      case 2:
+	doTransaction_T2(td[i].pNDB, &td[i], async);
+	break;
+      case 3:
+	doTransaction_T3(td[i].pNDB, &td[i], async);
+	break;
+      case 4:
+	doTransaction_T4(td[i].pNDB, &td[i], async);
+	break;
+      case 5:
+	doTransaction_T5(td[i].pNDB, &td[i], async);
+	break;
+      default:
+	ndbout_c("Unknown transaction type: %d", transactionType);
+      }
+    }
+  }
+  if (async == 1) {
+    td[0].pNDB->sendPollNdb(millis, minEvents, force);
+  }//if
+}  
+
+static 
+void 
+doTransaction_T1(Ndb * pNDB, ThreadData * td, int async)
+{
+  /*----------------*/
+  /* Init arguments */
+  /*----------------*/
+  getRandomSubscriberNumber(td->transactionData.number);
+  getRandomChangedBy(td->transactionData.changed_by);
+  BaseString::snprintf(td->transactionData.changed_time,
+	   sizeof(td->transactionData.changed_time),
+	   "%ld - %d", td->changedTime++, myRandom48(65536*1024));
+  //getRandomChangedTime(td->transactionData.changed_time);
+  td->transactionData.location = td->transactionData.changed_by[0];
+  
+  /*-----------------*/
+  /* Run transaction */
+  /*-----------------*/
+  td->runState = Running;
+  td->generator.transactions[0].startLatency();
+
+  start_T1(pNDB, td, async);
+}
+
+static
+void 
+doTransaction_T2(Ndb * pNDB, ThreadData * td, int async)
+{
+  /*----------------*/
+  /* Init arguments */
+  /*----------------*/
+  getRandomSubscriberNumber(td->transactionData.number);
+
+  /*-----------------*/
+  /* Run transaction */
+  /*-----------------*/
+  td->runState = Running;
+  td->generator.transactions[1].startLatency();
+
+  start_T2(pNDB, td, async);
+}
+
+static
+void 
+doTransaction_T3(Ndb * pNDB, ThreadData * td, int async)
+{
+  SessionElement  *se;
+  
+  /*----------------*/
+  /* Init arguments */
+  /*----------------*/
+  se = getNextSession(&td->generator.activeSessions);
+  if( se ) {
+    strcpy(td->transactionData.number, se->subscriberNumber);
+    td->transactionData.server_id = se->serverId;
+    td->transactionData.sessionElement = 1;
+  } else {
+    getRandomSubscriberNumber(td->transactionData.number);
+    getRandomServerId(&td->transactionData.server_id);
+    td->transactionData.sessionElement = 0;
+  }
+  
+  td->transactionData.server_bit = (1 << td->transactionData.server_id);
+
+  /*-----------------*/
+  /* Run transaction */
+  /*-----------------*/
+  td->runState = Running;
+  td->generator.transactions[2].startLatency();
+  start_T3(pNDB, td, async);
+}
+
+static 
+void 
+doTransaction_T4(Ndb * pNDB, ThreadData * td, int async)
+{
+   /*----------------*/
+   /* Init arguments */
+   /*----------------*/
+  getRandomSubscriberNumber(td->transactionData.number);
+  getRandomServerId(&td->transactionData.server_id);
+  
+  td->transactionData.server_bit = (1 << td->transactionData.server_id);
+  td->transactionData.do_rollback = 
+    getNextRandom(&td->generator.rollbackSequenceT4);
+
+#if 0
+  memset(td->transactionData.session_details, 
+	 myRandom48(26)+'A', SESSION_DETAILS_LENGTH);
+#endif
+  td->transactionData.session_details[SESSION_DETAILS_LENGTH] = 0;
+  
+  /*-----------------*/
+  /* Run transaction */
+  /*-----------------*/
+  td->runState = Running;
+  td->generator.transactions[3].startLatency();
+  start_T4(pNDB, td, async);
+}
+
+static 
+void 
+doTransaction_T5(Ndb * pNDB, ThreadData * td, int async)
+{
+  SessionElement * se;
+  se = getNextSession(&td->generator.activeSessions);
+  if( se ) {
+    strcpy(td->transactionData.number, se->subscriberNumber);
+    td->transactionData.server_id = se->serverId;
+    td->transactionData.sessionElement = 1;
+  }
+  else {
+    getRandomSubscriberNumber(td->transactionData.number);
+    getRandomServerId(&td->transactionData.server_id);
+    td->transactionData.sessionElement = 0;
+  }
+  
+  td->transactionData.server_bit = (1 << td->transactionData.server_id);
+  td->transactionData.do_rollback  
+    = getNextRandom(&td->generator.rollbackSequenceT5);
+  
+  /*-----------------*/
+  /* Run transaction */
+  /*-----------------*/
+  td->runState = Running;
+  td->generator.transactions[4].startLatency();
+  start_T5(pNDB, td, async);
+}
+
+void
+complete_T1(ThreadData * data){
+  data->generator.transactions[0].stopLatency();
+  data->generator.transactions[0].count++;
+
+  data->runState = Runnable;
+  data->generator.totalTransactions++;
+}
+
+void 
+complete_T2(ThreadData * data){
+  data->generator.transactions[1].stopLatency();
+  data->generator.transactions[1].count++;
+
+  data->runState = Runnable;
+  data->generator.totalTransactions++;
+}
+
+void 
+complete_T3(ThreadData * data){
+
+  data->generator.transactions[2].stopLatency();
+  data->generator.transactions[2].count++;
+
+  if(data->transactionData.branchExecuted)
+    data->generator.transactions[2].branchExecuted++;
+
+  data->runState = Runnable;
+  data->generator.totalTransactions++;
+}
+
+void 
+complete_T4(ThreadData * data){
+
+  data->generator.transactions[3].stopLatency();
+  data->generator.transactions[3].count++;
+
+  if(data->transactionData.branchExecuted)
+    data->generator.transactions[3].branchExecuted++;
+  if(data->transactionData.do_rollback)
+    data->generator.transactions[3].rollbackExecuted++;
+  
+  if(data->transactionData.branchExecuted &&
+     !data->transactionData.do_rollback){
+    insertSession(&data->generator.activeSessions, 
+		  data->transactionData.number, 
+		  data->transactionData.server_id);
+  }
+
+  data->runState = Runnable;
+  data->generator.totalTransactions++;
+
+}
+void 
+complete_T5(ThreadData * data){
+
+  data->generator.transactions[4].stopLatency();
+  data->generator.transactions[4].count++;
+
+  if(data->transactionData.branchExecuted)
+    data->generator.transactions[4].branchExecuted++;
+  if(data->transactionData.do_rollback)
+    data->generator.transactions[4].rollbackExecuted++;
+  
+  if(data->transactionData.sessionElement && 
+     !data->transactionData.do_rollback){
+    deleteSession(&data->generator.activeSessions);
+  }
+  
+  data->runState = Runnable;
+  data->generator.totalTransactions++;
+}
+
+/***************************************************************
+****************************************************************
+* P U B L I C   F U N C T I O N S   C O D E   S E C T I O N    *
+****************************************************************
+***************************************************************/
+void 
+asyncGenerator(ThreadData *data, 
+	       int parallellism, 
+	       int millisSendPoll,
+	       int minEventSendPoll,
+	       int forceSendPoll)
+{
+  ThreadData * startUp;
+  
+  GeneratorStatistics *st;
+  double periodStop;
+  double benchTimeStart;
+  double benchTimeEnd;
+  int i, j, done;
+
+  myRandom48Init(data->randomSeed);
+  
+  for(i = 0; i<parallellism; i++){
+    initGeneratorStatistics(&data[i].generator);
+   }
+
+  startUp = (ThreadData*)malloc(parallellism * sizeof(ThreadData));
+  memcpy(startUp, data, (parallellism * sizeof(ThreadData)));
+  
+  /*----------------*/
+  /* warm up period */
+  /*----------------*/
+  periodStop = userGetTime() + (double)data[0].warmUpSeconds;
+  
+  while(userGetTime() < periodStop){
+    doOneTransaction(startUp, parallellism, 
+		     millisSendPoll, minEventSendPoll, forceSendPoll);
+  }
+  
+  ndbout_c("Waiting for startup to finish");
+
+  /**
+   * Wait for all transactions
+   */
+  done = 0;
+  while(!done){
+    done = 1;
+    for(i = 0; i<parallellism; i++){
+      if(startUp[i].runState != Runnable){
+	done = 0;
+	break;
+      }
+    }
+    if(!done){
+      startUp[0].pNDB->sendPollNdb();
+    }
+  }
+  ndbout_c("Benchmark period starts");
+
+  /*-------------------------*/
+  /* normal benchmark period */
+  /*-------------------------*/
+  benchTimeStart = userGetTime();
+  
+  periodStop = benchTimeStart + (double)data[0].testSeconds;
+  while(userGetTime() < periodStop)
+    doOneTransaction(data, parallellism,
+		     millisSendPoll, minEventSendPoll, forceSendPoll);  
+
+  benchTimeEnd = userGetTime();
+  
+  ndbout_c("Benchmark period done");
+
+  /**
+   * Wait for all transactions
+   */
+  done = 0;
+  while(!done){
+    done = 1;
+    for(i = 0; i<parallellism; i++){
+      if(data[i].runState != Runnable){
+	done = 0;
+	break;
+      }
+    }
+    if(!done){
+      data[0].pNDB->sendPollNdb();
+    }
+  }
+
+  /*------------------*/
+  /* cool down period */
+   /*------------------*/
+  periodStop = userGetTime() + (double)data[0].coolDownSeconds;
+  while(userGetTime() < periodStop){
+    doOneTransaction(startUp, parallellism,
+		     millisSendPoll, minEventSendPoll, forceSendPoll);
+  }
+
+  done = 0;
+  while(!done){
+    done = 1;
+    for(i = 0; i<parallellism; i++){
+      if(startUp[i].runState != Runnable){
+	done = 0;
+	break;
+      }
+    }
+    if(!done){
+      startUp[0].pNDB->sendPollNdb();
+    }
+  }
+
+
+  /*---------------------------------------------------------*/
+  /* add the times for all transaction for inner loop timing */
+  /*---------------------------------------------------------*/
+  for(j = 0; j<parallellism; j++){
+    st = &data[j].generator;
+    
+    st->outerLoopTime = benchTimeEnd - benchTimeStart;
+    st->outerTps      = getTps(st->totalTransactions, st->outerLoopTime);
+  }
+  /* ndbout_c("maxsize = %d\n",maxsize); */
+
+  free(startUp);
+}
+
diff --git a/ndb/test/ndbapi/bench/dbGenerator.h b/ndb/test/ndbapi/bench/dbGenerator.h
new file mode 100644
index 0000000000000000000000000000000000000000..2256498e15181183d66a0843f70177cfccc26523
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbGenerator.h
@@ -0,0 +1,63 @@
+/* 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 */
+
+#ifndef DBGENERATOR_H
+#define DBGENERATOR_H
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include "testData.h"
+#include "userInterface.h"
+
+/***************************************************************
+* M A C R O S                                                  *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C    F U N C T I O N S                             *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void asyncGenerator(ThreadData *d, int parallellism,
+			   int millisSendPoll, 
+			   int minEventSendPoll, 
+			   int forceSendPoll);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L   D A T A                                    *
+***************************************************************/
+
+
+
+#endif /* DBGENERATOR_H */
+
diff --git a/ndb/test/ndbapi/bench/dbPopulate.cpp b/ndb/test/ndbapi/bench/dbPopulate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..42fbb52f3b2a594eec3c2a29b6c03f4b3c40c716
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbPopulate.cpp
@@ -0,0 +1,244 @@
+/* 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 */
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include <ndb_global.h>
+
+#include "userInterface.h"
+
+#include "dbPopulate.h"
+#include <NdbOut.hpp>
+#include <random.h>
+
+/***************************************************************
+* L O C A L   C O N S T A N T S                                *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   D A T A   S T R U C T U R E S                    *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   F U N C T I O N S                                *
+***************************************************************/
+
+static void getRandomSubscriberData(int              subscriberNo, 
+		                    SubscriberNumber number,
+		                    SubscriberName   name);
+
+static void populate(char *title,
+                     int   count,
+                     void (*func)(UserHandle*,int),
+                     UserHandle *uh);
+
+static void populateServers(UserHandle *uh, int count);
+static void populateSubscribers(UserHandle *uh, int count);
+static void populateGroups(UserHandle *uh, int count);
+
+/***************************************************************
+* L O C A L   D A T A                                          *
+***************************************************************/
+
+static SequenceValues permissionsDefinition[] = {
+   {90, 1},
+   {10, 0},
+   {0,  0}
+};
+
+/***************************************************************
+* P U B L I C   D A T A                                        *
+***************************************************************/
+
+
+/***************************************************************
+****************************************************************
+* L O C A L   F U N C T I O N S   C O D E   S E C T I O N      *
+****************************************************************
+***************************************************************/
+
+static void getRandomSubscriberData(int              subscriberNo, 
+		                    SubscriberNumber number,
+		                    SubscriberName   name)
+{
+   char sbuf[SUBSCRIBER_NUMBER_LENGTH + 1];
+   sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_LENGTH, subscriberNo);
+   memcpy(number, sbuf, SUBSCRIBER_NUMBER_LENGTH);
+
+   memset(name, myRandom48(26)+'A', SUBSCRIBER_NAME_LENGTH);
+}
+
+static void populate(char *title,
+                     int   count,
+                     void (*func)(UserHandle*, int),
+                     UserHandle *uh)
+{
+   ndbout_c("Populating %d '%s' ... ",count, title);
+   /* fflush(stdout); */
+   func(uh,count);
+   ndbout_c("done");
+}
+
+static void populateServers(UserHandle *uh, int count)
+{
+   int  i, j;
+   int len;
+   char tmp[80];
+   int suffix_length = 1;
+   ServerName serverName;
+   SubscriberSuffix suffix;
+
+   int commitCount = 0;
+
+   for(i = 0; i < SUBSCRIBER_NUMBER_SUFFIX_LENGTH; i++)
+     suffix_length *= 10;
+
+   for(i = 0; i < count; i++) {
+      sprintf(tmp, "-Server %d-", i);
+
+      len = strlen(tmp);
+      for(j = 0; j < SERVER_NAME_LENGTH; j++){
+         serverName[j] = tmp[j % len];
+      }
+      /* serverName[j] = 0;	not null-terminated */
+
+      for(j = 0; j < suffix_length; j++){
+	 char sbuf[SUBSCRIBER_NUMBER_SUFFIX_LENGTH + 1];
+         sprintf(sbuf, "%.*d", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, j);
+	 memcpy(suffix, sbuf, SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+         userDbInsertServer(uh, i, suffix, serverName);
+	 commitCount ++;
+	 if((commitCount % OP_PER_TRANS) == 0)
+	   userDbCommit(uh);
+      }
+   }
+   if((commitCount % OP_PER_TRANS) != 0)
+     userDbCommit(uh);
+}
+
+static void populateSubscribers(UserHandle *uh, int count)
+{
+   SubscriberNumber number;
+   SubscriberName   name;
+   int i, j, k;
+   int res;
+
+   SequenceValues values[NO_OF_GROUPS+1];
+   RandomSequence seq;
+
+   for(i = 0; i < NO_OF_GROUPS; i++) {
+      values[i].length = 1;
+      values[i].value  = i;
+   }
+
+   values[i].length = 0;
+   values[i].value  = 0;
+
+   if( initSequence(&seq, values) != 0 ) {
+      ndbout_c("could not set the sequence of random groups");
+      exit(0);
+   }
+
+#define RETRIES 25
+
+   for(i = 0; i < count; i+= OP_PER_TRANS) {
+     for(j = 0; j<RETRIES; j++){
+       for(k = 0; k<OP_PER_TRANS && i+k < count; k++){
+	 getRandomSubscriberData(i+k, number, name);
+	 userDbInsertSubscriber(uh, number, getNextRandom(&seq), name);
+       }
+       res = userDbCommit(uh);
+       if(res == 0)
+	 break;
+       if(res != 1){
+	 ndbout_c("Terminating");
+	 exit(0);
+       }
+     }
+     if(j == RETRIES){
+       ndbout_c("Terminating");
+       exit(0);
+     }
+   }
+}
+
+static void populateGroups(UserHandle *uh, int count)
+{
+   int i;
+   int j;
+   int len;
+   RandomSequence seq;
+   Permission     allow[NO_OF_GROUPS];
+   ServerBit      serverBit;
+   GroupName      groupName;
+   char           tmp[80];
+   int commitCount = 0;
+
+   if( initSequence(&seq, permissionsDefinition) != 0 ) {
+      ndbout_c("could not set the sequence of random permissions");
+      exit(0);
+   }
+
+   for(i = 0; i < NO_OF_GROUPS; i++)
+      allow[i] = 0;
+
+   for(i = 0; i < NO_OF_SERVERS; i++) {
+      serverBit = 1 << i;
+
+      for(j = 0; j < NO_OF_GROUPS; j++ ) {
+         if( getNextRandom(&seq) )
+            allow[j] |= serverBit;
+      }
+   }
+
+   for(i = 0; i < NO_OF_GROUPS; i++) {
+      sprintf(tmp, "-Group %d-", i);
+
+      len = strlen(tmp);
+
+      for(j = 0; j < GROUP_NAME_LENGTH; j++) {
+        groupName[j] = tmp[j % len];
+      }
+      /* groupName[j] = 0;	not null-terminated */
+
+      userDbInsertGroup(uh,
+		        i,
+		        groupName,
+		        allow[i],
+		        allow[i],
+		        allow[i]);
+      commitCount ++;
+      if((commitCount % OP_PER_TRANS) == 0)
+	userDbCommit(uh);
+   }
+   if((commitCount % OP_PER_TRANS) != 0)
+     userDbCommit(uh);
+}
+
+/***************************************************************
+****************************************************************
+* P U B L I C   F U N C T I O N S   C O D E   S E C T I O N    *
+****************************************************************
+***************************************************************/
+
+void dbPopulate(UserHandle *uh)
+{
+   populate("servers", NO_OF_SERVERS, populateServers, uh);
+   populate("subscribers", NO_OF_SUBSCRIBERS, populateSubscribers, uh);
+   populate("groups", NO_OF_GROUPS, populateGroups, uh);
+}
diff --git a/ndb/test/ndbapi/bench/dbPopulate.h b/ndb/test/ndbapi/bench/dbPopulate.h
new file mode 100644
index 0000000000000000000000000000000000000000..1916720e141e5a4c2badbc24e68c820d5128c103
--- /dev/null
+++ b/ndb/test/ndbapi/bench/dbPopulate.h
@@ -0,0 +1,59 @@
+/* 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 */
+
+#ifndef DBPOPULATE_H
+#define DBPOPULATE_H
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include "userInterface.h"
+
+/***************************************************************
+* M A C R O S                                                  *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C    F U N C T I O N S                             *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void dbPopulate(UserHandle *uh);
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L   D A T A                                    *
+***************************************************************/
+
+
+
+#endif /* DBPOPULATE_H */
+
diff --git a/ndb/test/ndbapi/bench/macros.h b/ndb/test/ndbapi/bench/macros.h
new file mode 100644
index 0000000000000000000000000000000000000000..22b7f5644909db0a8a9214ac4ec4330e36000617
--- /dev/null
+++ b/ndb/test/ndbapi/bench/macros.h
@@ -0,0 +1,51 @@
+/* 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 */
+
+#ifndef MACROS_H
+#define MACROS_H
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+
+#define ERROR(x) {ndbout_c((x));}
+#define ERROR1(x,y) {ndbout_c((x), (y));}
+#define ERROR2(x,y,z) {ndbout_c((x), (y), (z));}
+#define ERROR3(x,y,z,u) {ndbout_c((x), (y), (z), (u));}
+#define ERROR4(x,y,z,u,w) {ndbout_c((x), (y), (z), (u), (w));}
+
+#define INIT_RANDOM(x) srand48((x))
+#define UI_RANDOM(x)   ((unsigned int)(lrand48()%(x)))
+
+#define ASSERT(cond, message) \
+  { if(!(cond)) { ERROR(message); exit(-1); }}
+
+#ifdef DEBUG_ON
+#define DEBUG(x) {ndbout_c((x));}
+#define DEBUG1(x,y) {ndbout_c((x), (y));}
+#define DEBUG2(x,y,z) {ndbout_c((x), (y), (z));}
+#define DEBUG3(x,y,z,u) {ndbout_c((x), (y), (z), (u));}
+#define DEBUG4(x,y,z,u,w) {ndbout_c((x), (y), (z), (u), (w));}
+#define DEBUG5(x,y,z,u,w, v) {ndbout_c((x), (y), (z), (u), (w), (v));}
+#else
+#define DEBUG(x)
+#define DEBUG1(x,y)
+#define DEBUG2(x,y,z)
+#define DEBUG3(x,y,z,u)
+#define DEBUG4(x,y,z,u,w)
+#define DEBUG5(x,y,z,u,w, v)
+#endif
+
+#endif
diff --git a/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp b/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..828b924582fdcd0a80a1e2cbe4084b9ea0239894
--- /dev/null
+++ b/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp
@@ -0,0 +1,503 @@
+/* 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 <ndb_global.h>
+
+#include <NdbHost.h>
+#include <NdbSleep.h>
+#include <NdbThread.h>
+#include <NdbMain.h>
+#include <NdbOut.hpp>
+#include <NdbEnv.h>
+#include <NdbTest.hpp>
+
+#include "userInterface.h"
+#include "dbGenerator.h"
+
+static int   numProcesses;
+static int   numSeconds;
+static int   numWarmSeconds;
+static int   parallellism;
+static int   millisSendPoll;
+static int   minEventSendPoll;
+static int   forceSendPoll;
+
+static ThreadData *data;
+static Ndb_cluster_connection *g_cluster_connection= 0;
+
+
+static void usage(const char *prog)
+{
+  const char  *progname;
+
+   /*--------------------------------------------*/
+   /* Get the name of the program (without path) */
+   /*--------------------------------------------*/
+   progname = strrchr(prog, '/');
+
+   if (progname == 0)
+     progname = prog;
+   else
+     ++progname;
+
+   ndbout_c(
+           "Usage: %s [-proc <num>] [-warm <num>] [-time <num>] [ -p <num>] " 
+	   "[-t <num> ] [ -e <num> ] [ -f <num>] \n"
+           "  -proc <num>    Specifies that <num> is the number of\n"
+           "                 threads. The default is 1.\n"
+           "  -time <num>    Specifies that the test will run for <num> sec.\n"
+           "                 The default is 10 sec\n"
+           "  -warm <num>    Specifies the warm-up/cooldown period of <num> "
+	   "sec.\n"
+           "                 The default is 10 sec\n"
+	   "  -p <num>       The no of parallell transactions started by "
+	   "one thread\n"
+	   "  -e <num>       Minimum no of events before wake up in call to "
+	   "sendPoll\n"
+	   "                 Default is 1\n"
+	   "  -f <num>       force parameter to sendPoll\n"
+	   "                 Default is 0\n",
+           progname);
+}
+
+static
+int
+parse_args(int argc, const char **argv)
+{
+   int i;
+
+   numProcesses     = 1;
+   numSeconds       = 10;
+   numWarmSeconds   = 10;
+   parallellism     = 1;
+   millisSendPoll   = 10000;
+   minEventSendPoll = 1;
+   forceSendPoll    = 0;
+   
+
+   i = 1;
+   while (i < argc){
+     if (strcmp("-proc",argv[i]) == 0) {
+       if (i + 1 >= argc) {
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &numProcesses) == -1 ||
+	   numProcesses <= 0 || numProcesses > 127) {
+	 ndbout_c("-proc flag requires a positive integer argument [1..127]");
+	 return 1;
+       }
+       i += 2;
+     } else if (strcmp("-p", argv[i]) == 0){
+       if(i + 1 >= argc){
+	 usage(argv[0]);
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &parallellism) == -1 ||
+	   parallellism <= 0){
+	 ndbout_c("-p flag requires a positive integer argument");
+	 return 1;
+       }
+       i += 2;
+     }
+     else if (strcmp("-time",argv[i]) == 0) {
+       if (i + 1 >= argc) {
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &numSeconds) == -1 ||
+	   numSeconds < 0) {
+	 ndbout_c("-time flag requires a positive integer argument");
+	 return 1;
+       }
+       i += 2;
+     }
+     else if (strcmp("-warm",argv[i]) == 0) {
+       if (i + 1 >= argc) {
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &numWarmSeconds) == -1 ||
+	   numWarmSeconds < 0) {
+	 ndbout_c("-warm flag requires a positive integer argument");
+	 return 1;
+       }
+       i += 2;
+     }
+     else if (strcmp("-e",argv[i]) == 0) {
+       if (i + 1 >= argc) {
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &minEventSendPoll) == -1 ||
+	   minEventSendPoll < 0) {
+	 ndbout_c("-e flag requires a positive integer argument");
+	 return 1;
+       }
+       i += 2;
+     }
+     else if (strcmp("-f",argv[i]) == 0) {
+       if (i + 1 >= argc) {
+	 usage(argv[0]);
+	 return 1;
+       }
+       if (sscanf(argv[i+1], "%d", &forceSendPoll) == -1 ||
+	   forceSendPoll < 0) {
+	 ndbout_c("-f flag requires a positive integer argument");
+	 return 1;
+       }
+       i += 2;
+     }
+     else {
+       return 1;
+     }
+   }
+
+   if(minEventSendPoll > parallellism){
+     ndbout_c("minEventSendPoll(%d) > parallellism(%d)",
+	     minEventSendPoll, parallellism);
+     ndbout_c("not very good...");
+     ndbout_c("very bad...");
+     ndbout_c("exiting...");
+     return 1;
+   }
+   return 0;
+}
+
+static 
+void 
+print_transaction(const char            *header,
+		  unsigned long          totalCount,
+		  TransactionDefinition *trans,
+		  unsigned int           printBranch,
+		  unsigned int           printRollback)
+{
+  double f;
+  
+  ndbout_c("  %s: %d (%.2f%%) "
+	   "Latency(ms) avg: %d min: %d max: %d std: %d n: %d",
+	   header,
+	   trans->count,
+	   (double)trans->count / (double)totalCount * 100.0,
+	   (int)trans->latency.getMean(),
+	   (int)trans->latency.getMin(),
+	   (int)trans->latency.getMax(),
+	   (int)trans->latency.getStddev(),
+	   (int)trans->latency.getCount()
+	   );
+  
+  if( printBranch ){
+    if( trans->count == 0 )
+      f = 0.0;
+    else
+      f = (double)trans->branchExecuted / (double)trans->count * 100.0;
+    ndbout_c("      Branches Executed: %d (%.2f%%)", trans->branchExecuted, f);
+  }
+  
+  if( printRollback ){
+    if( trans->count == 0 )
+      f = 0.0;
+    else
+      f = (double)trans->rollbackExecuted / (double)trans->count * 100.0;
+    ndbout_c("      Rollback Executed: %d (%.2f%%)",trans->rollbackExecuted,f);
+  }
+}
+
+void 
+print_stats(const char       *title,
+	    unsigned int      length,
+	    unsigned int      transactionFlag,
+	    GeneratorStatistics *gen,
+	    int numProc, int parallellism)
+{
+  int    i;
+  char buf[10];
+  char name[MAXHOSTNAMELEN];
+  
+  name[0] = 0;
+  NdbHost_GetHostName(name);
+  
+  ndbout_c("\n------ %s ------",title);
+  ndbout_c("Length        : %d %s",
+	 length,
+	 transactionFlag ? "Transactions" : "sec");
+  ndbout_c("Processor     : %s", name);
+  ndbout_c("Number of Proc: %d",numProc);
+  ndbout_c("Parallellism  : %d", parallellism);
+  ndbout_c("\n");
+
+  if( gen->totalTransactions == 0 ) {
+    ndbout_c("   No Transactions for this test");
+  }
+  else {
+    for(i = 0; i < 5; i++) {
+      sprintf(buf, "T%d",i+1);
+      print_transaction(buf,
+			gen->totalTransactions,
+			&gen->transactions[i],
+			i >= 2,
+			i >= 3 );
+    }
+    
+    ndbout_c("\n");
+    ndbout_c("  Overall Statistics:");
+    ndbout_c("     Transactions: %d", gen->totalTransactions);
+    ndbout_c("     Outer       : %.0f TPS",gen->outerTps);
+    ndbout_c("\n");
+  }
+}
+
+static 
+void *
+threadRoutine(void *arg)
+{
+  int i;
+  ThreadData *data = (ThreadData *)arg;
+  Ndb * pNDB;
+
+  pNDB = asyncDbConnect(parallellism);		      
+  /* NdbSleep_MilliSleep(rand() % 10); */
+
+  for(i = 0; i<parallellism; i++){
+    data[i].pNDB = pNDB;
+  }
+  millisSendPoll = 30000;
+  asyncGenerator(data, parallellism,
+		 millisSendPoll, minEventSendPoll, forceSendPoll);
+
+  asyncDbDisconnect(pNDB);
+
+  return NULL;
+}
+
+NDB_COMMAND(DbAsyncGenerator, "DbAsyncGenerator",
+	    "DbAsyncGenerator", "DbAsyncGenerator", 65535)
+{
+  ndb_init();
+  int i;
+  int j;
+  int k;
+  struct NdbThread* pThread = NULL;
+  GeneratorStatistics  stats;
+  GeneratorStatistics *p;
+  char threadName[32];
+  int rc = NDBT_OK;
+  void* tmp = NULL;
+  if(parse_args(argc,argv) != 0){
+    usage(argv[0]);
+    return NDBT_ProgramExit(NDBT_WRONGARGS);
+  }
+    
+
+  ndbout_c("\nStarting Test with %d process(es) for %d %s parallellism %d",
+	   numProcesses,
+	   numSeconds,
+	   "sec",
+	   parallellism);
+
+  ndbout_c("   WarmUp/coolDown = %d sec", numWarmSeconds);
+
+  Ndb_cluster_connection con;
+  if(con.connect(12, 5, 1) != 0)
+  {
+    ndbout << "Unable to connect to management server." << endl;
+    return 0;
+  }
+  if (con.wait_until_ready(30,0) < 0)
+  {
+    ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+    return 0;
+  }
+  
+  g_cluster_connection= &con;
+  data = (ThreadData*)malloc((numProcesses*parallellism)*sizeof(ThreadData));
+ 
+  for(i = 0; i < numProcesses; i++) {
+    for(j = 0; j<parallellism; j++){
+      data[i*parallellism+j].warmUpSeconds   = numWarmSeconds;
+      data[i*parallellism+j].testSeconds     = numSeconds;
+      data[i*parallellism+j].coolDownSeconds = numWarmSeconds;
+      data[i*parallellism+j].randomSeed      = 
+	NdbTick_CurrentMillisecond()+i+j;
+      data[i*parallellism+j].changedTime     = 0;
+      data[i*parallellism+j].runState        = Runnable;
+    }
+    sprintf(threadName, "AsyncThread[%d]", i);
+    pThread = NdbThread_Create(threadRoutine, 
+			      (void**)&data[i*parallellism], 
+			      65535, 
+			      threadName,
+                              NDB_THREAD_PRIO_LOW);
+    if(pThread != 0 && pThread != NULL){
+      (&data[i*parallellism])->pThread = pThread;
+    } else {      
+      perror("Failed to create thread");
+      rc = NDBT_FAILED;
+    }
+  }
+
+  showTime();
+
+  /*--------------------------------*/
+  /* Wait for all processes to exit */
+  /*--------------------------------*/
+  for(i = 0; i < numProcesses; i++) {
+    NdbThread_WaitFor(data[i*parallellism].pThread, &tmp);
+    NdbThread_Destroy(&data[i*parallellism].pThread);
+  }
+   
+  ndbout_c("All threads have finished");
+  
+  /*-------------------------------------------*/
+  /* Clear all structures for total statistics */
+  /*-------------------------------------------*/
+  stats.totalTransactions = 0;
+  stats.outerTps          = 0.0;
+  
+  for(i = 0; i < NUM_TRANSACTION_TYPES; i++ ) {
+    stats.transactions[i].count            = 0;
+    stats.transactions[i].branchExecuted   = 0;
+    stats.transactions[i].rollbackExecuted = 0;
+    stats.transactions[i].latency.reset();
+  }
+  
+  /*--------------------------------*/
+  /* Add the values for all Threads */
+  /*--------------------------------*/
+  for(i = 0; i < numProcesses; i++) {
+    for(k = 0; k<parallellism; k++){
+      p = &data[i*parallellism+k].generator;
+      
+      stats.totalTransactions += p->totalTransactions;
+      stats.outerTps          += p->outerTps;
+      
+      for(j = 0; j < NUM_TRANSACTION_TYPES; j++ ) {
+	stats.transactions[j].count += 
+	  p->transactions[j].count;
+	stats.transactions[j].branchExecuted += 
+	  p->transactions[j].branchExecuted;
+	stats.transactions[j].rollbackExecuted += 
+	  p->transactions[j].rollbackExecuted;
+	stats.transactions[j].latency += 
+	  p->transactions[j].latency;
+      }
+    }
+  }
+
+  print_stats("Test Results", 
+	      numSeconds,
+	      0,
+	      &stats,
+	      numProcesses,
+	      parallellism);
+
+  free(data);
+  
+  NDBT_ProgramExit(rc);
+}
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+#include "userInterface.h"
+#include <NdbMutex.h>
+#include <NdbThread.h>
+#include <NdbTick.h>
+#include <NdbApi.hpp>
+#include <NdbOut.hpp>
+
+/***************************************************************
+* L O C A L   C O N S T A N T S                                *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   D A T A   S T R U C T U R E S                    *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   F U N C T I O N S                                *
+***************************************************************/
+
+#ifndef NDB_WIN32
+#include <unistd.h>
+#endif
+
+Ndb*
+asyncDbConnect(int parallellism){
+  Ndb * pNDB = new Ndb(g_cluster_connection, "TEST_DB");
+  
+  pNDB->init(parallellism + 1);
+  
+  while(pNDB->waitUntilReady() != 0){
+  }
+  
+  return pNDB;
+}
+
+void 
+asyncDbDisconnect(Ndb* pNDB)
+{
+  delete pNDB;
+}
+
+double
+userGetTime(void)
+{
+  static bool initialized = false;
+  static NDB_TICKS initSecs = 0;
+  static Uint32 initMicros = 0;
+  double timeValue = 0;
+
+  if ( !initialized ) {
+    initialized = true;
+    NdbTick_CurrentMicrosecond(&initSecs, &initMicros); 
+    timeValue = 0.0;
+  } else {
+    NDB_TICKS secs = 0;
+    Uint32 micros = 0;
+
+    NdbTick_CurrentMicrosecond(&secs, &micros);
+    double s  = (double)secs  - (double)initSecs;
+    double us = (double)micros - (double)initMicros;
+    
+    timeValue = s + (us / 1000000.0);
+  }
+  return timeValue;
+}
+
+void showTime()
+{
+  char buf[128];
+  struct tm* tm_now;
+  time_t now;
+  now = ::time((time_t*)NULL);
+  tm_now = ::gmtime(&now);
+
+  ::snprintf(buf, 128,
+	     "%d-%.2d-%.2d %.2d:%.2d:%.2d", 
+	     tm_now->tm_year + 1900, 
+	     tm_now->tm_mon, 
+	     tm_now->tm_mday,
+	     tm_now->tm_hour,
+	     tm_now->tm_min,
+	     tm_now->tm_sec);
+
+  ndbout_c("Time: %s", buf);
+}
+
diff --git a/ndb/test/ndbapi/bench/mainPopulate.cpp b/ndb/test/ndbapi/bench/mainPopulate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f4b73a3effb215fc13b2f312bda9eba6f3d409c
--- /dev/null
+++ b/ndb/test/ndbapi/bench/mainPopulate.cpp
@@ -0,0 +1,84 @@
+/* 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 <ndb_global.h>
+#include <ndb_opts.h>
+
+#include "userInterface.h"
+#include "dbPopulate.h"
+#include <NdbMain.h>
+#include <NdbOut.hpp>
+#include <random.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+int useTableLogging;
+int useIndexTables;
+#ifdef	__cplusplus
+}
+#endif
+
+
+static void usage()
+{
+}
+
+static 
+void usage(const char *prog)
+{
+  
+  ndbout_c(
+	   "Usage: %s [-l]\n"
+	   "  -l                  Use logging and checkpointing on tables\n",
+	   "  -i                  Use index tables\n",
+	   prog);
+  
+  exit(1);
+}
+
+NDB_STD_OPTS_VARS;
+
+NDB_COMMAND(DbCreate, "DbCreate", "DbCreate", "DbCreate", 16384)
+{
+  int i;
+  UserHandle *uh;
+  
+  useTableLogging = useIndexTables = 0;
+  NDB_INIT(argv[0]);
+  
+  for(i = 1; i<argc; i++){
+    if(strcmp(argv[i], "-l") == 0){
+      useTableLogging = 1;
+    } else if(strcmp(argv[i], "-i") == 0){
+      useIndexTables = 1;
+    } else {
+      usage(argv[0]);
+      return 0;
+    }
+  }
+
+  ndbout_c("Using %s tables and %s key storage",
+	   useTableLogging ? "logging" : "temporary",
+	   useIndexTables  ? "index" : "normal");
+  
+  myRandom48Init(0x3e6f);
+  
+  uh = userDbConnect(1, "TEST_DB");
+  dbPopulate(uh);
+  userDbDisconnect(uh);
+  return(0);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_async1.cpp b/ndb/test/ndbapi/bench/ndb_async1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a84f6b2aca5c0ffb8c8d3d429732683167b92dd
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_async1.cpp
@@ -0,0 +1,647 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <NdbApi.hpp>
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB, 
+		 ServerId inServerId, 
+		 const SubscriberNumber inNumber){
+  
+  const int keyDataLenBytes    = sizeof(ServerId)+SUBSCRIBER_NUMBER_LENGTH;
+  const int keyDataLen_64Words = keyDataLenBytes >> 3;
+
+  Uint64 keyDataBuf[keyDataLen_64Words+1]; // The "+1" is for rounding...
+  
+  char     * keyDataBuf_charP = (char *)&keyDataBuf[0];
+  Uint32  * keyDataBuf_wo32P = (Uint32 *)&keyDataBuf[0];
+  
+  // Server Id comes first
+  keyDataBuf_wo32P[0] = inServerId;
+  // Then subscriber number
+  memcpy(&keyDataBuf_charP[sizeof(ServerId)], inNumber, 
+	 SUBSCRIBER_NUMBER_LENGTH);
+
+  return pNDB->startTransaction(0, keyDataBuf_charP, keyDataLenBytes);
+}
+
+void T1_Callback(int result, NdbConnection * pCon, void * threadData);
+void T2_Callback(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_3(int result, NdbConnection * pCon, void * threadData);
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+void
+start_T1(Ndb * pNDB, ThreadData * td){
+
+  DEBUG2("T1(%.*s): - Starting\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number); 
+
+  int check;
+  NdbConnection * pCON = pNDB->startTransaction();
+  if (pCON != NULL) {
+    NdbOperation *MyOp = pCON->getNdbOperation(SUBSCRIBER_TABLE);
+    if (MyOp != NULL) {  
+      MyOp->updateTuple();  
+      MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+		  td->transactionData.number);
+      MyOp->setValue(IND_SUBSCRIBER_LOCATION, 
+		     (char *)&td->transactionData.location);
+      MyOp->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+		     td->transactionData.changed_by);
+      MyOp->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		     td->transactionData.changed_time);
+      pCON->executeAsynchPrepare( Commit , T1_Callback, td);
+    } else {
+      CHECK_NULL(MyOp, "T1: getNdbOperation", pCON);
+    }//if
+  } else {
+    error_handler("T1-1: startTranscation", 
+		  pNDB->getNdbErrorString(), 
+		  pNDB->getNdbError());
+  }//if
+}
+
+void
+T1_Callback(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  
+  DEBUG2("T1(%.*s): - Completing\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number); 
+
+  CHECK_MINUS_ONE(result, "T1: Commit", 
+		  pCON);
+  td->pNDB->closeTransaction(pCON);
+  complete_T1(td);
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+void
+start_T2(Ndb * pNDB, ThreadData * td){
+
+  DEBUG3("T2(%.*s, %p): - Starting\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.location);
+  
+  int check;
+  NdbRecAttr * check2;
+  
+  NdbConnection * pCON = pNDB->startTransaction();
+  if (pCON == NULL)	  
+    error_handler("T2-1: startTransaction", 
+		  pNDB->getNdbErrorString(), 
+		  pNDB->getNdbError());
+  
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T2: getNdbOperation", 
+	     pCON);
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER,
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_NAME, 
+		 td->transactionData.name);
+  pCON->executeAsynchPrepare( Commit, T2_Callback, td ); 
+}
+
+void
+T2_Callback(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  DEBUG3("T2(%.*s, %p): - Completing\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.location);
+  
+  CHECK_MINUS_ONE(result, "T2: Commit", pCON);
+  td->pNDB->closeTransaction(pCON);
+  complete_T2(td);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+void
+start_T3(Ndb * pNDB, ThreadData * td){
+
+  DEBUG3("T3(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * pCON = startTransaction(pNDB, 
+					     td->transactionData.server_id, 
+					     td->transactionData.number);
+  if (pCON == NULL)	  
+    error_handler("T3-1: startTranscation", 
+		  pNDB->getNdbErrorString(), 
+		  pNDB->getNdbError());
+  
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T3-1: getNdbOperation", 
+	     pCON);
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP, 
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS, 
+		 (char *)&td->transactionData.sessions);
+  pCON->executeAsynchPrepare( NoCommit , T3_Callback_1, td); 
+}
+
+void
+T3_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  DEBUG3("T3(%.*s, %.2d): - Callback 1\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  CHECK_MINUS_ONE(result, "T3-1: NoCommit", pCON); 
+
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T3-2: getNdbOperation", 
+	     pCON);
+    
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_READ, 
+		 (char *)&td->transactionData.permission);
+  pCON->executeAsynchPrepare( NoCommit, T3_Callback_2, td ); 
+}
+
+void
+T3_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  
+  CHECK_MINUS_ONE(result, "T3-2: NoCommit", pCON); 
+  
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == server_bit)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number
+	   [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH],
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    DEBUG5("T3(%.*s, %.2d): - Callback 2 - reading(%.*s)\n", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T3-3: getNdbOperation", 
+	       pCON);
+    
+    MyOp->simpleRead();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    MyOp->getValue(IND_SESSION_DATA, 
+		   (char *)td->transactionData.session_details);
+    
+    /* Operation 4 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T3-4: getNdbOperation", 
+	       pCON);
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_READS, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    DEBUG3("T3(%.*s, %.2d): - Callback 2 - no read\n",
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id);
+    td->transactionData.branchExecuted = 0;
+  }
+  pCON->executeAsynchPrepare( Commit, T3_Callback_3, td ); 
+}
+
+void
+T3_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  DEBUG3("T3(%.*s, %.2d): - Completing\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  CHECK_MINUS_ONE(result, "T3-3: Commit", pCON); 
+  
+  td->pNDB->closeTransaction(pCON);
+  complete_T3(td);
+}
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+start_T4(Ndb * pNDB, ThreadData * td){
+
+  DEBUG3("T4(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  int check;
+  NdbRecAttr * check2;
+  
+  NdbConnection * pCON = startTransaction(pNDB, 
+					  td->transactionData.server_id, 
+					  td->transactionData.number);
+  if (pCON == NULL)	  
+    error_handler("T4-1: startTranscation", 
+		  pNDB->getNdbErrorString(), 
+		  pNDB->getNdbError());
+  
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T4-1: getNdbOperation", 
+	     pCON);
+  
+  MyOp->interpretedUpdateTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP,
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+		 (char *)&td->transactionData.sessions); 
+  MyOp->incValue(IND_SUBSCRIBER_SESSIONS, 
+		 (uint32)td->transactionData.server_bit);
+  pCON->executeAsynchPrepare( NoCommit , T4_Callback_1, td); 
+}
+
+void
+T4_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T4-1: NoCommit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+  
+  DEBUG3("T4(%.*s, %.2d): - Callback 1\n", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T4-2: getNdbOperation", 
+	     pCON);
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_INSERT, 
+		 (char *)&td->transactionData.permission);
+  pCON->executeAsynchPrepare( NoCommit , T4_Callback_2, td); 
+}
+
+void
+T4_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T4-2: NoCommit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+  
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == 0)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number
+	   [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], 
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    
+    DEBUG5("T4(%.*s, %.2d): - Callback 2 - inserting(%.*s)\n", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T4-3: getNdbOperation", 
+	       pCON);
+    
+    MyOp->insertTuple();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    MyOp->setValue(SESSION_DATA, 
+		   (char *)td->transactionData.session_details);
+    /* Operation 4 */
+    
+    /* Operation 5 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T4-5: getNdbOperation", 
+	       pCON);
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_INSERTS, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    td->transactionData.branchExecuted = 0;
+    DEBUG5("T4(%.*s, %.2d): - Callback 2 - %s %s\n",
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   ((permission & server_bit) ? 
+	    "permission - " : "no permission - "),
+	   ((sessions   & server_bit) ? 
+	    "in session - " : "no in session - "));
+  }
+  
+  if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+    pCON->executeAsynchPrepare(Commit, T4_Callback_3, td); 
+  } else {
+    pCON->executeAsynchPrepare(Rollback, T4_Callback_3, td);
+  }
+}
+
+void
+T4_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T4-3: Commit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+  
+  DEBUG3("T4(%.*s, %.2d): - Completing\n", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  td->pNDB->closeTransaction(pCON);
+  complete_T4(td);
+}
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+start_T5(Ndb * pNDB, ThreadData * td){
+
+  DEBUG3("T5(%.*s, %.2d): - Starting\n", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  int check;
+  NdbRecAttr * check2;
+  
+  NdbConnection * pCON = pNDB->startTransaction();
+  if (pCON == NULL)	  
+    error_handler("T5-1: startTranscation", 
+		  pNDB->getNdbErrorString(), 
+		  pNDB->getNdbError());
+  
+  NdbOperation * MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T5-1: getNdbOperation", 
+	     pCON);
+  
+  MyOp->interpretedUpdateTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP,
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+		 (char *)&td->transactionData.sessions);
+  MyOp->subValue(IND_SUBSCRIBER_SESSIONS, 
+		 (uint32)td->transactionData.server_bit);
+  pCON->executeAsynchPrepare( NoCommit, T5_Callback_1, td ); 
+}
+
+void
+T5_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T5-1: NoCommit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+
+  DEBUG3("T5(%.*s, %.2d): - Callback 1\n", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T5-2: getNdbOperation", 
+	     pCON);
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_DELETE, 
+		 (char *)&td->transactionData.permission);
+  pCON->executeAsynchPrepare( NoCommit, T5_Callback_2, td ); 
+}
+
+void
+T5_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T5-2: NoCommit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == server_bit)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number
+	   [SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], 
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+  
+    DEBUG5("T5(%.*s, %.2d): - Callback 2 - deleting(%.*s)\n", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T5-3: getNdbOperation", 
+	       pCON);
+    
+    MyOp->deleteTuple();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    /* Operation 4 */
+    
+    /* Operation 5 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T5-5: getNdbOperation", 
+	       pCON);
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_DELETES, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    td->transactionData.branchExecuted = 0;
+
+    DEBUG5("T5(%.*s, %.2d): - Callback 2 - no delete - %s %s\n", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   ((permission & server_bit) ? 
+	    "permission - " : "no permission - "),
+	   ((sessions   & server_bit) ? 
+	    "in session - " : "no in session - "));
+  }
+  
+  if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+    pCON->executeAsynchPrepare(Commit, T5_Callback_3, td); 
+  } else {
+    pCON->executeAsynchPrepare(Rollback, T5_Callback_3, td);
+  }
+}
+
+void
+T5_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  CHECK_MINUS_ONE(result, "T5-3: Commit", pCON); 
+  ThreadData * td = (ThreadData *)threadData;  
+
+  DEBUG3("T5(%.*s, %.2d): - Completing\n", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  td->pNDB->closeTransaction(pCON);
+  complete_T5(td);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_async2.cpp b/ndb/test/ndbapi/bench/ndb_async2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..31cf1d8310a82be3642d11bf60b275a59bd89b3f
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_async2.cpp
@@ -0,0 +1,757 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+#include <string.h>
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+#include <NdbSleep.h>
+
+#include <NdbApi.hpp>
+
+void T1_Callback(int result, NdbConnection * pCon, void * threadData);
+void T2_Callback(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T3_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T4_Callback_3(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_1(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_2(int result, NdbConnection * pCon, void * threadData);
+void T5_Callback_3(int result, NdbConnection * pCon, void * threadData);
+
+static int stat_async = 0;
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+
+#define SFX_START (SUBSCRIBER_NUMBER_LENGTH - SUBSCRIBER_NUMBER_SUFFIX_LENGTH)
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB, ThreadData * td){
+  return pNDB->startTransaction();
+#ifdef OLD_CODE
+  return pNDB->startTransactionDGroup (0, 
+				       &td->transactionData.number[SFX_START],
+				       1);
+#endif
+}
+
+void
+start_T1(Ndb * pNDB, ThreadData * td, int async){
+
+  DEBUG2("T1(%.*s): - Starting", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number); 
+
+  NdbConnection * pCON = 0;
+  while((pCON = startTransaction(pNDB, td)) == 0){
+    CHECK_ALLOWED_ERROR("T1: startTransaction", td, pNDB->getNdbError());
+    NdbSleep_MilliSleep(10);
+  }
+
+  NdbOperation *MyOp = pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  if (MyOp != NULL) {  
+    MyOp->updateTuple();  
+    MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+		td->transactionData.number);
+    MyOp->setValue(IND_SUBSCRIBER_LOCATION, 
+		   (char *)&td->transactionData.location);
+    MyOp->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+		   td->transactionData.changed_by);
+    MyOp->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		   td->transactionData.changed_time);
+    if (async == 1) {
+      pCON->executeAsynchPrepare( Commit , T1_Callback, td);
+    } else {
+      int result = pCON->execute(Commit);
+      T1_Callback(result, pCON, (void*)td);
+      return;
+    }//if
+  } else {
+    CHECK_NULL(MyOp, "T1: getNdbOperation", td, pCON->getNdbError());
+  }//if
+}
+
+void
+T1_Callback(int result, NdbConnection * pCON, void * threadData) {
+  ThreadData * td = (ThreadData *)threadData;
+  
+  DEBUG2("T1(%.*s): - Completing", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number); 
+
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T1: Commit", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T1(td->pNDB, td, stat_async);
+    return;
+  }//if
+  td->pNDB->closeTransaction(pCON);
+  complete_T1(td);
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+void
+start_T2(Ndb * pNDB, ThreadData * td, int async){
+
+  DEBUG3("T2(%.*s, %d): - Starting", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.location);
+  
+  NdbConnection * pCON = 0;
+  
+  while((pCON = startTransaction(pNDB, td)) == 0){
+    CHECK_ALLOWED_ERROR("T2-1: startTransaction", td, pNDB->getNdbError());
+    NdbSleep_MilliSleep(10);
+  }
+
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T2: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER,
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_NAME, 
+		 td->transactionData.name);
+  if (async == 1) {
+    pCON->executeAsynchPrepare( Commit , T2_Callback, td);
+  } else {
+    int result = pCON->execute(Commit);
+    T2_Callback(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T2_Callback(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  DEBUG3("T2(%.*s, %d): - Completing", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.location);
+  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T2: Commit", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T2(td->pNDB, td, stat_async);
+    return;
+  }//if
+  td->pNDB->closeTransaction(pCON);
+  complete_T2(td);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+void
+start_T3(Ndb * pNDB, ThreadData * td, int async){
+
+  DEBUG3("T3(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  NdbConnection * pCON = 0;
+
+  while((pCON = startTransaction(pNDB, td)) == 0){
+    CHECK_ALLOWED_ERROR("T3-1: startTransaction", td, pNDB->getNdbError());
+    NdbSleep_MilliSleep(10);
+  }
+  
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T3-1: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP, 
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS, 
+		 (char *)&td->transactionData.sessions);
+  stat_async = async;
+  if (async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T3_Callback_1, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T3_Callback_1(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T3_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  DEBUG3("T3(%.*s, %.2d): - Callback 1", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T3-1: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T3(td->pNDB, td, stat_async);
+    return;
+  }//if
+
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T3-2: getNdbOperation", td,
+	     pCON->getNdbError());
+    
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_READ, 
+		 (char *)&td->transactionData.permission);
+  if (stat_async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T3_Callback_2, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T3_Callback_2(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T3_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;
+  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T3-2: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T3(td->pNDB, td, stat_async);
+    return;
+  }//if
+  
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == server_bit)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number[SFX_START],
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    DEBUG5("T3(%.*s, %.2d): - Callback 2 - reading(%.*s)", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T3-3: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->simpleRead();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    MyOp->getValue(IND_SESSION_DATA, 
+		   (char *)td->transactionData.session_details);
+    
+    /* Operation 4 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T3-4: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_READS, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    DEBUG3("T3(%.*s, %.2d): - Callback 2 - no read",
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id);
+    td->transactionData.branchExecuted = 0;
+  }
+  if (stat_async == 1) {
+    pCON->executeAsynchPrepare( Commit , T3_Callback_3, td);
+  } else {
+    int result = pCON->execute( Commit );
+    T3_Callback_3(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T3_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  DEBUG3("T3(%.*s, %.2d): - Completing", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T3-3: Commit", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T3(td->pNDB, td, stat_async);
+    return;
+  }//if
+  td->pNDB->closeTransaction(pCON);
+  complete_T3(td);
+}
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+start_T4(Ndb * pNDB, ThreadData * td, int async){
+
+  DEBUG3("T4(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  NdbConnection * pCON = 0;
+  while((pCON = startTransaction(pNDB, td)) == 0){
+    CHECK_ALLOWED_ERROR("T4-1: startTransaction", td, pNDB->getNdbError());
+    NdbSleep_MilliSleep(10);
+  }
+  
+  NdbOperation *MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T4-1: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->interpretedUpdateTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP,
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+		 (char *)&td->transactionData.sessions); 
+  MyOp->incValue(IND_SUBSCRIBER_SESSIONS, 
+		 (uint32)td->transactionData.server_bit);
+  stat_async = async;
+  if (async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T4_Callback_1, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T4_Callback_1(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T4_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T4-1: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T4(td->pNDB, td, stat_async);
+    return;
+  }//if
+  
+  DEBUG3("T4(%.*s, %.2d): - Callback 1", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T4-2: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_INSERT, 
+		 (char *)&td->transactionData.permission);
+  if (stat_async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T4_Callback_2, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T4_Callback_2(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T4_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T4-2: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T4(td->pNDB, td, stat_async);
+    return;
+  }//if
+
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+  
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == 0)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number[SFX_START],
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    
+    DEBUG5("T4(%.*s, %.2d): - Callback 2 - inserting(%.*s)", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T4-3: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->insertTuple();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    MyOp->setValue(SESSION_DATA, 
+		   (char *)td->transactionData.session_details);
+    /* Operation 4 */
+    
+    /* Operation 5 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T4-5: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_INSERTS, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    td->transactionData.branchExecuted = 0;
+    DEBUG5("T4(%.*s, %.2d): - Callback 2 - %s %s",
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   ((permission & server_bit) ? 
+	    "permission - " : "no permission - "),
+	   ((sessions   & server_bit) ? 
+	    "in session - " : "no in session - "));
+  }
+  
+  if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+    if (stat_async == 1) {
+      pCON->executeAsynchPrepare( Commit , T4_Callback_3, td);
+    } else {
+      int result = pCON->execute( Commit );
+      T4_Callback_3(result, pCON, (void*)td);
+      return;
+    }//if
+  } else {
+    if (stat_async == 1) {
+      pCON->executeAsynchPrepare( Rollback , T4_Callback_3, td);
+    } else {
+      int result = pCON->execute( Rollback );
+      T4_Callback_3(result, pCON, (void*)td);
+      return;
+    }//if
+  }
+}
+
+void
+T4_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T4-3: Commit", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T4(td->pNDB, td, stat_async);
+    return;
+  }//if
+  
+  DEBUG3("T4(%.*s, %.2d): - Completing", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  td->pNDB->closeTransaction(pCON);
+  complete_T4(td);
+}
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+start_T5(Ndb * pNDB, ThreadData * td, int async){
+
+  DEBUG3("T5(%.*s, %.2d): - Starting", SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+
+  NdbConnection * pCON = 0;
+  while((pCON = startTransaction(pNDB, td)) == 0){
+    CHECK_ALLOWED_ERROR("T5-1: startTransaction", td, pNDB->getNdbError());
+    NdbSleep_MilliSleep(10);
+  }
+  
+  NdbOperation * MyOp= pCON->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOp, "T5-1: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->interpretedUpdateTuple();
+  MyOp->equal(IND_SUBSCRIBER_NUMBER, 
+	      td->transactionData.number);
+  MyOp->getValue(IND_SUBSCRIBER_LOCATION, 
+		 (char *)&td->transactionData.location);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		 td->transactionData.changed_by);
+  MyOp->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+		 td->transactionData.changed_time);
+  MyOp->getValue(IND_SUBSCRIBER_GROUP,
+		 (char *)&td->transactionData.group_id);
+  MyOp->getValue(IND_SUBSCRIBER_SESSIONS,
+		 (char *)&td->transactionData.sessions);
+  MyOp->subValue(IND_SUBSCRIBER_SESSIONS, 
+		 (uint32)td->transactionData.server_bit);
+  stat_async = async;
+  if (async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T5_Callback_1, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T5_Callback_1(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T5_Callback_1(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T5-1: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T5(td->pNDB, td, stat_async);
+    return;
+  }//if
+
+  DEBUG3("T5(%.*s, %.2d): - Callback 1", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  NdbOperation * MyOp = pCON->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOp, "T5-2: getNdbOperation", td,
+	     pCON->getNdbError());
+  
+  MyOp->readTuple();
+  MyOp->equal(IND_GROUP_ID,
+	      (char*)&td->transactionData.group_id);
+  MyOp->getValue(IND_GROUP_ALLOW_DELETE, 
+		 (char *)&td->transactionData.permission);
+  if (stat_async == 1) {
+    pCON->executeAsynchPrepare( NoCommit , T5_Callback_2, td);
+  } else {
+    int result = pCON->execute( NoCommit );
+    T5_Callback_2(result, pCON, (void*)td);
+    return;
+  }//if
+}
+
+void
+T5_Callback_2(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T5-2: execute", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T5(td->pNDB, td, stat_async);
+    return;
+  }//if
+
+  Uint32 permission = td->transactionData.permission;
+  Uint32 sessions   = td->transactionData.sessions;
+  Uint32 server_bit = td->transactionData.server_bit;
+
+  if(((permission & server_bit) == server_bit) &&
+     ((sessions   & server_bit) == server_bit)){
+    
+    memcpy(td->transactionData.suffix,
+	   &td->transactionData.number[SFX_START],
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    
+    DEBUG5("T5(%.*s, %.2d): - Callback 2 - deleting(%.*s)", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   SUBSCRIBER_NUMBER_SUFFIX_LENGTH, 
+	   td->transactionData.suffix);
+    
+    /* Operation 3 */
+    NdbOperation * MyOp = pCON->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOp, "T5-3: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->deleteTuple();
+    MyOp->equal(IND_SESSION_SUBSCRIBER,
+		(char*)td->transactionData.number);
+    MyOp->equal(IND_SESSION_SERVER,
+		(char*)&td->transactionData.server_id);
+    /* Operation 4 */
+    
+    /* Operation 5 */
+    MyOp = pCON->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOp, "T5-5: getNdbOperation", td,
+	       pCON->getNdbError());
+    
+    MyOp->interpretedUpdateTuple();
+    MyOp->equal(IND_SERVER_ID,
+		(char*)&td->transactionData.server_id);
+    MyOp->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		(char*)td->transactionData.suffix);
+    MyOp->incValue(IND_SERVER_DELETES, (uint32)1);
+    td->transactionData.branchExecuted = 1;
+  } else {
+    td->transactionData.branchExecuted = 0;
+
+    DEBUG5("T5(%.*s, %.2d): - Callback 2 - no delete - %s %s", 
+	   SUBSCRIBER_NUMBER_LENGTH, 
+	   td->transactionData.number, 
+	   td->transactionData.server_id,
+	   ((permission & server_bit) ? 
+	    "permission - " : "no permission - "),
+	   ((sessions   & server_bit) ? 
+	    "in session - " : "no in session - "));
+  }
+  
+  if(!td->transactionData.do_rollback && td->transactionData.branchExecuted){
+    if (stat_async == 1) {
+      pCON->executeAsynchPrepare( Commit , T5_Callback_3, td);
+    } else {
+      int result = pCON->execute( Commit );
+      T5_Callback_3(result, pCON, (void*)td);
+      return;
+    }//if
+  } else {
+    if (stat_async == 1) {
+      pCON->executeAsynchPrepare( Rollback , T5_Callback_3, td);
+    } else {
+      int result = pCON->execute( Rollback );
+      T5_Callback_3(result, pCON, (void*)td);
+      return;
+    }//if
+  }
+}
+
+void
+T5_Callback_3(int result, NdbConnection * pCON, void * threadData){
+  ThreadData * td = (ThreadData *)threadData;  
+  if (result == -1) {
+    CHECK_ALLOWED_ERROR("T5-3: Commit", td, pCON->getNdbError());
+    td->pNDB->closeTransaction(pCON);
+    start_T5(td->pNDB, td, stat_async);
+    return;
+  }//if
+  
+  DEBUG3("T5(%.*s, %.2d): - Completing", 
+	 SUBSCRIBER_NUMBER_LENGTH, 
+	 td->transactionData.number, 
+	 td->transactionData.server_id);
+  
+  td->pNDB->closeTransaction(pCON);
+  complete_T5(td);
+}
diff --git a/ndb/test/ndbapi/bench/ndb_error.hpp b/ndb/test/ndbapi/bench/ndb_error.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d90f5506813b85ab62ba32221c70b981cd4d0f1c
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_error.hpp
@@ -0,0 +1,81 @@
+/* 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 */
+
+#ifndef NDB_ERROR_H
+#define NDB_ERROR_H
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+#include "userInterface.h"
+#include <NdbError.hpp>
+#include <NdbApi.hpp>
+
+#define error_handler(x,y, z) { \
+   ndbout << x << " " << y << endl; \
+   exit(-1); }
+
+#define CHECK_MINUS_ONE(x, y, z) if(x == -1) \
+   error_handler(y,(z->getNdbError()), 0)
+  
+inline
+void
+CHECK_ALLOWED_ERROR(const char * str, 
+		    const ThreadData * td, 
+		    const struct NdbError & error){
+  
+  char buf[100];
+  snprintf(buf, sizeof(buf), "subscriber = %.*s ", 
+	  SUBSCRIBER_NUMBER_LENGTH, 
+	  td->transactionData.number);
+  ndbout << str << " " << error << endl
+	 << buf;
+  showTime();
+  
+  switch(error.classification) { 
+  case NdbError::TimeoutExpired:  
+  case NdbError::OverloadError: 
+  case NdbError::TemporaryResourceError: 
+  case NdbError::NodeRecoveryError:
+    break;    
+  default:    
+    if(error.status != NdbError::TemporaryError)
+      exit(-1);
+  }
+}
+
+inline
+void
+CHECK_NULL(void * null, 
+	   const char * str, 
+	   const ThreadData * td,
+	   const struct NdbError & err){
+  if(null == 0){
+    CHECK_ALLOWED_ERROR(str, td, err);
+    exit(-1);
+  }
+}
+
+inline
+void
+CHECK_NULL(void * null, const char* msg, NdbConnection* obj)
+{
+  if(null == 0)
+  {
+    error_handler(msg, obj->getNdbError(), 0);
+  }
+}
+
+#endif
diff --git a/ndb/test/ndbapi/bench/ndb_schema.hpp b/ndb/test/ndbapi/bench/ndb_schema.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..af08bc2eecd261b9bed56065847a15a7ab143e0b
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_schema.hpp
@@ -0,0 +1,78 @@
+/* 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 */
+
+#ifndef NDB_SCHEMA_H
+#define NDB_SCHEMA_H
+
+#include "testDefinitions.h"
+
+#define SUBSCRIBER_TABLE        "SUBSCRIBER"
+#define SUBSCRIBER_NUMBER       "NUMBER"
+#define SUBSCRIBER_LOCATION     "LOCATION"
+#define SUBSCRIBER_NAME         "NAME"
+#define SUBSCRIBER_GROUP        "GROUP_ID"
+#define SUBSCRIBER_SESSIONS     "SESSIONS"
+#define SUBSCRIBER_CHANGED_BY   "CHANGED_BY"
+#define SUBSCRIBER_CHANGED_TIME "CHANGED_TIME"
+
+#define SERVER_TABLE             "SERVER"
+#define SERVER_ID                "SERVER_ID"
+#define SERVER_SUBSCRIBER_SUFFIX "SUFFIX"
+#define SERVER_NAME              "NAME"
+#define SERVER_READS             "NO_OF_READ"
+#define SERVER_INSERTS           "NO_OF_INSERT"
+#define SERVER_DELETES           "NO_OF_DELETE"
+
+#define GROUP_TABLE              "GROUP"
+#define GROUP_ID                 "GROUP_ID"
+#define GROUP_NAME               "GROUP_NAME"
+#define GROUP_ALLOW_READ         "ALLOW_READ"
+#define GROUP_ALLOW_INSERT       "ALLOW_INSERT"
+#define GROUP_ALLOW_DELETE       "ALLOW_DELETE"
+
+#define SESSION_TABLE            "SESSION"
+#define SESSION_SERVER           "SERVER_ID"
+#define SESSION_SUBSCRIBER       "NUMBER"
+#define SESSION_DATA             "DATA"
+
+/** Numbers */
+
+#define IND_SUBSCRIBER_NUMBER        (unsigned)0
+#define IND_SUBSCRIBER_NAME          (unsigned)1
+#define IND_SUBSCRIBER_GROUP         (unsigned)2
+#define IND_SUBSCRIBER_LOCATION      (unsigned)3
+#define IND_SUBSCRIBER_SESSIONS      (unsigned)4
+#define IND_SUBSCRIBER_CHANGED_BY    (unsigned)5
+#define IND_SUBSCRIBER_CHANGED_TIME  (unsigned)6
+
+#define IND_SERVER_SUBSCRIBER_SUFFIX (unsigned)0
+#define IND_SERVER_ID                (unsigned)1
+#define IND_SERVER_NAME              (unsigned)2
+#define IND_SERVER_READS             (unsigned)3
+#define IND_SERVER_INSERTS           (unsigned)4
+#define IND_SERVER_DELETES           (unsigned)5
+
+#define IND_GROUP_ID                 (unsigned)0
+#define IND_GROUP_NAME               (unsigned)1
+#define IND_GROUP_ALLOW_READ         (unsigned)2
+#define IND_GROUP_ALLOW_INSERT       (unsigned)3
+#define IND_GROUP_ALLOW_DELETE       (unsigned)4
+
+#define IND_SESSION_SUBSCRIBER       (unsigned)0
+#define IND_SESSION_SERVER           (unsigned)1
+#define IND_SESSION_DATA             (unsigned)2
+
+#endif
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..182f1f9958689d1e277c92eb7a736eeadf9bbfd8
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction.cpp
@@ -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 */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+   const SubscriberNumber number, 
+   const Location new_location, 
+   const ChangedBy changed_by, 
+   const ChangedTime changed_time,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+  
+  check = MyOperation->updateTuple();
+  CHECK_MINUS_ONE(check, "T1: updateTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T1: equal subscriber",
+		  MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_LOCATION, 
+				(char *)&new_location);
+  CHECK_MINUS_ONE(check, "T1: setValue location", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_CHANGED_BY, 
+				changed_by);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_by", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_CHANGED_TIME, 
+				changed_time);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_time", 
+		  MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T1: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+int
+T2(void * obj,
+   const SubscriberNumber number, 
+   Location * readLocation, 
+   ChangedBy changed_by, 
+   ChangedTime changed_time,
+   SubscriberName subscriberName,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T2: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_LOCATION, 
+				(char *)readLocation);
+  CHECK_NULL(check2, "T2: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY, 
+				 changed_by);
+  CHECK_NULL(check2, "T2: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME, 
+                                 changed_time);
+  CHECK_NULL(check2, "T2: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_NAME, 
+				subscriberName);
+  CHECK_NULL(check2, "T2: getValue name", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+int
+T3(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   SessionDetails     outSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb * pNDB = (Ndb *) obj;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T3-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T3-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T3-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T3-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T3-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T3-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(GROUP_ALLOW_READ, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T3-2: getValue allow_read", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+    
+    DEBUG("reading - ");
+
+    /* Operation 3 */
+
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->readTuple();
+    CHECK_MINUS_ONE(check, "T3-3: readTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T3-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-3: equal server id",
+		    MyTransaction);
+    
+    check2 = MyOperation->getValue(SESSION_DATA, 
+				   (char *)outSessionDetails);
+    CHECK_NULL(check2, "T3-3: getValue session details", 
+	       MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T3-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(SERVER_READS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T3-4: inc value",
+		    MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T3-4: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit\n");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T4(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   const SessionDetails     inSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  Ndb * pNDB = (Ndb *) obj;  
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  NdbOperation * MyOperation = 0;
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T4-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T4-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T4-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T4-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T4-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T4-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-1: NoCommit", 
+		  MyTransaction);
+
+    /* Operation 2 */
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T4-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T4-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(GROUP_ALLOW_INSERT, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T4-2: getValue allow_insert", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+
+    DEBUG("inserting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->insertTuple();
+    CHECK_MINUS_ONE(check, "T4-3: insertTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-3: equal server id",
+		    MyTransaction);
+    
+    check = MyOperation->setValue(SESSION_DATA, 
+				   (char *)inSessionDetails);
+    CHECK_MINUS_ONE(check, "T4-3: setValue session details", 
+	       MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T4-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->incValue(SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T4-4: inc value",
+		    MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-4: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(SERVER_INSERTS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T4-5: inc value",
+		    MyTransaction);
+        
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-5: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T5(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb           * pNDB = (Ndb *) obj;  
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T5-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T5-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T5-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T5-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T5-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T5-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T5-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T5-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(GROUP_ALLOW_DELETE, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T5-2: getValue allow_delete", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    DEBUG("deleting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->deleteTuple();
+    CHECK_MINUS_ONE(check, "T5-3: deleteTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-3: equal server id",
+		    MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T5-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->subValue(SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T5-4: dec value",
+		    MyTransaction);
+        
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-4: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(SERVER_DELETES, (uint32)1);
+    CHECK_MINUS_ONE(check, "T5-5: inc value",
+		    MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-5: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..df3c7a7989e7396277f94d15a41ccdc22a87a0c0
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp
@@ -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 */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+   const SubscriberNumber number, 
+   const Location new_location, 
+   const ChangedBy changed_by, 
+   const ChangedTime changed_time,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+  
+  check = MyOperation->updateTuple();
+  CHECK_MINUS_ONE(check, "T1: updateTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T1: equal subscriber",
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)&new_location);
+  CHECK_MINUS_ONE(check, "T1: setValue location", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+				changed_by);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_by", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+				changed_time);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_time", 
+		  MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T1: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+int
+T2(void * obj,
+   const SubscriberNumber number, 
+   Location * readLocation, 
+   ChangedBy changed_by, 
+   ChangedTime changed_time,
+   SubscriberName subscriberName,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T2: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)readLocation);
+  CHECK_NULL(check2, "T2: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 changed_by);
+  CHECK_NULL(check2, "T2: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 changed_time);
+  CHECK_NULL(check2, "T2: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME, 
+				subscriberName);
+  CHECK_NULL(check2, "T2: getValue name", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+int
+T3(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   SessionDetails     outSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb * pNDB = (Ndb *) obj;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T3-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T3-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T3-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T3-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T3-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T3-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T3-2: getValue allow_read", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+    
+    DEBUG("reading - ");
+
+    /* Operation 3 */
+
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->readTuple();
+    CHECK_MINUS_ONE(check, "T3-3: readTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T3-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-3: equal server id",
+		    MyTransaction);
+    
+    check2 = MyOperation->getValue(IND_SESSION_DATA, 
+				   (char *)outSessionDetails);
+    CHECK_NULL(check2, "T3-3: getValue session details", 
+	       MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T3-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T3-4: inc value",
+		    MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T3-4: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit\n");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T4(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   const SessionDetails     inSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  Ndb * pNDB = (Ndb *) obj;  
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  NdbOperation * MyOperation = 0;
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T4-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T4-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T4-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T4-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T4-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T4-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-1: NoCommit", 
+		  MyTransaction);
+
+    /* Operation 2 */
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T4-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T4-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T4-2: getValue allow_insert", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+
+    DEBUG("inserting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->insertTuple();
+    CHECK_MINUS_ONE(check, "T4-3: insertTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-3: equal server id",
+		    MyTransaction);
+    
+    check = MyOperation->setValue(SESSION_DATA, 
+				   (char *)inSessionDetails);
+    CHECK_MINUS_ONE(check, "T4-3: setValue session details", 
+	       MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T4-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T4-4: inc value",
+		    MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-4: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T4-5: inc value",
+		    MyTransaction);
+        
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T4-5: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T5(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb           * pNDB = (Ndb *) obj;  
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T5-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T5-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T5-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T5-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T5-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T5-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T5-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T5-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T5-2: getValue allow_delete", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    DEBUG("deleting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->deleteTuple();
+    CHECK_MINUS_ONE(check, "T5-3: deleteTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-3: equal server id",
+		    MyTransaction);
+    
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-3: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T5-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T5-4: dec value",
+		    MyTransaction);
+        
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-4: NoCommit", 
+		    MyTransaction);
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+    CHECK_MINUS_ONE(check, "T5-5: inc value",
+		    MyTransaction);
+
+    check = MyTransaction->execute( NoCommit ); 
+    CHECK_MINUS_ONE(check, "T5-5: NoCommit", 
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2c92ecd4245a7271da4540880e643377dd1eec4
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp
@@ -0,0 +1,793 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+   const SubscriberNumber number, 
+   const Location new_location, 
+   const ChangedBy changed_by, 
+   const ChangedTime changed_time,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+  
+  check = MyOperation->updateTuple();
+  CHECK_MINUS_ONE(check, "T1: updateTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T1: equal subscriber",
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)&new_location);
+  CHECK_MINUS_ONE(check, "T1: setValue location", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+				changed_by);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_by", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+				changed_time);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_time", 
+		  MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T1: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+int
+T2(void * obj,
+   const SubscriberNumber number, 
+   Location * readLocation, 
+   ChangedBy changed_by, 
+   ChangedTime changed_time,
+   SubscriberName subscriberName,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T2: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)readLocation);
+  CHECK_NULL(check2, "T2: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 changed_by);
+  CHECK_NULL(check2, "T2: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 changed_time);
+  CHECK_NULL(check2, "T2: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME, 
+				subscriberName);
+  CHECK_NULL(check2, "T2: getValue name", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+int
+T3(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   SessionDetails     outSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb * pNDB = (Ndb *) obj;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T3-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T3-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T3-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T3-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T3-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T3-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T3-2: getValue allow_read", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+    
+    DEBUG("reading - ");
+
+    /* Operation 3 */
+
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->readTuple();
+    CHECK_MINUS_ONE(check, "T3-3: readTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T3-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-3: equal server id",
+		    MyTransaction);
+    
+    check2 = MyOperation->getValue(IND_SESSION_DATA, 
+				   (char *)outSessionDetails);
+    CHECK_NULL(check2, "T3-3: getValue session details", 
+	       MyTransaction);
+    
+    /* Operation 4 */
+
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T3-4: inc value",
+		    MyTransaction);
+    
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit\n");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T4(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   const SessionDetails     inSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  Ndb * pNDB = (Ndb *) obj;  
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  NdbOperation * MyOperation = 0;
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T4-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T4-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T4-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T4-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T4-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T4-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-1: NoCommit", 
+		  MyTransaction);
+
+    /* Operation 2 */
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T4-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T4-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T4-2: getValue allow_insert", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+
+    DEBUG("inserting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->insertTuple();
+    CHECK_MINUS_ONE(check, "T4-3: insertTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-3: equal server id",
+		    MyTransaction);
+    
+    check = MyOperation->setValue(SESSION_DATA, 
+				   (char *)inSessionDetails);
+    CHECK_MINUS_ONE(check, "T4-3: setValue session details", 
+	       MyTransaction);
+
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T4-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T4-4: inc value",
+		    MyTransaction);
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T4-5: inc value",
+		    MyTransaction);
+        
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T5(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb           * pNDB = (Ndb *) obj;  
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTupleExclusive();
+  CHECK_MINUS_ONE(check, "T5-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T5-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T5-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T5-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T5-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T5-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T5-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T5-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T5-2: getValue allow_delete", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    DEBUG("deleting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->deleteTuple();
+    CHECK_MINUS_ONE(check, "T5-3: deleteTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-3: equal server id",
+		    MyTransaction);
+    
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    CHECK_NULL(MyOperation, "T5-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-4: equal number",
+		    MyTransaction);
+
+    check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS, 
+				  (uint32)inServerBit);
+    CHECK_MINUS_ONE(check, "T5-4: dec value",
+		    MyTransaction);
+        
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+    CHECK_MINUS_ONE(check, "T5-5: inc value",
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e652c7bfed8a075797941b30e7eba451fe7e4435
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp
@@ -0,0 +1,770 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+int 
+T1(void * obj,
+   const SubscriberNumber number, 
+   const Location new_location, 
+   const ChangedBy changed_by, 
+   const ChangedTime changed_time,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+  
+  check = MyOperation->updateTuple();
+  CHECK_MINUS_ONE(check, "T1: updateTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T1: equal subscriber",
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)&new_location);
+  CHECK_MINUS_ONE(check, "T1: setValue location", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+				changed_by);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_by", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+				changed_time);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_time", 
+		  MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T1: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+int
+T2(void * obj,
+   const SubscriberNumber number, 
+   Location * readLocation, 
+   ChangedBy changed_by, 
+   ChangedTime changed_time,
+   SubscriberName subscriberName,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T2: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)readLocation);
+  CHECK_NULL(check2, "T2: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 changed_by);
+  CHECK_NULL(check2, "T2: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 changed_time);
+  CHECK_NULL(check2, "T2: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME, 
+				subscriberName);
+  CHECK_NULL(check2, "T2: getValue name", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+int
+T3(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   SessionDetails     outSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+    
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T3-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T3-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T3-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T3-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T3-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T3-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T3-2: getValue allow_read", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+    
+    DEBUG("reading - ");
+
+    /* Operation 3 */
+
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->readTuple();
+    CHECK_MINUS_ONE(check, "T3-3: readTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T3-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-3: equal server id",
+		    MyTransaction);
+    
+    check2 = MyOperation->getValue(IND_SESSION_DATA, 
+				   (char *)outSessionDetails);
+    CHECK_NULL(check2, "T3-3: getValue session details", 
+	       MyTransaction);
+    
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T3-4: inc value",
+		    MyTransaction);
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit...");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  DEBUG("done\n");
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T4(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   const SessionDetails     inSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  Ndb * pNDB = (Ndb *) obj;  
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->interpretedUpdateTuple();
+  CHECK_MINUS_ONE(check, "T4-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T4-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T4-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T4-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T4-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T4-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS, 
+				(uint32)inServerBit);
+  CHECK_MINUS_ONE(check, "T4-4: inc value",
+		  MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-1: NoCommit", 
+		  MyTransaction);
+
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T4-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T4-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T4-2: getValue allow_insert", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+  
+    DEBUG("inserting - ");
+  
+    /* Operation 3 */
+    
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->insertTuple();
+    CHECK_MINUS_ONE(check, "T4-3: insertTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-3: equal server id",
+		    MyTransaction);
+    
+    check = MyOperation->setValue(SESSION_DATA, 
+				   (char *)inSessionDetails);
+    CHECK_MINUS_ONE(check, "T4-3: setValue session details", 
+	       MyTransaction);
+    
+    /* Operation 4 */
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T4-5: inc value",
+		    MyTransaction);
+        
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T5(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  Ndb           * pNDB = (Ndb *) obj;  
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->interpretedUpdateTuple();
+  CHECK_MINUS_ONE(check, "T5-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T5-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T5-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T5-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T5-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T5-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS, 
+				(uint32)inServerBit);
+  CHECK_MINUS_ONE(check, "T5-4: dec value",
+		  MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T5-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T5-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T5-2: getValue allow_delete", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    DEBUG("deleting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->deleteTuple();
+    CHECK_MINUS_ONE(check, "T5-3: deleteTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-3: equal server id",
+		    MyTransaction);
+    
+    /* Operation 4 */
+        
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+    CHECK_MINUS_ONE(check, "T5-5: inc value",
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..86580008d109b471a6511ff74af2519427df288d
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp
@@ -0,0 +1,769 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+extern "C" {
+#include "user_transaction.h"
+};
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <time.h>
+#include <NdbApi.hpp>
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+int
+T1(void * obj,
+   const SubscriberNumber number, 
+   const Location new_location, 
+   const ChangedBy changed_by, 
+   const ChangedTime changed_time,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+  
+  check = MyOperation->updateTuple();
+  CHECK_MINUS_ONE(check, "T1: updateTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T1: equal subscriber",
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)&new_location);
+  CHECK_MINUS_ONE(check, "T1: setValue location", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+				changed_by);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_by", 
+		  MyTransaction);
+
+  check = MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+				changed_time);
+  CHECK_MINUS_ONE(check, "T1: setValue changed_time", 
+		  MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T1: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+int
+T2(void * obj,
+   const SubscriberNumber number, 
+   Location * readLocation, 
+   ChangedBy changed_by, 
+   ChangedTime changed_time,
+   SubscriberName subscriberName,
+   BenchmarkTime * transaction_time){
+
+  Ndb * pNDB = (Ndb *) obj;
+
+  DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     number);
+  CHECK_MINUS_ONE(check, "T2: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				(char *)readLocation);
+  CHECK_NULL(check2, "T2: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 changed_by);
+  CHECK_NULL(check2, "T2: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 changed_time);
+  CHECK_NULL(check2, "T2: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_NAME, 
+				subscriberName);
+  CHECK_NULL(check2, "T2: getValue name", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(transaction_time);
+  time_diff(transaction_time, &start);
+  return 0;
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+int
+T3(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   SessionDetails     outSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb * pNDB = (Ndb *) obj;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+    
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T3-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T3-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T3-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T3-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T3-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T3-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T3-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T3-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_READ, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T3-2: getValue allow_read", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+    
+    DEBUG("reading - ");
+
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->simpleRead();
+    CHECK_MINUS_ONE(check, "T3-3: readTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T3-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-3: equal server id",
+		    MyTransaction);
+    
+    check2 = MyOperation->getValue(IND_SESSION_DATA, 
+				   (char *)outSessionDetails);
+    CHECK_NULL(check2, "T3-3: getValue session details", 
+	       MyTransaction);
+    
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T3-4: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T3-4: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T3-4: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T3-4: inc value",
+		    MyTransaction);
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit...");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  DEBUG("done\n");
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T4(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   const SessionDetails     inSessionDetails,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+
+  Ndb * pNDB = (Ndb *) obj;  
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), 0);
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->interpretedUpdateTuple();
+  CHECK_MINUS_ONE(check, "T4-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T4-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T4-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T4-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T4-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T4-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T4-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyOperation->incValue(IND_SUBSCRIBER_SESSIONS, 
+				(uint32)inServerBit);
+  CHECK_MINUS_ONE(check, "T4-4: inc value",
+		  MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-1: NoCommit", 
+		  MyTransaction);
+
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T4-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T4-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_INSERT, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T4-2: getValue allow_insert", 
+	     MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+  
+    DEBUG("inserting - ");
+  
+    /* Operation 3 */
+    
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->insertTuple();
+    CHECK_MINUS_ONE(check, "T4-3: insertTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T4-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-3: equal server id",
+		    MyTransaction);
+    
+    check = MyOperation->setValue(SESSION_DATA, 
+				   (char *)inSessionDetails);
+    CHECK_MINUS_ONE(check, "T4-3: setValue session details", 
+	       MyTransaction);
+    
+    /* Operation 4 */
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T4-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T4-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T4-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+    CHECK_MINUS_ONE(check, "T4-5: inc value",
+		    MyTransaction);
+        
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+int
+T5(void * obj,
+   const SubscriberNumber   inNumber,
+   const SubscriberSuffix   inSuffix,
+   const ServerId           inServerId,
+   const ServerBit          inServerBit,
+   ChangedBy          outChangedBy,
+   ChangedTime        outChangedTime,
+   Location         * outLocation,
+   DoRollback         inDoRollback,
+   BranchExecuted   * outBranchExecuted,
+   BenchmarkTime    * outTransactionTime){
+  
+  Ndb           * pNDB = (Ndb *) obj;  
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  GroupId        groupId;
+  ActiveSessions sessions;
+  Permission     permission;
+
+  BenchmarkTime start;
+  get_time(&start);
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), 0);
+  
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  check = MyOperation->interpretedUpdateTuple();
+  CHECK_MINUS_ONE(check, "T5-1: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  CHECK_MINUS_ONE(check, "T5-1: equal subscriber",
+		  MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+				 (char *)outLocation);
+  CHECK_NULL(check2, "T5-1: getValue location", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+				 outChangedBy);
+  CHECK_NULL(check2, "T5-1: getValue changed_by", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                                 outChangedTime);
+  CHECK_NULL(check2, "T5-1: getValue changed_time",
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+				 (char *)&groupId);
+  CHECK_NULL(check2, "T5-1: getValue group", 
+	     MyTransaction);
+
+  check2 = MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+				 (char *)&sessions);
+  CHECK_NULL(check2, "T5-1: getValue sessions", 
+	     MyTransaction);
+  
+  check = MyOperation->subValue(IND_SUBSCRIBER_SESSIONS, 
+				(uint32)inServerBit);
+  CHECK_MINUS_ONE(check, "T5-4: dec value",
+		  MyTransaction);
+
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  check = MyOperation->readTuple();
+  CHECK_MINUS_ONE(check, "T5-2: readTuple", 
+		  MyTransaction);
+  
+  check = MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  CHECK_MINUS_ONE(check, "T5-2: equal group",
+		  MyTransaction);
+  
+  check2 = MyOperation->getValue(IND_GROUP_ALLOW_DELETE, 
+				 (char *)&permission);
+  CHECK_NULL(check2, "T5-2: getValue allow_delete", 
+	     MyTransaction);
+  
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    DEBUG("deleting - ");
+  
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    check = MyOperation->deleteTuple();
+    CHECK_MINUS_ONE(check, "T5-3: deleteTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SESSION_SUBSCRIBER,
+			       (char*)inNumber);
+    CHECK_MINUS_ONE(check, "T5-3: equal number",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SESSION_SERVER,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-3: equal server id",
+		    MyTransaction);
+    
+    /* Operation 4 */
+        
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    check = MyOperation->interpretedUpdateTuple();
+    CHECK_MINUS_ONE(check, "T5-5: interpretedUpdateTuple", 
+		    MyTransaction);
+    
+    check = MyOperation->equal(IND_SERVER_ID,
+			       (char*)&inServerId);
+    CHECK_MINUS_ONE(check, "T5-5: equal serverId",
+		    MyTransaction);
+
+    check = MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+			       (char*)inSuffix);
+    CHECK_MINUS_ONE(check, "T5-5: equal suffix",
+		    MyTransaction);
+
+    check = MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+    CHECK_MINUS_ONE(check, "T5-5: inc value",
+		    MyTransaction);
+
+    (* outBranchExecuted) = 1;
+  } else {
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+    (* outBranchExecuted) = 0;
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  get_time(outTransactionTime);
+  time_diff(outTransactionTime, &start);
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp b/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..262f38e9ffba38d68e426fb7e179b0c78a21bd4a
--- /dev/null
+++ b/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp
@@ -0,0 +1,561 @@
+/* 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 */
+
+//#define DEBUG_ON
+
+#include <string.h>
+#include "userHandle.h"
+#include "userInterface.h"
+
+#include "macros.h"
+#include "ndb_schema.hpp"
+#include "ndb_error.hpp"
+
+#include <NdbApi.hpp>
+
+
+void
+userCheckpoint(UserHandle *uh){
+}
+
+inline
+NdbConnection *
+startTransaction(Ndb * pNDB, ServerId inServerId, const SubscriberNumber inNumber){
+  
+  const int keyDataLenBytes    = sizeof(ServerId)+SUBSCRIBER_NUMBER_LENGTH;
+  const int keyDataLen_64Words = keyDataLenBytes >> 3;
+
+  Uint64 keyDataBuf[keyDataLen_64Words+1]; // The "+1" is for rounding...
+  
+  char     * keyDataBuf_charP = (char *)&keyDataBuf[0];
+  Uint32  * keyDataBuf_wo32P = (Uint32 *)&keyDataBuf[0];
+  
+  // Server Id comes first
+  keyDataBuf_wo32P[0] = inServerId;
+  // Then subscriber number
+  memcpy(&keyDataBuf_charP[sizeof(ServerId)], inNumber, SUBSCRIBER_NUMBER_LENGTH);
+
+  return pNDB->startTransaction(0, keyDataBuf_charP, keyDataLenBytes);
+}
+
+/**
+ * Transaction 1 - T1 
+ *
+ * Update location and changed by/time on a subscriber
+ *
+ * Input: 
+ *   SubscriberNumber,
+ *   Location,
+ *   ChangedBy,
+ *   ChangedTime
+ *
+ * Output:
+ */
+void
+userTransaction_T1(UserHandle * uh,
+		   SubscriberNumber number, 
+		   Location new_location, 
+		   ChangedBy changed_by, 
+		   ChangedTime changed_time){
+  Ndb * pNDB = uh->pNDB;
+
+  DEBUG2("T1(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction != NULL) {
+    NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+    if (MyOperation != NULL) {  
+      MyOperation->updateTuple();  
+      MyOperation->equal(IND_SUBSCRIBER_NUMBER,
+                         number);
+      MyOperation->setValue(IND_SUBSCRIBER_LOCATION, 
+		            (char *)&new_location);
+      MyOperation->setValue(IND_SUBSCRIBER_CHANGED_BY, 
+			    changed_by);
+      MyOperation->setValue(IND_SUBSCRIBER_CHANGED_TIME, 
+			    changed_time);
+      check = MyTransaction->execute( Commit );
+      if (check != -1) {
+        pNDB->closeTransaction(MyTransaction);
+        return;
+      } else {
+        CHECK_MINUS_ONE(check, "T1: Commit", 
+		        MyTransaction);
+      }//if
+    } else {
+      CHECK_NULL(MyOperation, "T1: getNdbOperation", MyTransaction);
+    }//if
+  } else {
+    error_handler("T1-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+  }//if
+}
+
+/**
+ * Transaction 2 - T2
+ *
+ * Read from Subscriber:
+ *
+ * Input: 
+ *   SubscriberNumber
+ *
+ * Output:
+ *   Location
+ *   Changed by
+ *   Changed Timestamp
+ *   Name
+ */
+void
+userTransaction_T2(UserHandle * uh,
+		   SubscriberNumber number, 
+		   Location * readLocation, 
+		   ChangedBy changed_by, 
+		   ChangedTime changed_time,
+		   SubscriberName subscriberName){
+  Ndb * pNDB = uh->pNDB;
+
+  DEBUG2("T2(%.*s):\n", SUBSCRIBER_NUMBER_LENGTH, number);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T2-1: startTransaction", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T2: getNdbOperation", 
+	     MyTransaction);
+  
+  MyOperation->readTuple();
+  MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+		     number);
+  MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+			(char *)readLocation);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+			changed_by);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                        changed_time);
+  MyOperation->getValue(IND_SUBSCRIBER_NAME, 
+			subscriberName);
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T2: Commit", 
+		  MyTransaction);  
+  pNDB->closeTransaction(MyTransaction);
+}
+
+/**
+ * Transaction 3 - T3
+ *
+ * Read session details
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *
+ * Output:
+ *   BranchExecuted
+ *   SessionDetails
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ */
+void
+userTransaction_T3(UserHandle * uh,
+		   SubscriberNumber   inNumber,
+		   ServerId           inServerId,
+		   ServerBit          inServerBit,
+		   SessionDetails     outSessionDetails,
+		   BranchExecuted   * outBranchExecuted){
+  Ndb * pNDB = uh->pNDB;
+
+  char               outChangedBy   [sizeof(ChangedBy)  +(4-(sizeof(ChangedBy)   & 3))];
+  char               outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+  Location           outLocation;
+  GroupId            groupId;
+  ActiveSessions     sessions;
+  Permission         permission;
+  SubscriberSuffix   inSuffix;
+
+  DEBUG3("T3(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = startTransaction(pNDB, inServerId, inNumber);
+  if (MyTransaction == NULL)	  
+    error_handler("T3-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T3-1: getNdbOperation", 
+	     MyTransaction);
+    
+  MyOperation->readTuple();
+  MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+			     inNumber);
+  MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+			(char *)&outLocation);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+			outChangedBy);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                        outChangedTime);
+  MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+			(char *)&groupId);
+  MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+			(char *)&sessions);
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-1: NoCommit", 
+		  MyTransaction);
+  
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T3-2: getNdbOperation", 
+	     MyTransaction);
+  
+  
+  MyOperation->readTuple();
+  MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  MyOperation->getValue(IND_GROUP_ALLOW_READ, 
+			(char *)&permission);
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T3-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+
+    memcpy(inSuffix,
+	   &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    DEBUG2("reading(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+    
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T3-3: getNdbOperation", 
+	       MyTransaction);
+    
+    MyOperation->simpleRead();
+  
+    MyOperation->equal(IND_SESSION_SUBSCRIBER,
+		       (char*)inNumber);
+    MyOperation->equal(IND_SESSION_SERVER,
+		       (char*)&inServerId);
+    MyOperation->getValue(IND_SESSION_DATA, 
+			  (char *)outSessionDetails);
+    /* Operation 4 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T3-4: getNdbOperation", 
+	       MyTransaction);
+    
+    MyOperation->interpretedUpdateTuple();
+    MyOperation->equal(IND_SERVER_ID,
+		       (char*)&inServerId);
+    MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		        (char*)inSuffix);
+    MyOperation->incValue(IND_SERVER_READS, (uint32)1);
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+  }
+  DEBUG("commit...");
+  check = MyTransaction->execute( Commit ); 
+  CHECK_MINUS_ONE(check, "T3: Commit", 
+		  MyTransaction);
+  
+  pNDB->closeTransaction(MyTransaction);
+  
+  DEBUG("done\n");
+}
+
+
+/**
+ * Transaction 4 - T4
+ * 
+ * Create session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   SessionDetails,
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+userTransaction_T4(UserHandle * uh,
+		   SubscriberNumber   inNumber,
+		   ServerId           inServerId,
+		   ServerBit          inServerBit,
+		   SessionDetails     inSessionDetails,
+		   DoRollback         inDoRollback,
+		   BranchExecuted   * outBranchExecuted){
+  
+  Ndb * pNDB = uh->pNDB;
+  
+  char               outChangedBy   [sizeof(ChangedBy)  +(4-(sizeof(ChangedBy)   & 3))];
+  char               outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+  Location         outLocation;
+  GroupId          groupId;
+  ActiveSessions   sessions;
+  Permission       permission;
+  SubscriberSuffix inSuffix;
+
+  DEBUG3("T4(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  int check;
+  NdbRecAttr * check2;
+
+  NdbConnection * MyTransaction = startTransaction(pNDB, inServerId, inNumber);
+  if (MyTransaction == NULL)	  
+    error_handler("T4-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+
+  NdbOperation *MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T4-1: getNdbOperation", 
+	     MyTransaction);
+  
+  MyOperation->interpretedUpdateTuple();
+  MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+		     inNumber);
+  MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+			(char *)&outLocation);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+		        outChangedBy);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                        outChangedTime);
+  MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+			(char *)&groupId);
+  MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+			(char *)&sessions); 
+  MyOperation->incValue(IND_SUBSCRIBER_SESSIONS, 
+			(uint32)inServerBit);
+  check = MyTransaction->execute( NoCommit ); 
+
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T4-2: getNdbOperation", 
+	     MyTransaction);
+  
+  MyOperation->readTuple();
+  MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  MyOperation->getValue(IND_GROUP_ALLOW_INSERT, 
+			(char *)&permission);
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T4-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == 0)){
+  
+    memcpy(inSuffix,
+	   &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+
+    DEBUG2("inserting(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+  
+    /* Operation 3 */
+    
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T4-3: getNdbOperation", 
+	       MyTransaction);
+    
+    MyOperation->insertTuple();
+    MyOperation->equal(IND_SESSION_SUBSCRIBER,
+		      (char*)inNumber);
+    MyOperation->equal(IND_SESSION_SERVER,
+		       (char*)&inServerId);
+    MyOperation->setValue(SESSION_DATA, 
+			  (char *)inSessionDetails);
+    /* Operation 4 */
+
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T4-5: getNdbOperation", 
+	       MyTransaction);
+    
+    MyOperation->interpretedUpdateTuple();
+    MyOperation->equal(IND_SERVER_ID,
+		       (char*)&inServerId);
+    MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		       (char*)inSuffix);
+    MyOperation->incValue(IND_SERVER_INSERTS, (uint32)1);
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T4: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T4:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+}
+
+
+/**
+ * Transaction 5 - T5
+ * 
+ * Delete session
+ *
+ * Input:
+ *   SubscriberNumber
+ *   ServerId
+ *   ServerBit
+ *   DoRollback
+ * Output:
+ *   ChangedBy
+ *   ChangedTime
+ *   Location
+ *   BranchExecuted
+ */
+void
+userTransaction_T5(UserHandle * uh,
+		   SubscriberNumber   inNumber,
+		   ServerId           inServerId,
+		   ServerBit          inServerBit,
+		   DoRollback         inDoRollback,
+		   BranchExecuted   * outBranchExecuted){
+  Ndb * pNDB = uh->pNDB;
+
+  DEBUG3("T5(%.*s, %.2d): ", SUBSCRIBER_NUMBER_LENGTH, inNumber, inServerId);
+
+  NdbConnection * MyTransaction = 0;
+  NdbOperation  * MyOperation = 0;
+
+  char             outChangedBy   [sizeof(ChangedBy)  +(4-(sizeof(ChangedBy)   & 3))];
+  char             outChangedTime [sizeof(ChangedTime)+(4-(sizeof(ChangedTime) & 3))];
+  Location         outLocation;
+  GroupId          groupId;
+  ActiveSessions   sessions;
+  Permission       permission;
+  SubscriberSuffix inSuffix;
+
+  int check;
+  NdbRecAttr * check2;
+
+  MyTransaction = pNDB->startTransaction();
+  if (MyTransaction == NULL)	  
+    error_handler("T5-1: startTranscation", pNDB->getNdbErrorString(), pNDB->getNdbError());
+  
+  MyOperation= MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "T5-1: getNdbOperation", 
+	     MyTransaction);
+  
+  MyOperation->interpretedUpdateTuple();
+  MyOperation->equal(IND_SUBSCRIBER_NUMBER, 
+		     inNumber);
+  MyOperation->getValue(IND_SUBSCRIBER_LOCATION, 
+		        (char *)&outLocation);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_BY, 
+			&outChangedBy[0]);
+  MyOperation->getValue(IND_SUBSCRIBER_CHANGED_TIME, 
+                        &outChangedTime[0]);
+  MyOperation->getValue(IND_SUBSCRIBER_GROUP,
+		        (char *)&groupId);
+  MyOperation->getValue(IND_SUBSCRIBER_SESSIONS,
+		        (char *)&sessions);
+  MyOperation->subValue(IND_SUBSCRIBER_SESSIONS, 
+		        (uint32)inServerBit);
+  MyTransaction->execute( NoCommit ); 
+    /* Operation 2 */
+
+  MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "T5-2: getNdbOperation", 
+	     MyTransaction);
+    
+  MyOperation->readTuple();
+  MyOperation->equal(IND_GROUP_ID,
+		     (char*)&groupId);
+  MyOperation->getValue(IND_GROUP_ALLOW_DELETE, 
+			(char *)&permission);
+  check = MyTransaction->execute( NoCommit ); 
+  CHECK_MINUS_ONE(check, "T5-2: NoCommit", 
+		  MyTransaction);
+  
+  if(((permission & inServerBit) == inServerBit) &&
+     ((sessions   & inServerBit) == inServerBit)){
+  
+    memcpy(inSuffix,
+	   &inNumber[SUBSCRIBER_NUMBER_LENGTH-SUBSCRIBER_NUMBER_SUFFIX_LENGTH], SUBSCRIBER_NUMBER_SUFFIX_LENGTH);
+    
+    DEBUG2("deleting(%.*s) - ", SUBSCRIBER_NUMBER_SUFFIX_LENGTH, inSuffix);
+
+    /* Operation 3 */
+    MyOperation = MyTransaction->getNdbOperation(SESSION_TABLE);
+    CHECK_NULL(MyOperation, "T5-3: getNdbOperation", 
+	       MyTransaction);
+    
+    MyOperation->deleteTuple();
+    MyOperation->equal(IND_SESSION_SUBSCRIBER,
+		       (char*)inNumber);
+    MyOperation->equal(IND_SESSION_SERVER,
+		       (char*)&inServerId);
+    /* Operation 4 */
+        
+    /* Operation 5 */
+    MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+    CHECK_NULL(MyOperation, "T5-5: getNdbOperation", 
+	       MyTransaction);
+    
+    
+    MyOperation->interpretedUpdateTuple();
+    MyOperation->equal(IND_SERVER_ID,
+		       (char*)&inServerId);
+    MyOperation->equal(IND_SERVER_SUBSCRIBER_SUFFIX,
+		       (char*)inSuffix);
+    MyOperation->incValue(IND_SERVER_DELETES, (uint32)1);
+    (* outBranchExecuted) = 1;
+  } else {
+    (* outBranchExecuted) = 0;
+    DEBUG1("%s", ((permission & inServerBit) ? "permission - " : "no permission - "));
+    DEBUG1("%s", ((sessions   & inServerBit) ? "in session - " : "no in session - "));
+  }
+
+  if(!inDoRollback && (* outBranchExecuted)){
+    DEBUG("commit\n");
+    check = MyTransaction->execute( Commit ); 
+    CHECK_MINUS_ONE(check, "T5: Commit", 
+		    MyTransaction);
+  } else {
+    DEBUG("rollback\n");
+    check = MyTransaction->execute(Rollback);
+    CHECK_MINUS_ONE(check, "T5:Rollback", 
+		    MyTransaction);
+    
+  }
+  
+  pNDB->closeTransaction(MyTransaction);
+}
+
diff --git a/ndb/test/ndbapi/bench/testData.h b/ndb/test/ndbapi/bench/testData.h
new file mode 100644
index 0000000000000000000000000000000000000000..3db85e7342e3ac7f61c3f49345a1abb73c5e2610
--- /dev/null
+++ b/ndb/test/ndbapi/bench/testData.h
@@ -0,0 +1,156 @@
+/* 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 */
+
+#ifndef TESTDATA_H
+#define TESTDATA_H
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+#include <NdbTick.h>
+#include <NdbThread.h>
+#include <NDBT_Stats.hpp>
+#include <random.h>
+#include "testDefinitions.h"
+
+/***************************************************************
+* M A C R O S                                                  *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+#define NUM_TRANSACTION_TYPES    5
+#define SESSION_LIST_LENGTH   1000
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+typedef struct {
+  SubscriberNumber subscriberNumber;
+  ServerId         serverId;
+} SessionElement;
+
+typedef struct {
+  SessionElement list[SESSION_LIST_LENGTH];
+  unsigned int readIndex;
+  unsigned int writeIndex;
+  unsigned int numberInList;
+} SessionList;  
+
+typedef struct {
+  unsigned int  count;
+  unsigned int  branchExecuted;
+  unsigned int  rollbackExecuted;
+
+  /**
+   * Latency measures
+   */
+  NDB_TICKS     startTime;
+  NDBT_Stats    latency;
+  unsigned int  latencyCounter;
+
+  inline void startLatency(){
+    if((latencyCounter & 127) == 127)
+      startTime = NdbTick_CurrentMillisecond();
+  }
+
+  inline void stopLatency(){
+    if((latencyCounter & 127) == 127){
+      const NDB_TICKS tmp = NdbTick_CurrentMillisecond() - startTime;
+      latency.addObservation(tmp);
+    }
+    latencyCounter++;
+  }
+} TransactionDefinition;
+
+typedef struct {
+  RandomSequence transactionSequence;
+  RandomSequence rollbackSequenceT4;
+  RandomSequence rollbackSequenceT5;
+  
+  TransactionDefinition transactions[NUM_TRANSACTION_TYPES];
+
+  unsigned int totalTransactions;
+    
+  double       outerLoopTime;
+  double       outerTps;
+  
+  SessionList  activeSessions;
+  
+} GeneratorStatistics;
+
+typedef enum{
+  Runnable,
+  Running
+} RunState ;
+
+typedef struct {
+  SubscriberNumber    number;	
+  SubscriberSuffix    suffix;
+  SubscriberName      name;
+  Location            location;
+  ChangedBy           changed_by;
+  ChangedTime         changed_time;
+  ServerId            server_id;
+  ServerBit           server_bit;
+  SessionDetails      session_details;
+
+  GroupId             group_id;
+  ActiveSessions      sessions;
+  Permission          permission;
+
+  unsigned int        do_rollback;
+
+  unsigned int        branchExecuted;
+  unsigned int        sessionElement;
+} TransactionData ;
+
+typedef struct {
+  struct NdbThread* pThread;
+
+  unsigned long randomSeed;
+  unsigned long changedTime;
+
+  unsigned int warmUpSeconds;
+  unsigned int testSeconds;
+  unsigned int coolDownSeconds;
+
+  GeneratorStatistics generator;
+  
+  /**
+   * For async execution
+   */
+  RunState          runState;
+  double            startTime;
+  TransactionData   transactionData;
+  struct Ndb      * pNDB;
+} ThreadData;
+
+/***************************************************************
+ * P U B L I C    F U N C T I O N S                             *
+ ***************************************************************/
+
+/***************************************************************
+ * E X T E R N A L   D A T A                                    *
+ ***************************************************************/
+
+
+
+#endif /* TESTDATA_H */
+
diff --git a/ndb/test/ndbapi/bench/testDefinitions.h b/ndb/test/ndbapi/bench/testDefinitions.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f4aeb309756e8b50060a62353e2bed0ee2cd9aa
--- /dev/null
+++ b/ndb/test/ndbapi/bench/testDefinitions.h
@@ -0,0 +1,90 @@
+/* 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 */
+
+#ifndef TESTDEFINITIONS_H
+#define TESTDEFINITIONS_H
+
+/***************************************************************/
+/* I N C L U D E D   F I L E S                                 */
+/***************************************************************/
+
+#include <ndb_types.h>
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+#define OP_PER_TRANS                  200
+#define NO_OF_SUBSCRIBERS             500000
+#define NO_OF_GROUPS                     100
+#define NO_OF_SERVERS                     20
+
+#define SUBSCRIBER_NUMBER_LENGTH          12
+#define SUBSCRIBER_NUMBER_SUFFIX_LENGTH    2
+
+#define SUBSCRIBER_NAME_LENGTH            32
+#define CHANGED_BY_LENGTH                 32
+#define CHANGED_TIME_LENGTH               32
+#define SESSION_DETAILS_LENGTH          2000
+#define SERVER_NAME_LENGTH                32
+#define GROUP_NAME_LENGTH                 32
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+#define PADDING 4
+
+typedef char   SubscriberNumber[SUBSCRIBER_NUMBER_LENGTH];
+typedef char   SubscriberSuffix[SUBSCRIBER_NUMBER_SUFFIX_LENGTH + 2];
+typedef char   SubscriberName[SUBSCRIBER_NAME_LENGTH];
+typedef char   ServerName[SERVER_NAME_LENGTH];
+typedef char   GroupName[GROUP_NAME_LENGTH];
+typedef char   ChangedBy[CHANGED_BY_LENGTH];
+typedef char   ChangedTime[CHANGED_TIME_LENGTH];
+typedef char   SessionDetails[SESSION_DETAILS_LENGTH];
+typedef Uint32 ServerId;
+typedef Uint32 ServerBit;
+typedef Uint32 GroupId;
+typedef Uint32 Location;
+typedef Uint32 Permission;
+
+typedef Uint32 Counter;
+typedef Uint32 ActiveSessions;
+typedef unsigned int BranchExecuted;
+typedef unsigned int DoRollback;
+
+/***************************************************************
+* P U B L I C    F U N C T I O N S                             *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L   D A T A                                    *
+***************************************************************/
+
+
+
+#endif /* TESTDEFINITIONS_H */
+
diff --git a/ndb/test/ndbapi/bench/userInterface.cpp b/ndb/test/ndbapi/bench/userInterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..128d20dc9bbc3bed81daddcd531c895ce41cc3d0
--- /dev/null
+++ b/ndb/test/ndbapi/bench/userInterface.cpp
@@ -0,0 +1,745 @@
+/* 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 */
+
+/***************************************************************
+* I N C L U D E D   F I L E S                                  *
+***************************************************************/
+
+#include <ndb_global.h>
+#ifndef NDB_WIN32
+#include <sys/time.h>
+#endif
+
+#include "ndb_error.hpp"
+#include "userInterface.h"
+#include <NdbThread.h>
+#include <NdbTick.h>
+#include <NdbMutex.h>
+#include <NdbSleep.h>
+#include "ndb_schema.hpp"
+#include <NDBT.hpp>
+#include <NdbSchemaCon.hpp>
+
+/***************************************************************
+* L O C A L   C O N S T A N T S                                *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   D A T A   S T R U C T U R E S                    *
+***************************************************************/
+
+/***************************************************************
+* L O C A L   F U N C T I O N S                                *
+***************************************************************/
+
+extern int localDbPrepare(UserHandle *uh);
+
+static int dbCreate(UserHandle *uh);
+
+/***************************************************************
+* L O C A L   D A T A                                          *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C   D A T A                                        *
+***************************************************************/
+
+
+/***************************************************************
+****************************************************************
+* L O C A L   F U N C T I O N S   C O D E   S E C T I O N      *
+****************************************************************
+***************************************************************/
+
+/***************************************************************
+****************************************************************
+* P U B L I C   F U N C T I O N S   C O D E   S E C T I O N    *
+****************************************************************
+***************************************************************/
+
+/*-----------------------------------*/
+/* Time related Functions            */
+/*                                   */
+/* Returns a double value in seconds */
+/*-----------------------------------*/
+double userGetTimeSync(void)
+{
+  static int initialized = 0;
+  static NDB_TICKS initSecs = 0;
+  static Uint32 initMicros = 0;
+  double timeValue = 0;
+
+  if ( !initialized ) {
+    initialized = 1;
+    NdbTick_CurrentMicrosecond(&initSecs, &initMicros);  
+    timeValue = 0.0;
+  } else {
+    NDB_TICKS secs = 0;
+    Uint32 micros = 0;
+  
+    NdbTick_CurrentMicrosecond(&secs, &micros);
+
+    double s  = (double)secs  - (double)initSecs;
+    double us = (double)secs - (double)initMicros;
+    
+    timeValue = s + (us / 1000000.0);
+  }
+
+  return timeValue;
+}
+
+// 0 - OK
+// 1 - Retry transaction
+// 2 - Permanent
+int 
+userDbCommit(UserHandle *uh){
+  if(uh->pCurrTrans != 0){
+    int check = uh->pCurrTrans->execute( Commit ); 
+    NdbError err = uh->pCurrTrans->getNdbError();
+    uh->pNDB->closeTransaction(uh->pCurrTrans);
+    uh->pCurrTrans = 0;
+    
+    if(err.status != NdbError::Success)
+      ndbout << err << endl;
+    
+    if(err.status == NdbError::TemporaryError && 
+       err.classification == NdbError::OverloadError){
+      NdbSleep_SecSleep(3);
+    }
+    
+    return err.status;
+  }
+  return 2;
+}
+
+/**
+ * TRUE - Normal table
+ * FALSE - Table w.o. checkpoing and logging
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+extern int useTableLogging;
+extern int useIndexTables;
+#ifdef	__cplusplus
+}
+#endif
+
+
+int
+create_table_server(Ndb * pNdb){
+  int check;
+  NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+  if( MySchemaTransaction == NULL )
+    error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+  
+  NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();	
+  if( MySchemaOp == NULL ) 
+    error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+  
+  // Create table
+  check = MySchemaOp->createTable( SERVER_TABLE,
+				   8,	     	// Table size
+				   TupleKey,	// Key Type
+				   1		// Nr of Pages
+				   ,DistributionGroup,
+				   6,
+				   78,
+				   80,
+				   1,
+				   useTableLogging
+                                   );
+  if( check == -1 ) 
+    error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+  
+  check = MySchemaOp->createAttribute
+    ( SERVER_SUBSCRIBER_SUFFIX,
+      TupleKey, 
+      sizeof(char) << 3,
+      SUBSCRIBER_NUMBER_SUFFIX_LENGTH,
+      String, 
+      MMBased,
+      NotNullAttribute,
+      NormalStorageAttribute,
+      0,
+      1,
+      16);
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber suffix)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  // Create first column, primary key 
+  check = MySchemaOp->createAttribute( SERVER_ID,
+				       TupleKey, 
+				       sizeof(ServerId) << 3,
+				       1,
+				       UnSigned, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (serverid)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+
+  check = MySchemaOp->createAttribute( SERVER_NAME,
+				       NoKey, 
+				       sizeof(char) << 3,
+				       SERVER_NAME_LENGTH,
+				       String, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (server name)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+
+  check = MySchemaOp->createAttribute( SERVER_READS,
+				       NoKey, 
+				       sizeof(Counter) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (server reads)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( SERVER_INSERTS,
+				       NoKey, 
+				       sizeof(Counter) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (server inserts)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( SERVER_DELETES,
+				       NoKey, 
+				       sizeof(Counter) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (server deletes)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  if( MySchemaTransaction->execute() == -1 ) {
+    error_handler("schemaTransaction->execute()", 
+		  MySchemaTransaction->getNdbError(), 0);
+  }    
+  NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+  return 0;
+}
+
+int
+create_table_group(Ndb * pNdb){
+  int check;
+
+  NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+  if( MySchemaTransaction == NULL )
+    error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+  
+  NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();	
+  if( MySchemaOp == NULL ) 
+    error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+  
+  // Create table
+  check = MySchemaOp->createTable( GROUP_TABLE,
+				   8,	     	// Table size
+				   TupleKey,	// Key Type
+				   1		// Nr of Pages
+				   ,All,
+				   6,
+				   78,
+				   80,
+				   1,
+				   useTableLogging
+                                   );
+
+  if( check == -1 ) 
+    error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+  
+  // Create first column, primary key 
+  check = MySchemaOp->createAttribute( GROUP_ID,
+				       TupleKey, 
+				       sizeof(GroupId) << 3,
+				       1,
+				       UnSigned, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (group id)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( GROUP_NAME,
+				       NoKey,
+				       sizeof(char) << 3,
+				       GROUP_NAME_LENGTH,
+				       String, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (group name)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+
+  check = MySchemaOp->createAttribute( GROUP_ALLOW_READ,
+				       NoKey, 
+				       sizeof(Permission) << 3,
+				       1,
+				       String, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (group read)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+
+  check = MySchemaOp->createAttribute( GROUP_ALLOW_INSERT,
+				       NoKey, 
+				       sizeof(Permission) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (group insert)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( GROUP_ALLOW_DELETE,
+				       NoKey, 
+				       sizeof(Permission) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (group delete)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  if( MySchemaTransaction->execute() == -1 ) {
+    error_handler("schemaTransaction->execute()", 
+		  MySchemaTransaction->getNdbError(), 0);
+  }    
+  NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+  return 0;
+}
+
+int
+create_table_subscriber(Ndb * pNdb){
+  int check;
+  NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+  if( MySchemaTransaction == NULL )
+    error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+  
+  NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();	
+  if( MySchemaOp == NULL ) 
+    error_handler("getNdbSchemaOp", MySchemaTransaction->getNdbError(), 0);
+  
+  // Create table
+  check = MySchemaOp->createTable( SUBSCRIBER_TABLE,
+				   8,	     	// Table size
+				   TupleKey,	// Key Type
+				   1		// Nr of Pages
+				   ,DistributionGroup,
+				   6,
+				   78,
+				   80,
+				   1,
+				   useTableLogging
+                                   );
+  if( check == -1 ) 
+    error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+  
+  // Create first column, primary key 
+  check = MySchemaOp->createAttribute
+    ( SUBSCRIBER_NUMBER,
+      TupleKey, 
+      sizeof(char) << 3,
+      SUBSCRIBER_NUMBER_LENGTH,
+      String, 
+      MMBased,
+      NotNullAttribute,
+      (useIndexTables ? IndexStorageAttribute : NormalStorageAttribute),
+      0,
+      1,
+      16);
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber number)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  check = MySchemaOp->createAttribute( SUBSCRIBER_NAME,
+				       NoKey, 
+				       sizeof(char) << 3,
+				       SUBSCRIBER_NAME_LENGTH,
+				       String, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber name)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+
+  check = MySchemaOp->createAttribute( SUBSCRIBER_GROUP,
+				       NoKey, 
+				       sizeof(GroupId) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber_group)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+
+  check = MySchemaOp->createAttribute( SUBSCRIBER_LOCATION,
+				       NoKey, 
+				       sizeof(Location) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (server reads)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( SUBSCRIBER_SESSIONS,
+				       NoKey, 
+				       sizeof(ActiveSessions) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber_sessions)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( SUBSCRIBER_CHANGED_BY,
+				       NoKey, 
+				       sizeof(char) << 3,
+				       CHANGED_BY_LENGTH,
+				       String,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber_changed_by)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  check = MySchemaOp->createAttribute( SUBSCRIBER_CHANGED_TIME,
+				       NoKey, 
+				       sizeof(char) << 3,
+				       CHANGED_TIME_LENGTH,
+				       String,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (subscriber_changed_time)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  if( MySchemaTransaction->execute() == -1 ) {
+    error_handler("schemaTransaction->execute()", 
+		  MySchemaTransaction->getNdbError(), 0);
+  }    
+  NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+  return 0;
+}
+
+int
+create_table_session(Ndb * pNdb){
+  int check;
+  NdbSchemaCon * MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pNdb);
+  if( MySchemaTransaction == NULL )
+    error_handler("startSchemaTransaction", pNdb->getNdbError(), 0);
+  
+  NdbSchemaOp * MySchemaOp = MySchemaTransaction->getNdbSchemaOp();	
+  if( MySchemaOp == NULL ) 
+    error_handler("getNdbSchemaOp", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  // Create table
+  check = MySchemaOp->createTable( SESSION_TABLE,
+				   8,	     	// Table size
+				   TupleKey,	// Key Type
+				   1		// Nr of Pages
+				   ,DistributionGroup,
+				   6,
+				   78,
+				   80,
+				   1,
+				   useTableLogging
+                                   );
+  if( check == -1 ) 
+    error_handler("createTable", MySchemaTransaction->getNdbError(), 0);
+  
+  check = MySchemaOp->createAttribute( SESSION_SUBSCRIBER,
+				       TupleKey, 
+				       sizeof(char) << 3,
+				       SUBSCRIBER_NUMBER_LENGTH,
+				       String, 
+				       MMBased,
+				       NotNullAttribute,
+				       NormalStorageAttribute,
+				       0,
+				       1,
+				       16);
+  if( check == -1 ) 
+    error_handler("createAttribute (session_subscriber)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+  // Create first column, primary key 
+  check = MySchemaOp->createAttribute( SESSION_SERVER,
+				       TupleKey, 
+				       sizeof(ServerId) << 3,
+				       1,
+				       UnSigned,
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (session_server)", 
+		  MySchemaTransaction->getNdbError(), 0);
+
+
+  check = MySchemaOp->createAttribute( SESSION_DATA,
+				       NoKey, 
+				       sizeof(char) << 3,
+				       SESSION_DETAILS_LENGTH,
+				       String, 
+				       MMBased,
+				       NotNullAttribute );
+  if( check == -1 ) 
+    error_handler("createAttribute (session_data)", 
+		  MySchemaTransaction->getNdbError(), 0);
+  
+  if( MySchemaTransaction->execute() == -1 ) {
+    error_handler("schemaTransaction->execute()", 
+		  MySchemaTransaction->getNdbError(), 0);
+  }    
+  NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
+  return 0;
+}
+
+void 
+create_table(const char * name, int (* function)(Ndb * pNdb), Ndb* pNdb){
+  printf("creating table %s...", name);
+  if(pNdb->getDictionary()->getTable(name) != 0){
+    printf(" it already exists\n");
+    return;
+  } else {
+    printf("\n");
+  }
+  function(pNdb);
+  printf("creating table %s... done\n", name);
+}
+
+static int dbCreate(Ndb * pNdb)
+{
+  create_table(SUBSCRIBER_TABLE, create_table_subscriber, pNdb);
+  create_table(GROUP_TABLE     , create_table_group, pNdb);
+  create_table(SESSION_TABLE   , create_table_session, pNdb);
+  create_table(SERVER_TABLE    , create_table_server, pNdb);
+  return 0;
+}
+
+#ifndef NDB_WIN32
+#include <unistd.h>
+#endif
+
+UserHandle*
+userDbConnect(uint32 createDb, char *dbName)
+{
+  Ndb_cluster_connection *con= new Ndb_cluster_connection();
+  if(con->connect(12, 5, 1) != 0)
+  {
+    ndbout << "Unable to connect to management server." << endl;
+    return 0;
+  }
+  if (con->wait_until_ready(30,0) < 0)
+  {
+    ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+    return 0;
+  }
+
+  Ndb * pNdb = new Ndb(con, dbName);
+  
+  //printf("Initializing...\n");
+  pNdb->init();
+  
+  //printf("Waiting...");
+  while(pNdb->waitUntilReady() != 0){
+    //printf("...");
+  }
+  //  printf("done\n");
+  
+  if( createDb )
+    dbCreate(pNdb);
+  
+
+  UserHandle * uh = new UserHandle;
+  uh->pNCC       = con;
+  uh->pNDB       = pNdb;
+  uh->pCurrTrans = 0;
+
+  return uh;
+}
+
+void userDbDisconnect(UserHandle *uh)
+{
+  delete uh;
+}
+
+int userDbInsertServer(UserHandle       *uh,
+                       ServerId         serverId,
+	               SubscriberSuffix suffix,
+	               ServerName       name)
+{
+  int check;
+
+  uint32 noOfRead   = 0;
+  uint32 noOfInsert = 0;
+  uint32 noOfDelete = 0;
+
+  NdbConnection * MyTransaction = 0;
+  if(uh->pCurrTrans != 0){
+    MyTransaction = uh->pCurrTrans;
+  } else {
+    uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+  }
+  if (MyTransaction == NULL)	  
+    error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+  
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SERVER_TABLE);
+  CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);
+  
+  check = MyOperation->insertTuple();
+  CHECK_MINUS_ONE(check, "insert tuple", MyTransaction);  
+  
+  check = MyOperation->equal(SERVER_ID, (char*)&serverId);
+  CHECK_MINUS_ONE(check, "setValue id", MyTransaction);  
+  
+  check = MyOperation->setValue(SERVER_SUBSCRIBER_SUFFIX, suffix);
+  CHECK_MINUS_ONE(check, "setValue suffix", MyTransaction);  
+
+  check = MyOperation->setValue(SERVER_NAME, name);
+  CHECK_MINUS_ONE(check, "setValue name", MyTransaction);  
+
+  check = MyOperation->setValue(SERVER_READS, (char*)&noOfRead);
+  CHECK_MINUS_ONE(check, "setValue reads", MyTransaction);  
+
+  check = MyOperation->setValue(SERVER_INSERTS, (char*)&noOfInsert);
+  CHECK_MINUS_ONE(check, "setValue inserts", MyTransaction);  
+
+  check = MyOperation->setValue(SERVER_DELETES, (char*)&noOfDelete);
+  CHECK_MINUS_ONE(check, "setValue deletes", MyTransaction);  
+
+  return 0;
+}
+
+int userDbInsertSubscriber(UserHandle      *uh,
+	                   SubscriberNumber number,
+                           uint32           groupId,
+	                   SubscriberName   name)
+{
+  int check;
+  uint32 activeSessions = 0;
+  Location l = 0;
+  ChangedBy changedBy; snprintf(changedBy, sizeof(changedBy), "ChangedBy");
+  ChangedTime changedTime; snprintf(changedTime, sizeof(changedTime), "ChangedTime"); 
+
+  NdbConnection * MyTransaction = 0;
+  if(uh->pCurrTrans != 0){
+    MyTransaction = uh->pCurrTrans;
+  } else {
+    uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+  }
+  if (MyTransaction == NULL)	  
+    error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+  
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(SUBSCRIBER_TABLE);
+  CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);
+  
+  check = MyOperation->insertTuple();
+  CHECK_MINUS_ONE(check, "insertTuple", MyTransaction);
+  
+  check = MyOperation->equal(SUBSCRIBER_NUMBER, number);
+  CHECK_MINUS_ONE(check, "equal", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_NAME, name);
+  CHECK_MINUS_ONE(check, "setValue name", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_GROUP, (char*)&groupId);
+  CHECK_MINUS_ONE(check, "setValue group", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_LOCATION, (char*)&l);
+  CHECK_MINUS_ONE(check, "setValue location", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_SESSIONS, (char*)&activeSessions);
+  CHECK_MINUS_ONE(check, "setValue sessions", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_CHANGED_BY, changedBy);
+  CHECK_MINUS_ONE(check, "setValue changedBy", MyTransaction);
+
+  check = MyOperation->setValue(SUBSCRIBER_CHANGED_TIME, changedTime);
+  CHECK_MINUS_ONE(check, "setValue changedTime", MyTransaction);
+
+  return 0;
+}
+
+int userDbInsertGroup(UserHandle *uh,
+		      GroupId    groupId, 
+		      GroupName  name,
+		      Permission allowRead,
+		      Permission allowInsert,
+		      Permission allowDelete)
+{
+  int check;
+  
+  NdbConnection * MyTransaction = 0;
+  if(uh->pCurrTrans != 0){
+    MyTransaction = uh->pCurrTrans;
+  } else {
+    uh->pCurrTrans = MyTransaction = uh->pNDB->startTransaction();
+  }
+  if (MyTransaction == NULL)	  
+    error_handler("startTranscation", uh->pNDB->getNdbError(), 0);
+
+  NdbOperation *MyOperation = MyTransaction->getNdbOperation(GROUP_TABLE);
+  CHECK_NULL(MyOperation, "getNdbOperation", MyTransaction);  
+  
+  check = MyOperation->insertTuple();
+  CHECK_MINUS_ONE(check, "insertTuple", MyTransaction);  
+  
+  check = MyOperation->equal(GROUP_ID, (char*)&groupId);
+  CHECK_MINUS_ONE(check, "equal", MyTransaction);  
+  
+  check = MyOperation->setValue(GROUP_NAME, name);
+  CHECK_MINUS_ONE(check, "setValue name", MyTransaction);  
+
+  check = MyOperation->setValue(GROUP_ALLOW_READ, (char*)&allowRead);
+  CHECK_MINUS_ONE(check, "setValue allowRead", MyTransaction);  
+
+  check = MyOperation->setValue(GROUP_ALLOW_INSERT, (char*)&allowInsert);
+  CHECK_MINUS_ONE(check, "setValue allowInsert", MyTransaction);  
+
+  check = MyOperation->setValue(GROUP_ALLOW_DELETE, (char*)&allowDelete);
+  CHECK_MINUS_ONE(check, "setValue allowDelete", MyTransaction);  
+  
+  return 0;
+}
+
diff --git a/ndb/test/ndbapi/bench/userInterface.h b/ndb/test/ndbapi/bench/userInterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e3b6f8f2a5e6c978b8ce7aade36e15f8822eb34
--- /dev/null
+++ b/ndb/test/ndbapi/bench/userInterface.h
@@ -0,0 +1,151 @@
+/* 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 */
+
+#ifndef DBINTERFACE_H
+#define DBINTERFACE_H
+
+/***************************************************************/
+/* I N C L U D E D   F I L E S                                 */
+/***************************************************************/
+
+#include "testDefinitions.h"
+#include "testData.h"
+
+/***************************************************************
+* M A C R O S                                                  *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+/*-----------------------*/
+/* Default Database Name */
+/*-----------------------*/
+#define DEFAULTDB "TestDbClient"
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+/***************************************************************
+* P U B L I C    F U N C T I O N S                             *
+***************************************************************/
+
+typedef struct Ndb Ndb;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  extern void showTime();
+  extern double userGetTime(void);
+  extern Ndb   *asyncDbConnect(int parallellism);
+  extern void    asyncDbDisconnect(Ndb* pNDB);
+
+  extern void start_T1(Ndb * uh, ThreadData * data, int async);
+  extern void start_T2(Ndb * uh, ThreadData * data, int async);
+  extern void start_T3(Ndb * uh, ThreadData * data, int async);
+  extern void start_T4(Ndb * uh, ThreadData * data, int async);
+  extern void start_T5(Ndb * uh, ThreadData * data, int async);
+  
+  extern void complete_T1(ThreadData * data);
+  extern void complete_T2(ThreadData * data);
+  extern void complete_T3(ThreadData * data);
+  extern void complete_T4(ThreadData * data);
+  extern void complete_T5(ThreadData * data);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/***************************************************************/
+/* I N C L U D E D   F I L E S                                 */
+/***************************************************************/
+
+#include "testDefinitions.h"
+
+/***************************************************************
+* M A C R O S                                                  *
+***************************************************************/
+
+/***************************************************************/
+/* C O N S T A N T S                                           */
+/***************************************************************/
+
+/*-----------------------*/
+/* Default Database Name */
+/*-----------------------*/
+#define DEFAULTDB "TestDbClient"
+
+/***************************************************************
+* D A T A   S T R U C T U R E S                                *
+***************************************************************/
+
+typedef struct {
+  struct Ndb_cluster_connection* pNCC;
+  struct Ndb           * pNDB;
+  struct NdbConnection * pCurrTrans;
+} UserHandle;
+
+/***************************************************************
+* P U B L I C    F U N C T I O N S                             *
+***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern double userGetTimeSync(void);
+
+extern void userCheckpoint(UserHandle *uh);
+
+extern UserHandle *userDbConnect(uint32 createDb, char *dbName);
+extern void        userDbDisconnect(UserHandle *uh);
+
+extern int userDbInsertServer(UserHandle      *uh,
+                              ServerId         serverId,
+	                      SubscriberSuffix suffix,
+	                      ServerName       name);
+
+extern int userDbInsertSubscriber(UserHandle      *uh,
+	                          SubscriberNumber number,
+                                  uint32           groupId,
+	                          SubscriberName   name);
+
+extern int userDbInsertGroup(UserHandle *uh,
+		             GroupId     groupId, 
+		             GroupName   name,
+		             Permission  allowRead,
+		             Permission  allowInsert,
+		             Permission  allowDelete);
+  
+  extern int userDbCommit(UserHandle *uh);
+  extern int userDbRollback(UserHandle *uh);
+  
+#ifdef __cplusplus
+}
+#endif
+
+/***************************************************************
+* E X T E R N A L   D A T A                                    *
+***************************************************************/
+
+#endif /* DBINTERFACE_H */
+