#At file:///home/marty/MySQL/mysql-5.1-telco-6.2_orig/
2973 Martin Skold 2009-09-07 [merge]
Merge
modified:
mysql-test/suite/ndb/r/ndb_auto_increment.result
mysql-test/suite/ndb/r/ndb_trigger.result
mysql-test/suite/ndb/t/ndb_auto_increment.test
mysql-test/suite/ndb/t/ndb_trigger.test
sql/ha_ndbcluster.cc
storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp
storage/ndb/src/kernel/blocks/ERROR_codes.txt
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
storage/ndb/test/ndbapi/testNdbApi.cpp
storage/ndb/test/run-test/autotest-boot.sh
storage/ndb/test/run-test/daily-basic-tests.txt
=== modified file 'mysql-test/suite/ndb/r/ndb_auto_increment.result'
--- a/mysql-test/suite/ndb/r/ndb_auto_increment.result 2008-01-25 09:43:30 +0000
+++ b/mysql-test/suite/ndb/r/ndb_auto_increment.result 2009-09-03 07:49:50 +0000
@@ -3,6 +3,9 @@ DROP TABLE IF EXISTS t1;
set @old_auto_increment_offset = @@session.auto_increment_offset;
set @old_auto_increment_increment = @@session.auto_increment_increment;
set @old_ndb_autoincrement_prefetch_sz = @@session.ndb_autoincrement_prefetch_sz;
+set @old_auto_increment_offset = @@session.auto_increment_offset;
+set @old_auto_increment_increment = @@session.auto_increment_increment;
+set @old_ndb_autoincrement_prefetch_sz = @@session.ndb_autoincrement_prefetch_sz;
flush status;
create table t1 (a int not null auto_increment primary key) engine ndb;
insert into t1 values (NULL);
@@ -443,3 +446,56 @@ set auto_increment_offset = @old_auto_in
set auto_increment_increment = @old_auto_increment_increment;
set ndb_autoincrement_prefetch_sz = @old_ndb_autoincrement_prefetch_sz;
drop table t1;
+set auto_increment_offset = @old_auto_increment_offset;
+set auto_increment_increment = @old_auto_increment_increment;
+set ndb_autoincrement_prefetch_sz = @old_ndb_autoincrement_prefetch_sz;
+CREATE TABLE `t1` (
+`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+`k` int(10) unsigned NOT NULL DEFAULT '0',
+`c` char(120) NOT NULL DEFAULT '',
+`pad` char(60) NOT NULL DEFAULT '',
+PRIMARY KEY (`id`),
+KEY `k` (`k`)
+) ENGINE=ndbcluster;
+CREATE TABLE `t2` (
+`evend_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+`timestamp` int(11) NOT NULL,
+`server_id` int(11) NOT NULL,
+PRIMARY KEY (`evend_id`)
+) ENGINE=ndbcluster;
+insert into t1 values (null,1,'',''),(null,2,'','');
+CREATE TRIGGER tr1
+AFTER UPDATE ON t1
+FOR EACH ROW
+BEGIN
+insert into t2(timestamp, server_id) values(UNIX_TIMESTAMP(),@@global.server_id);
+end;
+|
+CREATE TRIGGER tr1
+AFTER UPDATE ON t1
+FOR EACH ROW
+BEGIN
+insert into t2(timestamp, server_id) values(UNIX_TIMESTAMP(),@@global.server_id);
+end;
+|
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+update t1 set c='foobar' where id=1;
+select evend_id,server_id from t2 order by evend_id;
+evend_id server_id
+1 1
+2 2
+3 1
+4 2
+5 1
+6 2
+7 1
+8 2
+drop trigger tr1;
+drop table t1, t2;
+drop trigger if exists tr1;
=== modified file 'mysql-test/suite/ndb/r/ndb_trigger.result'
--- a/mysql-test/suite/ndb/r/ndb_trigger.result 2009-02-01 21:05:19 +0000
+++ b/mysql-test/suite/ndb/r/ndb_trigger.result 2009-09-03 07:50:51 +0000
@@ -340,4 +340,68 @@ trigger_name='trg1';
trigger_name event_object_table
trg1 t2
drop table t2;
+create table t1(c1 int(11) not null auto_increment primary key, c2 int(11) not null) engine=ndb;
+create trigger bi_t1 before insert on t1
+FOR EACH ROW BEGIN
+SET new.c2 = last_insert_id();
+End
+|
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+c1
+3
+select * from t1 order by c1;
+c1 c2
+1 0
+2 1
+3 2
+start transaction;
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+c1
+5
+select * from t1 order by c1;
+c1 c2
+1 0
+2 1
+3 2
+4 3
+5 4
+rollback;
+select c1 from t1 where c1=last_insert_id();
+c1
+select * from t1 order by c1;
+c1 c2
+1 0
+2 1
+3 2
+start transaction;
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+c1
+7
+select * from t1 order by c1;
+c1 c2
+1 0
+2 1
+3 2
+6 5
+7 6
+commit;
+select c1 from t1 where c1=last_insert_id();
+c1
+7
+select * from t1 order by c1;
+c1 c2
+1 0
+2 1
+3 2
+6 5
+7 6
+drop trigger bi_t1;
+drop table t1;
End of 5.1 tests
=== modified file 'mysql-test/suite/ndb/t/ndb_auto_increment.test'
--- a/mysql-test/suite/ndb/t/ndb_auto_increment.test 2007-11-06 09:57:49 +0000
+++ b/mysql-test/suite/ndb/t/ndb_auto_increment.test 2009-09-03 07:49:50 +0000
@@ -6,6 +6,9 @@ connection server1;
DROP TABLE IF EXISTS t1,t2;
connection server2;
DROP TABLE IF EXISTS t1;
+set @old_auto_increment_offset = @@session.auto_increment_offset;
+set @old_auto_increment_increment = @@session.auto_increment_increment;
+set @old_ndb_autoincrement_prefetch_sz = @@session.ndb_autoincrement_prefetch_sz;
connection server1;
--enable_warnings
@@ -291,3 +294,87 @@ set auto_increment_increment = @old_auto
set ndb_autoincrement_prefetch_sz = @old_ndb_autoincrement_prefetch_sz;
drop table t1;
+
+connection server2;
+set auto_increment_offset = @old_auto_increment_offset;
+set auto_increment_increment = @old_auto_increment_increment;
+set ndb_autoincrement_prefetch_sz = @old_ndb_autoincrement_prefetch_sz;
+
+# bug#46712 Auto_increment work incorrectly when using triggers and NDB Cluster
+#
+# Testing that auto_increment values are set correctly when inserting from
+# multiple SQL-nodes
+
+connection server1;
+
+CREATE TABLE `t1` (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `k` int(10) unsigned NOT NULL DEFAULT '0',
+ `c` char(120) NOT NULL DEFAULT '',
+ `pad` char(60) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY `k` (`k`)
+) ENGINE=ndbcluster;
+
+CREATE TABLE `t2` (
+ `evend_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `timestamp` int(11) NOT NULL,
+ `server_id` int(11) NOT NULL,
+ PRIMARY KEY (`evend_id`)
+) ENGINE=ndbcluster;
+
+
+insert into t1 values (null,1,'',''),(null,2,'','');
+
+DELIMITER |;
+
+CREATE TRIGGER tr1
+ AFTER UPDATE ON t1
+ FOR EACH ROW
+ BEGIN
+ insert into t2(timestamp, server_id) values(UNIX_TIMESTAMP(),@@global.server_id);
+ end;
+|
+
+DELIMITER ;|
+
+connection server2;
+
+DELIMITER |;
+
+CREATE TRIGGER tr1
+ AFTER UPDATE ON t1
+ FOR EACH ROW
+ BEGIN
+ insert into t2(timestamp, server_id) values(UNIX_TIMESTAMP(),@@global.server_id);
+ end;
+|
+
+DELIMITER ;|
+
+connection server1;
+update t1 set c='foobar' where id=1;
+connection server2;
+update t1 set c='foobar' where id=1;
+connection server1;
+update t1 set c='foobar' where id=1;
+connection server2;
+update t1 set c='foobar' where id=1;
+connection server1;
+update t1 set c='foobar' where id=1;
+connection server2;
+update t1 set c='foobar' where id=1;
+connection server1;
+update t1 set c='foobar' where id=1;
+connection server2;
+update t1 set c='foobar' where id=1;
+connection server1;
+select evend_id,server_id from t2 order by evend_id;
+
+drop trigger tr1;
+drop table t1, t2;
+
+connection server2;
+--disable_warnings
+drop trigger if exists tr1;
+--enable_warnings
=== modified file 'mysql-test/suite/ndb/t/ndb_trigger.test'
--- a/mysql-test/suite/ndb/t/ndb_trigger.test 2009-02-01 21:05:19 +0000
+++ b/mysql-test/suite/ndb/t/ndb_trigger.test 2009-09-03 07:50:51 +0000
@@ -258,4 +258,45 @@ trigger_name='trg1';
connection server1;
drop table t2;
+# bug#38034: last_insert_id() value not shown in table with trigger
+#
+# testing that last_insert_id is correct in ongoing transaction.
+
+create table t1(c1 int(11) not null auto_increment primary key, c2 int(11) not null) engine=ndb;
+
+delimiter |;
+
+create trigger bi_t1 before insert on t1
+FOR EACH ROW BEGIN
+ SET new.c2 = last_insert_id();
+End
+|
+
+delimiter ;|
+
+
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+select * from t1 order by c1;
+start transaction;
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+select * from t1 order by c1;
+rollback;
+select c1 from t1 where c1=last_insert_id();
+select * from t1 order by c1;
+start transaction;
+INSERT INTO t1 (c2) VALUES (17);
+INSERT INTO t1 (c2) VALUES (17);
+select c1 from t1 where c1=last_insert_id();
+select * from t1 order by c1;
+commit;
+select c1 from t1 where c1=last_insert_id();
+select * from t1 order by c1;
+drop trigger bi_t1;
+drop table t1;
+
--echo End of 5.1 tests
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2009-09-07 08:53:55 +0000
+++ b/sql/ha_ndbcluster.cc 2009-09-07 09:31:01 +0000
@@ -4243,6 +4243,8 @@ int ha_ndbcluster::reset()
m_ignore_dup_key= FALSE;
m_use_write= FALSE;
m_ignore_no_key= FALSE;
+ m_rows_inserted= (ha_rows) 0;
+ m_rows_to_insert= (ha_rows) 1;
m_delete_cannot_batch= FALSE;
m_update_cannot_batch= FALSE;
@@ -4312,10 +4314,18 @@ void ha_ndbcluster::start_bulk_insert(ha
if (rows == (ha_rows) 0)
{
/* We don't know how many will be inserted, guess */
- m_rows_to_insert= m_autoincrement_prefetch;
+ m_rows_to_insert=
+ (m_autoincrement_prefetch > NDB_DEFAULT_AUTO_PREFETCH)
+ ? m_autoincrement_prefetch
+ : NDB_DEFAULT_AUTO_PREFETCH;
+ m_autoincrement_prefetch= m_rows_to_insert;
}
else
- m_rows_to_insert= rows;
+ {
+ m_rows_to_insert= rows;
+ if (m_autoincrement_prefetch < m_rows_to_insert)
+ m_autoincrement_prefetch= m_rows_to_insert;
+ }
DBUG_VOID_RETURN;
}
@@ -4593,11 +4603,7 @@ int ha_ndbcluster::init_handler_for_stat
DBUG_ENTER("ha_ndbcluster::init_handler_for_statement");
// store thread specific data first to set the right context
m_force_send= thd->variables.ndb_force_send;
- m_autoincrement_prefetch=
- (thd->variables.ndb_autoincrement_prefetch_sz >
- NDB_DEFAULT_AUTO_PREFETCH) ?
- (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz
- : (ha_rows) NDB_DEFAULT_AUTO_PREFETCH;
+ m_autoincrement_prefetch= thd->variables.ndb_autoincrement_prefetch_sz;
m_thd_ndb= thd_ndb;
DBUG_ASSERT(m_thd_ndb->trans);
// Start of transaction
@@ -6543,26 +6549,11 @@ void ha_ndbcluster::get_auto_increment(u
ulonglong *first_value,
ulonglong *nb_reserved_values)
{
- uint cache_size;
Uint64 auto_value;
THD *thd= current_thd;
DBUG_ENTER("get_auto_increment");
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
Ndb *ndb= get_ndb(table->in_use);
-
- if (m_rows_inserted > m_rows_to_insert)
- {
- /* We guessed too low */
- m_rows_to_insert+= m_autoincrement_prefetch;
- }
- uint remaining= m_rows_to_insert - m_rows_inserted;
- uint min_prefetch=
- (remaining < thd->variables.ndb_autoincrement_prefetch_sz) ?
- thd->variables.ndb_autoincrement_prefetch_sz
- : remaining;
- cache_size= ((remaining < m_autoincrement_prefetch) ?
- min_prefetch
- : remaining);
uint retries= NDB_AUTO_INCREMENT_RETRIES;
int retry_sleep= 30; /* 30 milliseconds, transaction */
for (;;)
@@ -6570,7 +6561,9 @@ void ha_ndbcluster::get_auto_increment(u
Ndb_tuple_id_range_guard g(m_share);
if (m_skip_auto_increment &&
ndb->readAutoIncrementValue(m_table, g.range, auto_value) ||
- ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size, increment, offset))
+ ndb->getAutoIncrementValue(m_table, g.range, auto_value,
+ Uint32(m_autoincrement_prefetch),
+ increment, offset))
{
if (--retries && !thd->killed &&
ndb->getNdbError().status == NdbError::TemporaryError)
=== modified file 'storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp'
--- a/storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp 2009-09-01 10:50:11 +0000
@@ -42,10 +42,17 @@ class CloseComReqConf {
friend bool printCLOSECOMREQCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo);
public:
- STATIC_CONST( SignalLength = 3 + NodeBitmask::Size );
+ STATIC_CONST( SignalLength = 4 + NodeBitmask::Size );
private:
+ enum RequestType {
+ RT_API_FAILURE = 0,
+ RT_NODE_FAILURE = 1,
+ RT_NO_REPLY = 2
+ };
+
Uint32 xxxBlockRef;
+ Uint32 requestType;
Uint32 failNo;
Uint32 noOfNodes;
=== modified file 'storage/ndb/src/kernel/blocks/ERROR_codes.txt'
--- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2009-05-26 04:14:03 +0000
+++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2009-09-01 10:50:11 +0000
@@ -6,7 +6,7 @@ Next DBTUP 4029
Next DBLQH 5054
Next DBDICT 6008
Next DBDIH 7215
-Next DBTC 8074
+Next DBTC 8080
Next CMVMI 9000
Next BACKUP 10041
Next DBUTIL 11002
@@ -348,6 +348,8 @@ ABORT OF TCKEYREQ
8052 : Simulate failure of TransactionBufferMemory allocation for OI lookup
8051 : Simulate failure of allocation for saveINDXKEYINFO
+8078 : Activate error insert 8079 on receiving API_FAILREQ
+8079 : Crash if TCKEYREQ received from failed api
CMVMI
=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2009-09-01 10:50:11 +0000
@@ -497,6 +497,7 @@ void Cmvmi::execCLOSE_COMREQ(Signal* sig
CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
const BlockReference userRef = closeCom->xxxBlockRef;
+ Uint32 requestType = closeCom->requestType;
Uint32 failNo = closeCom->failNo;
// Uint32 noOfNodes = closeCom->noOfNodes;
@@ -519,11 +520,20 @@ void Cmvmi::execCLOSE_COMREQ(Signal* sig
}
}
- if (failNo != 0)
+ if (requestType != CloseComReqConf::RT_NO_REPLY)
{
+ ndbassert((requestType == CloseComReqConf::RT_API_FAILURE) ||
+ ((requestType == CloseComReqConf::RT_NODE_FAILURE) &&
+ (failNo != 0)));
jam();
- signal->theData[0] = userRef;
- signal->theData[1] = failNo;
+ CloseComReqConf* closeComConf = (CloseComReqConf *)signal->getDataPtrSend();
+ closeComConf->xxxBlockRef = userRef;
+ closeComConf->requestType = requestType;
+ closeComConf->failNo = failNo;
+
+ /* Note assumption that noOfNodes and theNodes
+ * bitmap is not trampled above
+ */
sendSignal(QMGR_REF, GSN_CLOSE_COMCONF, signal, 19, JBA);
}
}
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp 2009-09-01 12:27:40 +0000
@@ -1980,6 +1980,11 @@ private:
/**************************************************************************/
Uint32 c_gcp_ref;
+
+#ifdef ERROR_INSERT
+ // Used with ERROR_INSERT 8078 + 8079 to check API_FAILREQ handling
+ Uint32 c_lastFailedApi;
+#endif
};
#endif
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2009-08-04 10:52:04 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2009-09-01 12:27:40 +0000
@@ -936,6 +936,13 @@ void Dbtc::execAPI_FAILREQ(Signal* signa
CLEAR_ERROR_INSERT_VALUE;
return;
}
+#ifdef ERROR_INSERT
+ if (ERROR_INSERTED(8078))
+ {
+ c_lastFailedApi = signal->theData[0];
+ SET_ERROR_INSERT_VALUE(8079);
+ }
+#endif
capiFailRef = signal->theData[1];
arrGuard(signal->theData[0], MAX_NODES);
@@ -1278,6 +1285,12 @@ void Dbtc::execTCSEIZEREQ(Signal* signal
}
}
+ if (ERROR_INSERTED(8078) || ERROR_INSERTED(8079))
+ {
+ /* Clear testing of API_FAILREQ behaviour */
+ CLEAR_ERROR_INSERT_VALUE;
+ };
+
seizeApiConnect(signal);
if (terrorCode == ZOK) {
jam();
@@ -2573,6 +2586,18 @@ void Dbtc::execTCKEYREQ(Signal* signal)
return;
}//if
+#ifdef ERROR_INSERT
+ if (ERROR_INSERTED(8079))
+ {
+ /* Test that no signals received after API_FAILREQ */
+ if (sendersNodeId == c_lastFailedApi)
+ {
+ /* Signal from API node received *after* API_FAILREQ */
+ ndbrequire(false);
+ }
+ }
+#endif
+
Treqinfo = tcKeyReq->requestInfo;
//--------------------------------------------------------------------------
// Optimised version of ptrAss(tabptr, tableRecord)
@@ -4118,7 +4143,8 @@ void Dbtc::sendtckeyconf(Signal* signal,
if (unlikely(!ndb_check_micro_gcp(getNodeInfo(localHostptr.i).m_version)))
{
jam();
- ndbassert(Tpack6 == 0 || getNodeInfo(localHostptr.i).m_connected == false);
+ ndbassert(Tpack6 == 0 ||
+ getNodeInfo(localHostptr.i).m_version == 0); // Disconnected
}
}//Dbtc::sendtckeyconf()
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2009-09-04 10:15:28 +0000
@@ -571,9 +571,9 @@ typedef Ptr<Fragoperrec> FragoperrecPtr;
Local_key m_key;
Uint32 m_frag_ptr_i;
Uint32 m_extent_info_ptr;
- Uint16 m_estimated_free_space; // in bytes/records
- Uint16 m_list_index; // in Disk_alloc_info.m_page_requests
- Uint16 m_ref_count; // Waiters for page
+ Uint16 m_original_estimated_free_space; // in bytes/records
+ Uint16 m_list_index; // in Disk_alloc_info.m_page_requests
+ Uint16 m_ref_count; // Waiters for page
Uint16 m_uncommitted_used_space;
Uint32 nextList;
Uint32 prevList;
@@ -3140,9 +3140,19 @@ private:
void drop_table_logsync_callback(Signal*, Uint32, Uint32);
void disk_page_set_dirty(Ptr<Page>);
- void restart_setup_page(Disk_alloc_info&, Ptr<Page>);
- void update_extent_pos(Disk_alloc_info&, Ptr<Extent_info>);
-
+ void restart_setup_page(Disk_alloc_info&, Ptr<Page>, Int32 estimate);
+ void update_extent_pos(Disk_alloc_info&, Ptr<Extent_info>, Int32 delta);
+
+ void disk_page_move_page_request(Disk_alloc_info& alloc,
+ Ptr<Extent_info>,
+ Ptr<Page_request> req,
+ Uint32 old_idx, Uint32 new_idx);
+
+ void disk_page_move_dirty_page(Disk_alloc_info& alloc,
+ Ptr<Extent_info> extentPtr,
+ Ptr<Page> pagePtr,
+ Uint32 old_idx, Uint32 new_idx);
+
/**
* Disk restart code
*/
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp 2009-05-28 12:43:04 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp 2009-09-04 15:19:41 +0000
@@ -42,7 +42,7 @@ operator<<(NdbOut& out, const Ptr<Dbtup:
{
out << "[ Page_request: ptr.i: " << ptr.i
<< " " << ptr.p->m_key
- << " m_estimated_free_space: " << ptr.p->m_estimated_free_space
+ << " m_original_estimated_free_space: " << ptr.p->m_original_estimated_free_space
<< " m_list_index: " << ptr.p->m_list_index
<< " m_frag_ptr_i: " << ptr.p->m_frag_ptr_i
<< " m_extent_info_ptr: " << ptr.p->m_extent_info_ptr
@@ -250,16 +250,41 @@ Dbtup::Disk_alloc_info::calc_extent_pos(
void
Dbtup::update_extent_pos(Disk_alloc_info& alloc,
- Ptr<Extent_info> extentPtr)
+ Ptr<Extent_info> extentPtr,
+ Int32 delta)
{
+ if (delta < 0)
+ {
+ jam();
+ Uint32 sub = Uint32(- delta);
+ ddassert(extentPtr.p->m_free_space >= sub);
+ extentPtr.p->m_free_space -= sub;
+ }
+ else
+ {
+ jam();
+ extentPtr.p->m_free_space += delta;
+ ndbassert(Uint32(delta) <= alloc.calc_page_free_space(0));
+ }
+
#ifdef VM_TRACE
- Uint32 min_free = 0;
+ Uint32 cnt = 0;
+ Uint32 sum = 0;
for(Uint32 i = 0; i<MAX_FREE_LIST; i++)
{
- Uint32 sum = alloc.calc_page_free_space(i);
- min_free += sum * extentPtr.p->m_free_page_count[i];
+ cnt += extentPtr.p->m_free_page_count[i];
+ sum += extentPtr.p->m_free_page_count[i] * alloc.calc_page_free_space(i);
+ }
+ if (extentPtr.p->m_free_page_count[0] == cnt)
+ {
+ ddassert(extentPtr.p->m_free_space == cnt*alloc.m_page_free_bits_map[0]);
}
- ddassert(extentPtr.p->m_free_space >= min_free);
+ else
+ {
+ ddassert(extentPtr.p->m_free_space < cnt*alloc.m_page_free_bits_map[0]);
+ }
+ ddassert(extentPtr.p->m_free_space >= sum);
+ ddassert(extentPtr.p->m_free_space <= cnt*alloc.m_page_free_bits_map[0]);
#endif
Uint32 old = extentPtr.p->m_free_matrix_pos;
@@ -283,7 +308,8 @@ Dbtup::update_extent_pos(Disk_alloc_info
}
void
-Dbtup::restart_setup_page(Disk_alloc_info& alloc, PagePtr pagePtr)
+Dbtup::restart_setup_page(Disk_alloc_info& alloc, PagePtr pagePtr,
+ Int32 estimate)
{
jam();
/**
@@ -299,16 +325,24 @@ Dbtup::restart_setup_page(Disk_alloc_inf
ndbrequire(c_extent_hash.find(extentPtr, key));
pagePtr.p->m_extent_info_ptr = extentPtr.i;
- Uint32 idx = pagePtr.p->list_index & ~0x8000;
- Uint32 estimated = alloc.calc_page_free_space(idx);
Uint32 real_free = pagePtr.p->free_space;
-
- ddassert(real_free >= estimated);
- if (real_free != estimated)
+ const bool prealloc = estimate >= 0;
+ Uint32 estimated;
+ if (prealloc)
+ {
+ jam();
+ /**
+ * If this is during prealloc, use estimate from there
+ */
+ estimated = (Uint32)estimate;
+ }
+ else
{
jam();
- extentPtr.p->m_free_space += (real_free - estimated);
- update_extent_pos(alloc, extentPtr);
+ /**
+ * else use the estimate based on the actual free space
+ */
+ estimated =alloc.calc_page_free_space(alloc.calc_page_free_bits(real_free));
}
#ifdef VM_TRACE
@@ -324,10 +358,30 @@ Dbtup::restart_setup_page(Disk_alloc_inf
(void) tsman.get_page_free_bits(&page, &uncommitted, &committed);
jamEntry();
- idx = alloc.calc_page_free_bits(real_free);
- ddassert(idx == committed);
+ ddassert(alloc.calc_page_free_bits(real_free) == committed);
+ if (prealloc)
+ {
+ /**
+ * tsman.alloc_page sets the uncommitted-bits to MAX_FREE_LIST -1
+ * to avoid page being preallocated several times
+ */
+ ddassert(uncommitted == MAX_FREE_LIST - 1);
+ }
+ else
+ {
+ ddassert(committed == uncommitted);
+ }
}
#endif
+
+ ddassert(real_free >= estimated);
+
+ if (real_free != estimated)
+ {
+ jam();
+ Uint32 delta = (real_free-estimated);
+ update_extent_pos(alloc, extentPtr, delta);
+ }
}
/**
@@ -524,6 +578,7 @@ Dbtup::disk_page_prealloc(Signal* signal
Logfile_client lgman(this, c_lgman, logfile_group_id);
int res= lgman.get_log_buffer(signal, sz, &cb);
+ jamEntry();
switch(res){
case 0:
break;
@@ -575,9 +630,9 @@ Dbtup::disk_page_prealloc(Signal* signal
Uint32 size= alloc.calc_page_free_space((Uint32)pageBits);
ddassert(size >= sz);
- Uint32 new_size = size - sz; // Subtract alloc rec
- req.p->m_estimated_free_space= new_size; // Store on page request
+ req.p->m_original_estimated_free_space = size;
+ Uint32 new_size = size - sz; // Subtract alloc rec
Uint32 newPageBits= alloc.calc_page_free_bits(new_size);
if (newPageBits != (Uint32)pageBits)
{
@@ -586,9 +641,8 @@ Dbtup::disk_page_prealloc(Signal* signal
ext.p->m_free_page_count[pageBits]--;
ext.p->m_free_page_count[newPageBits]++;
}
- ddassert(ext.p->m_free_space >= sz);
- ext.p->m_free_space -= sz;
-
+ update_extent_pos(alloc, ext, -Int32(sz));
+
// And put page request in correct free list
idx= alloc.calc_page_free_bits(new_size);
{
@@ -651,26 +705,15 @@ Dbtup::disk_page_prealloc_dirty_page(Dis
c_extent_pool.getPtr(extentPtr, ext);
Uint32 new_idx= alloc.calc_page_free_bits(free - used);
- ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
if (old_idx != new_idx)
{
jam();
- LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
- LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
- old_list.remove(pagePtr);
- new_list.add(pagePtr);
-
- ddassert(extentPtr.p->m_free_page_count[old_idx]);
- extentPtr.p->m_free_page_count[old_idx]--;
- extentPtr.p->m_free_page_count[new_idx]++;
- pagePtr.p->list_index= new_idx;
+ disk_page_move_dirty_page(alloc, extentPtr, pagePtr, old_idx, new_idx);
}
pagePtr.p->uncommitted_used_space = used;
- ddassert(extentPtr.p->m_free_space >= sz);
- extentPtr.p->m_free_space -= sz;
- update_extent_pos(alloc, extentPtr);
+ update_extent_pos(alloc, extentPtr, -Int32(sz));
}
@@ -682,39 +725,26 @@ Dbtup::disk_page_prealloc_transit_page(D
jam();
ddassert(req.p->m_list_index == old_idx);
- Uint32 free= req.p->m_estimated_free_space;
+ Uint32 free= req.p->m_original_estimated_free_space;
Uint32 used= req.p->m_uncommitted_used_space + sz;
Uint32 ext= req.p->m_extent_info_ptr;
Ptr<Extent_info> extentPtr;
c_extent_pool.getPtr(extentPtr, ext);
- ddassert(free >= sz);
- Uint32 new_idx= alloc.calc_page_free_bits(free - sz);
+ ddassert(free >= used);
+ Uint32 new_idx= alloc.calc_page_free_bits(free - used);
if (old_idx != new_idx)
{
jam();
- Page_request_list::Head *lists = alloc.m_page_requests;
- Local_page_request_list old_list(c_page_request_pool, lists[old_idx]);
- Local_page_request_list new_list(c_page_request_pool, lists[new_idx]);
- old_list.remove(req);
- new_list.add(req);
-
- ddassert(extentPtr.p->m_free_page_count[old_idx]);
- extentPtr.p->m_free_page_count[old_idx]--;
- extentPtr.p->m_free_page_count[new_idx]++;
- req.p->m_list_index= new_idx;
+ disk_page_move_page_request(alloc, extentPtr, req, old_idx, new_idx);
}
req.p->m_uncommitted_used_space = used;
- req.p->m_estimated_free_space = free - sz;
- ddassert(extentPtr.p->m_free_space >= sz);
- extentPtr.p->m_free_space -= sz;
- update_extent_pos(alloc, extentPtr);
+ update_extent_pos(alloc, extentPtr, -Int32(sz));
}
-
void
Dbtup::disk_page_prealloc_callback(Signal* signal,
Uint32 page_request, Uint32 page_id)
@@ -736,12 +766,87 @@ Dbtup::disk_page_prealloc_callback(Signa
pagePtr.i = gpage.i;
pagePtr.p = reinterpret_cast<Page*>(gpage.p);
+ Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq))
{
- restart_setup_page(fragPtr.p->m_disk_alloc_info, pagePtr);
+ jam();
+ restart_setup_page(alloc, pagePtr, req.p->m_original_estimated_free_space);
+ }
+
+ Ptr<Extent_info> extentPtr;
+ c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr);
+
+ pagePtr.p->uncommitted_used_space += req.p->m_uncommitted_used_space;
+ ddassert(pagePtr.p->free_space >= pagePtr.p->uncommitted_used_space);
+
+ Uint32 free = pagePtr.p->free_space - pagePtr.p->uncommitted_used_space;
+ Uint32 idx = req.p->m_list_index;
+ Uint32 real_idx = alloc.calc_page_free_bits(free);
+
+ if (idx != real_idx)
+ {
+ jam();
+ ddassert(extentPtr.p->m_free_page_count[idx]);
+ extentPtr.p->m_free_page_count[idx]--;
+ extentPtr.p->m_free_page_count[real_idx]++;
+ update_extent_pos(alloc, extentPtr, 0);
}
- disk_page_prealloc_callback_common(signal, req, fragPtr, pagePtr);
+ {
+ /**
+ * add to dirty list
+ */
+ pagePtr.p->list_index = real_idx;
+ ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
+ LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[real_idx]);
+ list.add(pagePtr);
+ }
+
+ {
+ /**
+ * release page request
+ */
+ Local_page_request_list list(c_page_request_pool,
+ alloc.m_page_requests[idx]);
+ list.release(req);
+ }
+}
+
+void
+Dbtup::disk_page_move_dirty_page(Disk_alloc_info& alloc,
+ Ptr<Extent_info> extentPtr,
+ Ptr<Page> pagePtr,
+ Uint32 old_idx,
+ Uint32 new_idx)
+{
+ ddassert(extentPtr.p->m_free_page_count[old_idx]);
+ extentPtr.p->m_free_page_count[old_idx]--;
+ extentPtr.p->m_free_page_count[new_idx]++;
+
+ ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
+ LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
+ LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
+ old_list.remove(pagePtr);
+ new_list.add(pagePtr);
+ pagePtr.p->list_index = new_idx;
+}
+
+void
+Dbtup::disk_page_move_page_request(Disk_alloc_info& alloc,
+ Ptr<Extent_info> extentPtr,
+ Ptr<Page_request> req,
+ Uint32 old_idx, Uint32 new_idx)
+{
+ Page_request_list::Head *lists = alloc.m_page_requests;
+ Local_page_request_list old_list(c_page_request_pool, lists[old_idx]);
+ Local_page_request_list new_list(c_page_request_pool, lists[new_idx]);
+ old_list.remove(req);
+ new_list.add(req);
+
+ ddassert(extentPtr.p->m_free_page_count[old_idx]);
+ extentPtr.p->m_free_page_count[old_idx]--;
+ extentPtr.p->m_free_page_count[new_idx]++;
+ req.p->m_list_index= new_idx;
}
void
@@ -778,17 +883,6 @@ Dbtup::disk_page_prealloc_initial_callba
Ptr<Extent_info> extentPtr;
c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr);
- pagePtr.p->m_page_no= req.p->m_key.m_page_no;
- pagePtr.p->m_file_no= req.p->m_key.m_file_no;
- pagePtr.p->m_table_id= fragPtr.p->fragTableId;
- pagePtr.p->m_fragment_id = fragPtr.p->fragmentId;
- pagePtr.p->m_extent_no = extentPtr.p->m_key.m_page_idx; // logical extent no
- pagePtr.p->m_extent_info_ptr= req.p->m_extent_info_ptr;
- pagePtr.p->m_restart_seq = globalData.m_restart_seq;
- pagePtr.p->list_index = 0x8000;
- pagePtr.p->uncommitted_used_space = 0;
- pagePtr.p->nextList = pagePtr.p->prevList = RNIL;
-
if (tabPtr.p->m_attributes[DD].m_no_of_varsize == 0)
{
convertThPage((Fix_page*)pagePtr.p, tabPtr.p, DD);
@@ -797,70 +891,42 @@ Dbtup::disk_page_prealloc_initial_callba
{
abort();
}
- disk_page_prealloc_callback_common(signal, req, fragPtr, pagePtr);
-}
-void
-Dbtup::disk_page_prealloc_callback_common(Signal* signal,
- Ptr<Page_request> req,
- Ptr<Fragrecord> fragPtr,
- PagePtr pagePtr)
-{
- /**
- * 1) remove page request from Disk_alloc_info.m_page_requests
- * 2) Add page to Disk_alloc_info.m_dirty_pages
- * 3) register callback in pgman (unmap callback)
- * 4) inform pgman about current users
- */
- Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
- ddassert((pagePtr.p->list_index & 0x8000) == 0x8000);
- ddassert(pagePtr.p->m_extent_info_ptr == req.p->m_extent_info_ptr);
- ddassert(pagePtr.p->m_page_no == req.p->m_key.m_page_no);
- ddassert(pagePtr.p->m_file_no == req.p->m_key.m_file_no);
-
- Uint32 old_idx = req.p->m_list_index;
- Uint32 free= req.p->m_estimated_free_space;
- Uint32 ext = req.p->m_extent_info_ptr;
- Uint32 used= req.p->m_uncommitted_used_space;
- Uint32 real_free = pagePtr.p->free_space;
- Uint32 real_used = used + pagePtr.p->uncommitted_used_space;
-
- ddassert(real_free >= free);
- ddassert(real_free >= real_used);
- ddassert(alloc.calc_page_free_bits(free) == old_idx);
- Uint32 new_idx= alloc.calc_page_free_bits(real_free - real_used);
+ pagePtr.p->m_page_no= req.p->m_key.m_page_no;
+ pagePtr.p->m_file_no= req.p->m_key.m_file_no;
+ pagePtr.p->m_table_id= fragPtr.p->fragTableId;
+ pagePtr.p->m_fragment_id = fragPtr.p->fragmentId;
+ pagePtr.p->m_extent_no = extentPtr.p->m_key.m_page_idx; // logical extent no
+ pagePtr.p->m_extent_info_ptr= req.p->m_extent_info_ptr;
+ pagePtr.p->m_restart_seq = globalData.m_restart_seq;
+ pagePtr.p->nextList = pagePtr.p->prevList = RNIL;
+ pagePtr.p->list_index = req.p->m_list_index;
+ pagePtr.p->uncommitted_used_space = req.p->m_uncommitted_used_space;
- /**
- * Add to dirty pages
- */
- ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
- LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[new_idx]);
- list.add(pagePtr);
- pagePtr.p->uncommitted_used_space = real_used;
- pagePtr.p->list_index = new_idx;
+ Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
+ Uint32 idx = req.p->m_list_index;
- if (old_idx != new_idx || free != real_free)
{
- jam();
- Ptr<Extent_info> extentPtr;
- c_extent_pool.getPtr(extentPtr, ext);
+ Uint32 free = pagePtr.p->free_space - pagePtr.p->uncommitted_used_space;
+ ddassert(idx == alloc.calc_page_free_bits(free));
+ ddassert(pagePtr.p->free_space == req.p->m_original_estimated_free_space);
+ }
- extentPtr.p->m_free_space += (real_free - free);
-
- if (old_idx != new_idx)
- {
- jam();
- ddassert(extentPtr.p->m_free_page_count[old_idx]);
- extentPtr.p->m_free_page_count[old_idx]--;
- extentPtr.p->m_free_page_count[new_idx]++;
- }
-
- update_extent_pos(alloc, extentPtr);
+ {
+ /**
+ * add to dirty list
+ */
+ ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
+ LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[idx]);
+ list.add(pagePtr);
}
-
+
{
+ /**
+ * release page request
+ */
Local_page_request_list list(c_page_request_pool,
- alloc.m_page_requests[old_idx]);
+ alloc.m_page_requests[idx]);
list.release(req);
}
}
@@ -870,7 +936,8 @@ Dbtup::disk_page_set_dirty(PagePtr pageP
{
jam();
Uint32 idx = pagePtr.p->list_index;
- if ((idx & 0x8000) == 0)
+ if ((pagePtr.p->m_restart_seq == globalData.m_restart_seq) &&
+ ((idx & 0x8000) == 0))
{
jam();
/**
@@ -901,12 +968,15 @@ Dbtup::disk_page_set_dirty(PagePtr pageP
Uint32 used = pagePtr.p->uncommitted_used_space;
if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq))
{
- restart_setup_page(alloc, pagePtr);
+ jam();
+ restart_setup_page(alloc, pagePtr, -1);
+ ndbassert(free == pagePtr.p->free_space);
idx = alloc.calc_page_free_bits(free);
used = 0;
}
else
{
+ jam();
idx &= ~0x8000;
ddassert(idx == alloc.calc_page_free_bits(free - used));
}
@@ -1131,20 +1201,10 @@ Dbtup::disk_page_free(Signal *signal,
if (old_idx != new_idx)
{
jam();
- ddassert(extentPtr.p->m_free_page_count[old_idx]);
- extentPtr.p->m_free_page_count[old_idx]--;
- extentPtr.p->m_free_page_count[new_idx]++;
-
- ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
- LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
- LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
- old_list.remove(pagePtr);
- new_list.add(pagePtr);
- pagePtr.p->list_index = new_idx;
+ disk_page_move_dirty_page(alloc, extentPtr, pagePtr, old_idx, new_idx);
}
- extentPtr.p->m_free_space += sz;
- update_extent_pos(alloc, extentPtr);
+ update_extent_pos(alloc, extentPtr, sz);
#if NOT_YET_FREE_EXTENT
if (check_free(extentPtr.p) == 0)
{
@@ -1158,6 +1218,7 @@ Dbtup::disk_page_abort_prealloc(Signal *
Local_key* key, Uint32 sz)
{
jam();
+
Page_cache_client::Request req;
req.m_callback.m_callbackData= sz;
req.m_callback.m_callbackFunction =
@@ -1221,47 +1282,29 @@ Dbtup::disk_page_abort_prealloc_callback
disk_page_set_dirty(pagePtr);
Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
- Uint32 page_idx = pagePtr.p->list_index;
+
+ Ptr<Extent_info> extentPtr;
+ c_extent_pool.getPtr(extentPtr, pagePtr.p->m_extent_info_ptr);
+
+ Uint32 idx = pagePtr.p->list_index & 0x7FFF;
Uint32 used = pagePtr.p->uncommitted_used_space;
Uint32 free = pagePtr.p->free_space;
- Uint32 ext = pagePtr.p->m_extent_info_ptr;
- Uint32 old_idx = page_idx & 0x7FFF;
ddassert(free >= used);
ddassert(used >= sz);
- ddassert(alloc.calc_page_free_bits(free - used) == old_idx);
+ ddassert(alloc.calc_page_free_bits(free - used) == idx);
+
+ pagePtr.p->uncommitted_used_space = used - sz;
+
Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz);
- Ptr<Extent_info> extentPtr;
- c_extent_pool.getPtr(extentPtr, ext);
- if (old_idx != new_idx)
+ if (idx != new_idx)
{
jam();
- ddassert(extentPtr.p->m_free_page_count[old_idx]);
- extentPtr.p->m_free_page_count[old_idx]--;
- extentPtr.p->m_free_page_count[new_idx]++;
-
- if (old_idx == page_idx)
- {
- jam();
- ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
- LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
- LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
- old_list.remove(pagePtr);
- new_list.add(pagePtr);
- pagePtr.p->list_index = new_idx;
- }
- else
- {
- jam();
- pagePtr.p->list_index = new_idx | 0x8000;
- }
+ disk_page_move_dirty_page(alloc, extentPtr, pagePtr, idx, new_idx);
}
- pagePtr.p->uncommitted_used_space = used - sz;
-
- extentPtr.p->m_free_space += sz;
- update_extent_pos(alloc, extentPtr);
+ update_extent_pos(alloc, extentPtr, sz);
#if NOT_YET_FREE_EXTENT
if (check_free(extentPtr.p) == 0)
{
@@ -1322,6 +1365,7 @@ Dbtup::disk_page_undo_alloc(Page* page,
Logfile_client::Change c[1] = {{ &alloc, sizeof(alloc) >> 2 } };
Uint64 lsn= lgman.add_entry(c, 1);
+ jamEntry();
m_pgman.update_lsn(* key, lsn);
jamEntry();
@@ -1353,6 +1397,7 @@ Dbtup::disk_page_undo_update(Page* page,
ndbassert(4*(3 + sz + 1) == (sizeof(update) + 4*sz - 4));
Uint64 lsn= lgman.add_entry(c, 3);
+ jamEntry();
m_pgman.update_lsn(* key, lsn);
jamEntry();
@@ -1384,6 +1429,7 @@ Dbtup::disk_page_undo_free(Page* page, c
ndbassert(4*(3 + sz + 1) == (sizeof(free) + 4*sz - 4));
Uint64 lsn= lgman.add_entry(c, 3);
+ jamEntry();
m_pgman.update_lsn(* key, lsn);
jamEntry();
@@ -1882,7 +1928,7 @@ Dbtup::disk_restart_alloc_extent(Uint32
void
Dbtup::disk_restart_page_bits(Uint32 tableId, Uint32 fragId,
- const Local_key*, Uint32 bits)
+ const Local_key* key, Uint32 bits)
{
jam();
TablerecPtr tabPtr;
@@ -1897,7 +1943,7 @@ Dbtup::disk_restart_page_bits(Uint32 tab
Uint32 size= alloc.calc_page_free_space(bits);
- ext.p->m_free_space += size;
ext.p->m_free_page_count[bits]++;
+ update_extent_pos(alloc, ext, size); // actually only to update free_space
ndbassert(ext.p->m_free_matrix_pos == RNIL);
}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2009-09-04 10:15:28 +0000
@@ -350,6 +350,7 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
Tablespace_client tsman(0, c_tsman, 0, 0,
regFragPtr.p->m_tablespace_id);
ndbrequire(tsman.get_tablespace_info(&rep) == 0);
+ jamEntry();
regFragPtr.p->m_logfile_group_id= rep.tablespace.logfile_group_id;
}
else
@@ -549,6 +550,7 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
Tablespace_client tsman(0, c_tsman, 0, 0,
regFragPtr.p->m_tablespace_id);
ndbrequire(tsman.get_tablespace_info(&rep) == 0);
+ jamEntry();
regFragPtr.p->m_logfile_group_id= rep.tablespace.logfile_group_id;
}
else
@@ -578,11 +580,14 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
if((terrorCode =
c_lgman->alloc_log_space(regFragPtr.p->m_logfile_group_id, sz)))
{
+ jamEntry();
addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId);
return;
}
+ jamEntry();
int res= lgman.get_log_buffer(signal, sz, &cb);
+ jamEntry();
switch(res){
case 0:
jam();
@@ -1201,6 +1206,7 @@ Dbtup::undo_createtable_callback(Signal*
Logfile_client::Change c[1] = {{ &create, sizeof(create) >> 2 } };
Uint64 lsn= lgman.add_entry(c, 1);
+ jamEntry();
Logfile_client::Request req;
req.m_callback.m_callbackData= fragOperPtr.i;
@@ -1208,6 +1214,7 @@ Dbtup::undo_createtable_callback(Signal*
safe_cast(&Dbtup::undo_createtable_logsync_callback);
int ret = lgman.sync_lsn(signal, lsn, &req, 0);
+ jamEntry();
switch(ret){
case 0:
return;
@@ -1586,6 +1593,7 @@ void Dbtup::releaseFragment(Signal* sign
safe_cast(&Dbtup::drop_table_log_buffer_callback);
Uint32 sz= sizeof(Disk_undo::Drop) >> 2;
int r0 = c_lgman->alloc_log_space(logfile_group_id, sz);
+ jamEntry();
if (r0)
{
jam();
@@ -1596,6 +1604,7 @@ void Dbtup::releaseFragment(Signal* sign
Logfile_client lgman(this, c_lgman, logfile_group_id);
int res= lgman.get_log_buffer(signal, sz, &cb);
+ jamEntry();
switch(res){
case 0:
jam();
@@ -1604,6 +1613,7 @@ void Dbtup::releaseFragment(Signal* sign
warningEvent("Failed to get log buffer for drop table: %u",
tabPtr.i);
c_lgman->free_log_space(logfile_group_id, sz);
+ jamEntry();
goto done;
break;
default:
@@ -1630,7 +1640,6 @@ Dbtup::drop_fragment_unmap_pages(Signal
if (!alloc_info.m_unmap_pages.isEmpty())
{
jam();
- ndbout_c("waiting for unmape pages");
signal->theData[0] = ZUNMAP_PAGES;
signal->theData[1] = tabPtr.i;
signal->theData[2] = fragPtr.i;
@@ -1675,6 +1684,7 @@ Dbtup::drop_fragment_unmap_pages(Signal
int flags= Page_cache_client::COMMIT_REQ;
int res= m_pgman.get_page(signal, req, flags);
+ jamEntry();
switch(res)
{
case 0:
@@ -1703,6 +1713,7 @@ Dbtup::drop_fragment_unmap_page_callback
Uint32 fragId = ((Page*)page.p)->m_fragment_id;
Uint32 tableId = ((Page*)page.p)->m_table_id;
m_pgman.drop_page(key, page_id);
+ jamEntry();
TablerecPtr tabPtr;
tabPtr.i= tableId;
@@ -1739,10 +1750,12 @@ Dbtup::drop_fragment_free_extent(Signal
#if NOT_YET_UNDO_FREE_EXTENT
Uint32 sz= sizeof(Disk_undo::FreeExtent) >> 2;
(void) c_lgman->alloc_log_space(fragPtr.p->m_logfile_group_id, sz);
+ jamEntry();
Logfile_client lgman(this, c_lgman, fragPtr.p->m_logfile_group_id);
int res= lgman.get_log_buffer(signal, sz, &cb);
+ jamEntry();
switch(res){
case 0:
jam();
@@ -1794,6 +1807,7 @@ Dbtup::drop_table_log_buffer_callback(Si
Logfile_client::Change c[1] = {{ &drop, sizeof(drop) >> 2 } };
Uint64 lsn = lgman.add_entry(c, 1);
+ jamEntry();
Logfile_client::Request req;
req.m_callback.m_callbackData= tablePtrI;
@@ -1801,6 +1815,7 @@ Dbtup::drop_table_log_buffer_callback(Si
safe_cast(&Dbtup::drop_table_logsync_callback);
int ret = lgman.sync_lsn(signal, lsn, &req, 0);
+ jamEntry();
switch(ret){
case 0:
return;
@@ -1871,6 +1886,7 @@ Dbtup::drop_fragment_free_extent_log_buf
Logfile_client::Change c[1] = {{ &free, sizeof(free) >> 2 } };
Uint64 lsn = lgman.add_entry(c, 1);
+ jamEntry();
#else
Uint64 lsn = 0;
#endif
@@ -1880,6 +1896,7 @@ Dbtup::drop_fragment_free_extent_log_buf
fragPtr.p->m_tablespace_id);
tsman.free_extent(&ext_ptr.p->m_key, lsn);
+ jamEntry();
c_extent_hash.remove(ext_ptr);
list.release(ext_ptr);
=== modified file 'storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp'
--- a/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp 2009-09-01 10:50:11 +0000
@@ -92,10 +92,12 @@ public:
enum FailState {
NORMAL = 0,
- WAITING_FOR_FAILCONF1 = 1,
- WAITING_FOR_FAILCONF2 = 2,
- WAITING_FOR_FAILCONF3 = 3,
- WAITING_FOR_NDB_FAILCONF = 3
+ WAITING_FOR_CLOSECOMCONF_ACTIVE = 1, /* Node had phase ZAPI_ACTIVE */
+ WAITING_FOR_CLOSECOMCONF_NOTACTIVE = 2, /* Node had phase != ZAPI_ACTIVE */
+ WAITING_FOR_FAILCONF1 = 3,
+ WAITING_FOR_FAILCONF2 = 4,
+ WAITING_FOR_FAILCONF3 = 5,
+ WAITING_FOR_NDB_FAILCONF = 6
};
enum Phase {
@@ -391,7 +393,8 @@ private:
Uint32 failNo,
Uint32 noOfNodes,
const NodeId theNodes[]);
-
+
+ void handleApiCloseComConf(Signal* signal);
/* Wait this time until we try to join the */
=== modified file 'storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp'
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2009-09-01 10:50:11 +0000
@@ -2618,14 +2618,14 @@ void Qmgr::sendApiFailReq(Signal* signal
ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec);
- ndbrequire(failedNodePtr.p->failState == NORMAL);
-
failedNodePtr.p->failState = WAITING_FOR_FAILCONF1;
- NodeReceiverGroup rg(QMGR, c_clusterNodes);
- sendSignal(rg, GSN_API_FAILREQ, signal, 2, JBA);
- sendSignal(DBTC_REF, GSN_API_FAILREQ, signal, 2, JBA);
- sendSignal(DBDICT_REF, GSN_API_FAILREQ, signal, 2, JBA);
- sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBA);
+
+ /* JBB used to ensure delivery *after* any pending
+ * signals
+ */
+ sendSignal(DBTC_REF, GSN_API_FAILREQ, signal, 2, JBB);
+ sendSignal(DBDICT_REF, GSN_API_FAILREQ, signal, 2, JBB);
+ sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBB);
}//Qmgr::sendApiFailReq()
void Qmgr::execAPI_FAILREQ(Signal* signal)
@@ -2888,6 +2888,7 @@ void Qmgr::node_failed(Signal* signal, U
(CloseComReqConf *)&signal->theData[0];
closeCom->xxxBlockRef = reference();
+ closeCom->requestType = CloseComReqConf::RT_NO_REPLY;
closeCom->failNo = 0;
closeCom->noOfNodes = 1;
NodeBitmask::clear(closeCom->theNodes);
@@ -2931,25 +2932,24 @@ Qmgr::api_failed(Signal* signal, Uint32
return;
}
- if (failedNodePtr.p->phase == ZAPI_ACTIVE)
- {
- jam();
- sendApiFailReq(signal, nodeId);
- arbitRec.code = ArbitCode::ApiFail;
- handleArbitApiFail(signal, nodeId);
- }
- else
- {
- /**
- * Always inform SUMA
- */
- jam();
- signal->theData[0] = nodeId;
- signal->theData[1] = QMGR_REF;
- sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBA);
- failedNodePtr.p->failState = WAITING_FOR_FAILCONF3;
- }
+ ndbrequire(failedNodePtr.p->failState == NORMAL);
+ /* Send API_FAILREQ to peer QMGR blocks to allow them to disconnect
+ * quickly
+ * Local application blocks get API_FAILREQ once all pending signals
+ * from the failed API have been processed.
+ */
+ signal->theData[0] = failedNodePtr.i;
+ signal->theData[1] = QMGR_REF;
+ NodeReceiverGroup rg(QMGR, c_clusterNodes);
+ sendSignal(rg, GSN_API_FAILREQ, signal, 2, JBA);
+
+ /* Now ask CMVMI to disconnect the node */
+ FailState initialState = (failedNodePtr.p->phase == ZAPI_ACTIVE) ?
+ WAITING_FOR_CLOSECOMCONF_ACTIVE :
+ WAITING_FOR_CLOSECOMCONF_NOTACTIVE;
+
+ failedNodePtr.p->failState = initialState;
failedNodePtr.p->phase = ZFAIL_CLOSING;
setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0;
setNodeInfo(failedNodePtr.i).m_version = 0;
@@ -2957,22 +2957,14 @@ Qmgr::api_failed(Signal* signal, Uint32
CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
closeCom->xxxBlockRef = reference();
+ closeCom->requestType = CloseComReqConf::RT_API_FAILURE;
closeCom->failNo = 0;
closeCom->noOfNodes = 1;
NodeBitmask::clear(closeCom->theNodes);
NodeBitmask::set(closeCom->theNodes, failedNodePtr.i);
sendSignal(CMVMI_REF, GSN_CLOSE_COMREQ, signal,
CloseComReqConf::SignalLength, JBA);
-
- if (getNodeInfo(failedNodePtr.i).getType() == NodeInfo::MGM)
- {
- /**
- * Allow MGM do reconnect "directly"
- */
- jam();
- setNodeInfo(failedNodePtr.i).m_heartbeat_cnt = 3;
- }
-}
+} // api_failed
/**--------------------------------------------------------------------------
* AN API NODE IS REGISTERING. IF FOR THE FIRST TIME WE WILL ENABLE
@@ -3502,6 +3494,80 @@ void Qmgr::execPREP_FAILREQ(Signal* sign
return;
}//Qmgr::execPREP_FAILREQ()
+
+void Qmgr::handleApiCloseComConf(Signal* signal)
+{
+ jam();
+ CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
+
+ /* Api failure special case */
+ for(Uint32 nodeId = 0; nodeId < MAX_NDB_NODES; nodeId ++)
+ {
+ if(NdbNodeBitmask::get(closeCom->theNodes, nodeId))
+ {
+ jam();
+ /* Check that *only* 1 *API* node is included in
+ * this CLOSE_COM_CONF
+ */
+ ndbrequire(getNodeInfo(nodeId).getType() != NodeInfo::DB);
+ ndbrequire(closeCom->noOfNodes == 1);
+ NdbNodeBitmask::clear(closeCom->theNodes, nodeId);
+ ndbrequire(NdbNodeBitmask::isclear(closeCom->theNodes));
+
+ /* Now that we know communication from the failed Api has
+ * ceased, we can send the required API_FAILREQ signals
+ * and continue API failure handling
+ */
+ NodeRecPtr failedNodePtr;
+ failedNodePtr.i = nodeId;
+ ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec);
+
+ ndbrequire((failedNodePtr.p->failState ==
+ WAITING_FOR_CLOSECOMCONF_ACTIVE) ||
+ (failedNodePtr.p->failState ==
+ WAITING_FOR_CLOSECOMCONF_NOTACTIVE));
+
+ if (failedNodePtr.p->failState == WAITING_FOR_CLOSECOMCONF_ACTIVE)
+ {
+ /**
+ * Inform application blocks TC, DICT, SUMA etc.
+ */
+ jam();
+ sendApiFailReq(signal, nodeId);
+ arbitRec.code = ArbitCode::ApiFail;
+ handleArbitApiFail(signal, nodeId);
+ }
+ else
+ {
+ /**
+ * Always inform SUMA
+ * JBB used to ensure delivery *after* any pending
+ * signals.
+ */
+ jam();
+ signal->theData[0] = nodeId;
+ signal->theData[1] = QMGR_REF;
+ sendSignal(SUMA_REF, GSN_API_FAILREQ, signal, 2, JBB);
+ failedNodePtr.p->failState = WAITING_FOR_FAILCONF3;
+ }
+
+ if (getNodeInfo(failedNodePtr.i).getType() == NodeInfo::MGM)
+ {
+ /**
+ * Allow MGM do reconnect "directly"
+ */
+ jam();
+ setNodeInfo(failedNodePtr.i).m_heartbeat_cnt = 3;
+ }
+
+ /* Handled the single API node failure */
+ return;
+ }
+ }
+ /* Never get here */
+ ndbrequire(false);
+}
+
/**---------------------------------------------------------------------------
* THE CRASHED NODES HAS BEEN EXCLUDED FROM COMMUNICATION.
* WE WILL CHECK WHETHER ANY MORE NODES HAVE FAILED DURING THE PREPARE PROCESS.
@@ -3517,6 +3583,17 @@ void Qmgr::execCLOSE_COMCONF(Signal* sig
CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
+ Uint32 requestType = closeCom->requestType;
+
+ if (requestType == CloseComReqConf::RT_API_FAILURE)
+ {
+ jam();
+ handleApiCloseComConf(signal);
+ return;
+ }
+
+ /* Normal node failure preparation path */
+ ndbassert(requestType == CloseComReqConf::RT_NODE_FAILURE);
BlockReference Tblockref = closeCom->xxxBlockRef;
Uint16 TfailureNr = closeCom->failNo;
@@ -4251,6 +4328,7 @@ void Qmgr::sendCloseComReq(Signal* signa
CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
closeCom->xxxBlockRef = TBRef;
+ closeCom->requestType = CloseComReqConf::RT_NODE_FAILURE;
closeCom->failNo = aFailNo;
closeCom->noOfNodes = cnoPrepFailedNodes;
=== modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp'
--- a/storage/ndb/test/ndbapi/testNdbApi.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/test/ndbapi/testNdbApi.cpp 2009-09-01 10:50:11 +0000
@@ -40,6 +40,14 @@
result = NDBT_FAILED; \
continue; }
+static const char* ApiFailTestRun = "ApiFailTestRun";
+static const char* ApiFailTestComplete = "ApiFailTestComplete";
+static const char* ApiFailTestsRunning = "ApiFailTestsRunning";
+static const char* ApiFailNumberPkSteps = "ApiFailNumberPkSteps";
+static const int MAX_STEPS = 10;
+static Ndb_cluster_connection* otherConnection = NULL;
+static Ndb* stepNdbs[MAX_STEPS];
+
int runTestMaxNdb(NDBT_Context* ctx, NDBT_Step* step){
Uint32 loops = ctx->getNumLoops();
@@ -2843,6 +2851,259 @@ runBug44065(NDBT_Context* ctx, NDBT_Step
return NDBT_OK;
}
+int testApiFailReqImpl(NDBT_Context* ctx, NDBT_Step* step)
+{
+ /* Setup a separate connection for running PK updates
+ * with that will be disconnected without affecting
+ * the test framework
+ */
+ if (otherConnection != NULL)
+ {
+ ndbout << "Connection not null" << endl;
+ return NDBT_FAILED;
+ }
+
+ const Uint32 MaxConnectStringSize= 256;
+ char connectString[ MaxConnectStringSize ];
+ ctx->m_cluster_connection.get_connectstring(connectString,
+ MaxConnectStringSize);
+
+ otherConnection= new Ndb_cluster_connection(connectString);
+
+ if (otherConnection == NULL)
+ {
+ ndbout << "Connection is null" << endl;
+ return NDBT_FAILED;
+ }
+
+ int rc= otherConnection->connect();
+
+ if (rc!= 0)
+ {
+ ndbout << "Connect failed with rc " << rc << endl;
+ return NDBT_FAILED;
+ }
+
+ /* Check that all nodes are alive - if one has failed
+ * then probably we exposed bad API_FAILREQ handling
+ */
+ if (otherConnection->wait_until_ready(10,10) != 0)
+ {
+ ndbout << "Cluster connection was not ready" << endl;
+ return NDBT_FAILED;
+ }
+
+ for (int i=0; i < MAX_STEPS; i++)
+ {
+ /* We must create the Ndb objects here as we
+ * are still single threaded
+ */
+ stepNdbs[i]= new Ndb(otherConnection,
+ "TEST_DB");
+ stepNdbs[i]->init();
+ int rc= stepNdbs[i]->waitUntilReady(10);
+
+ if (rc != 0)
+ {
+ ndbout << "Ndb " << i << " was not ready" << endl;
+ return NDBT_FAILED;
+ }
+
+ }
+
+ /* Now signal the 'worker' threads to start sending Pk
+ * reads
+ */
+ ctx->setProperty(ApiFailTestRun, 1);
+
+ /* Wait until all of them are running before proceeding */
+ ctx->getPropertyWait(ApiFailTestsRunning,
+ ctx->getProperty(ApiFailNumberPkSteps));
+
+ if (ctx->isTestStopped())
+ {
+ return NDBT_OK;
+ }
+
+ /* Clear the test-run flag so that they'll wait after
+ * they hit an error
+ */
+ ctx->setProperty(ApiFailTestRun, (Uint32)0);
+
+ /* Wait a little */
+ sleep(1);
+
+ /* Active more stringent checking of behaviour after
+ * API_FAILREQ
+ */
+ NdbRestarter restarter;
+
+ /* Activate 8078 - TCs will abort() if they get a TCKEYREQ
+ * from the failed API after an API_FAILREQ message
+ */
+ ndbout << "Activating 8078" << endl;
+ restarter.insertErrorInAllNodes(8078);
+
+ /* Wait a little longer */
+ sleep(1);
+
+ /* Now cause our connection to disconnect
+ * This results in TC receiving an API_FAILREQ
+ * If there's an issue with API_FAILREQ 'cleanly'
+ * stopping further signals, there should be
+ * an assertion failure in TC
+ */
+ int otherNodeId = otherConnection->node_id();
+
+ ndbout << "Forcing disconnect of node "
+ << otherNodeId << endl;
+
+ /* All dump 900 <nodeId> */
+ int args[2]= {900, otherNodeId};
+
+ restarter.dumpStateAllNodes( args, 2 );
+
+
+ /* Now wait for all workers to finish
+ * (Running worker count to get down to zero
+ */
+ ctx->getPropertyWait(ApiFailTestsRunning, (Uint32)0);
+
+ if (ctx->isTestStopped())
+ {
+ return NDBT_OK;
+ }
+
+ /* Clean up error insert */
+ restarter.insertErrorInAllNodes(0);
+
+ /* Clean up allocated resources */
+ for (int i= 0; i < MAX_STEPS; i++)
+ {
+ delete stepNdbs[i];
+ stepNdbs[i]= NULL;
+ }
+
+ delete otherConnection;
+ otherConnection= NULL;
+
+ return NDBT_OK;
+}
+
+
+int testApiFailReq(NDBT_Context* ctx, NDBT_Step* step)
+{
+ /* Perform a number of iterations, connecting,
+ * sending lots of PK updates, inserting error
+ * and then causing node failure
+ */
+ Uint32 iterations = 10;
+ int rc = NDBT_OK;
+
+ while (iterations --)
+ {
+ rc= testApiFailReqImpl(ctx, step);
+
+ if (rc == NDBT_FAILED)
+ {
+ break;
+ }
+ } // while(iterations --)
+
+ /* Avoid PkRead worker threads getting stuck */
+ ctx->setProperty(ApiFailTestComplete, (Uint32) 1);
+
+ return rc;
+}
+
+int runBulkPkReads(NDBT_Context* ctx, NDBT_Step* step)
+{
+ /* Run batched Pk reads */
+
+ while(true)
+ {
+ /* Wait to be signalled to start running */
+ while ((ctx->getProperty(ApiFailTestRun) == 0) &&
+ (ctx->getProperty(ApiFailTestComplete) == 0) &&
+ !ctx->isTestStopped())
+ {
+ ctx->wait_timeout(500); /* 500 millis */
+ }
+
+ if (ctx->isTestStopped() ||
+ (ctx->getProperty(ApiFailTestComplete) != 0))
+ {
+ /* Asked to stop by main test thread */
+ return NDBT_OK;
+ }
+ /* Indicate that we're underway */
+ ctx->incProperty(ApiFailTestsRunning);
+
+ Ndb* otherNdb = stepNdbs[step->getStepNo()];
+ HugoOperations hugoOps(*ctx->getTab());
+ Uint32 numRecords = ctx->getNumRecords();
+ Uint32 batchSize = (1000 < numRecords)? 1000 : numRecords;
+
+ ndbout << "Step number " << step->getStepNo()
+ << " reading batches of " << batchSize
+ << " rows " << endl;
+
+ while(true)
+ {
+ if (hugoOps.startTransaction(otherNdb) != 0)
+ {
+ ndbout << "Failed to start transaction. Error : "
+ << otherNdb->getNdbError().message << endl;
+ return NDBT_FAILED;
+ }
+
+ for (Uint32 op = 0; op < batchSize; op++)
+ {
+ if (hugoOps.pkReadRecord(otherNdb,
+ op) != 0)
+ {
+ ndbout << "Failed to define read of record number " << op << endl;
+ ndbout << "Error : " << hugoOps.getTransaction()->getNdbError().message
+ << endl;
+ return NDBT_FAILED;
+ }
+ }
+
+ if (hugoOps.execute_Commit(otherNdb) != 0)
+ {
+ NdbError err = hugoOps.getTransaction()->getNdbError();
+ ndbout << "Execute failed with Error : "
+ << err.message
+ << endl;
+
+ hugoOps.closeTransaction(otherNdb);
+
+ if ((err.code == 4010) || // Node failure
+ (err.code == 4025) || // Node failure
+ (err.code == 1218)) // Send buffer overload (reading larger tables)
+ {
+ /* Expected scenario due to injected Api disconnect
+ * If there was a node failure due to assertion failure
+ * then we'll detect it when we try to setup a new
+ * connection
+ */
+ break;
+ }
+ return NDBT_FAILED;
+ }
+
+ hugoOps.closeTransaction(otherNdb);
+ }
+
+ /* Signal that we've finished running this iteration */
+ ctx->decProperty(ApiFailTestsRunning);
+ }
+
+ return NDBT_OK;
+}
+
+
+
NDBT_TESTSUITE(testNdbApi);
TESTCASE("MaxNdb",
"Create Ndb objects until no more can be created\n"){
@@ -2992,6 +3253,24 @@ TESTCASE("Bug44065",
"Rollback no-change update on top of existing data") {
INITIALIZER(runBug44065);
}
+TESTCASE("ApiFailReqBehaviour",
+ "Check ApiFailReq cleanly marks Api disconnect") {
+ // Some flags to enable the various threads to cooperate
+ TC_PROPERTY(ApiFailTestRun, (Uint32)0);
+ TC_PROPERTY(ApiFailTestComplete, (Uint32)0);
+ TC_PROPERTY(ApiFailTestsRunning, (Uint32)0);
+ TC_PROPERTY(ApiFailNumberPkSteps, (Uint32)5); // Num threads below
+ INITIALIZER(runLoadTable);
+ // 5 threads to increase probability of pending
+ // TCKEYREQ after API_FAILREQ
+ STEP(runBulkPkReads);
+ STEP(runBulkPkReads);
+ STEP(runBulkPkReads);
+ STEP(runBulkPkReads);
+ STEP(runBulkPkReads);
+ STEP(testApiFailReq);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNdbApi);
int main(int argc, const char** argv){
=== modified file 'storage/ndb/test/run-test/autotest-boot.sh'
--- a/storage/ndb/test/run-test/autotest-boot.sh 2008-12-16 17:12:00 +0000
+++ b/storage/ndb/test/run-test/autotest-boot.sh 2009-09-03 07:43:49 +0000
@@ -13,7 +13,12 @@ save_args=$*
VERSION="autotest-boot.sh version 1.00"
DATE=`date '+%Y-%m-%d'`
-HOST=`hostname -s`
+if [ `uname -s` != "SunOS" ]
+then
+ HOST=`hostname -s`
+else
+ HOST=`hostname`
+fi
export DATE HOST
set -e
@@ -220,13 +225,16 @@ fi
################################
script=$install_dir0/mysql-test/ndb/autotest-run.sh
-sh -x $script $save_args --conf=$conf --run-dir=$install_dir --install-dir0=$install_dir0 --install-dir1=$install_dir1 --suite=$RUN --nolock $extra_args
+for R in $RUN
+do
+ sh -x $script $save_args --conf=$conf --run-dir=$install_dir --install-dir0=$install_dir0 --install-dir1=$install_dir1 --suite=$R --nolock $extra_args
+done
if [ "$build" ]
then
rm -rf $dst_place0
- if [ "$clone1" ]
+ if [ "$dst_place1" ]
then
rm -rf $dst_place1
fi
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2009-08-21 13:05:47 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2009-09-01 11:04:11 +0000
@@ -1304,3 +1304,8 @@ max-time: 300
cmd: testDict
args: -n Bug36702 D1
+# Test clean ApiFailReq behaviour
+max-time: 300
+cmd: testNdbApi
+args: -n ApiFailReqBehaviour T1
+
Thread |
---|
• bzr commit into mysql-5.1-telco-6.2 branch (Martin.Skold:2973) Bug#38034Bug#46712 Bug#47039 Bug#47072 | Martin Skold | 7 Sep |