#At file:///home/frazer/bzr/mysql-5.1-telco-7.1/ based on revid:craig.russell@stripped
4205 Frazer Clement 2011-05-18 [merge]
Merge 7.0->7.1
modified:
mysql-test/suite/ndb/r/ndb_native_default_support.result
storage/ndb/include/kernel/AttributeHeader.hpp
storage/ndb/include/kernel/signaldata/CreateTab.hpp
storage/ndb/include/kernel/signaldata/CreateTable.hpp
storage/ndb/include/kernel/signaldata/DictTabInfo.hpp
storage/ndb/include/ndb_version.h.in
storage/ndb/include/ndbapi/NdbDictionary.hpp
storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp
storage/ndb/src/kernel/vm/LongSignal.cpp
storage/ndb/src/kernel/vm/LongSignalImpl.hpp
storage/ndb/src/kernel/vm/SimulatedBlock.cpp
storage/ndb/src/kernel/vm/SimulatedBlock.hpp
storage/ndb/src/ndbapi/NdbDictionary.cpp
storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
storage/ndb/test/ndbapi/testRestartGci.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
storage/ndb/test/src/NDBT_Table.cpp
storage/ndb/tools/select_all.cpp
=== modified file 'mysql-test/suite/ndb/r/ndb_native_default_support.result'
--- a/mysql-test/suite/ndb/r/ndb_native_default_support.result 2010-11-10 13:39:11 +0000
+++ b/mysql-test/suite/ndb/r/ndb_native_default_support.result 2011-05-17 23:29:55 +0000
@@ -140,6 +140,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -178,6 +180,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
pk Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -246,6 +250,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -283,6 +289,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
pk Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -360,6 +368,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -450,6 +460,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
@@ -497,6 +509,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -538,6 +552,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -587,6 +603,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -630,6 +648,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -672,6 +692,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -714,6 +736,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -758,6 +782,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -805,6 +831,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -847,6 +875,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -891,6 +921,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -936,6 +968,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -985,6 +1019,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1028,6 +1064,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1070,6 +1108,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1112,6 +1152,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1154,6 +1196,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1198,6 +1242,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1245,6 +1291,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
a Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
@@ -1333,6 +1381,8 @@ Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 2
+ExtraRowGciBits: 0
+ExtraRowAuthorBits: 0
TableStatus: Retrieved
-- Attributes --
i Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
=== modified file 'storage/ndb/include/kernel/AttributeHeader.hpp'
--- a/storage/ndb/include/kernel/AttributeHeader.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/kernel/AttributeHeader.hpp 2011-05-17 23:29:55 +0000
@@ -66,6 +66,17 @@ public:
STATIC_CONST( CORR_FACTOR64 = 0xFFE8 ); // including root-frag
/**
+ * 64-bit row gci (extending lower if not sufficient bits)
+ * read-only
+ */
+ STATIC_CONST( ROW_GCI64 = 0xFFE7);
+
+ /**
+ * Row author... autoset to 0, can be over written
+ */
+ STATIC_CONST( ROW_AUTHOR = 0xFFE6);
+
+ /**
* Optimize pseudo column and optimization options
*/
STATIC_CONST( OPTIMIZE = 0xFFE0 ); //pseudo column id to optimize
=== modified file 'storage/ndb/include/kernel/signaldata/CreateTab.hpp'
--- a/storage/ndb/include/kernel/signaldata/CreateTab.hpp 2011-02-15 10:52:32 +0000
+++ b/storage/ndb/include/kernel/signaldata/CreateTab.hpp 2011-05-17 23:29:55 +0000
@@ -24,7 +24,7 @@
struct CreateTabReq
{
STATIC_CONST( SignalLength = 6 );
- STATIC_CONST( SignalLengthLDM = 6 + 10 );
+ STATIC_CONST( SignalLengthLDM = 6 + 11 );
enum RequestType {
};
@@ -49,6 +49,7 @@ struct CreateTabReq
Uint32 noOfKeyAttr;
Uint32 checksumIndicator;
Uint32 GCPIndicator;
+ Uint32 extraRowAuthorBits;
SECTION( DICT_TAB_INFO = 0 );
SECTION( FRAGMENTATION = 1 );
=== modified file 'storage/ndb/include/kernel/signaldata/CreateTable.hpp'
--- a/storage/ndb/include/kernel/signaldata/CreateTable.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/kernel/signaldata/CreateTable.hpp 2011-05-17 23:29:55 +0000
@@ -75,7 +75,8 @@ struct CreateTableRef {
OutOfStringBuffer = 773,
NoLoggingTemporaryTable = 778,
InvalidHashMap = 790,
- TableDefinitionTooBig = 793
+ TableDefinitionTooBig = 793,
+ FeatureRequiresUpgrade = 794
};
Uint32 senderRef;
=== modified file 'storage/ndb/include/kernel/signaldata/DictTabInfo.hpp'
--- a/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2011-02-16 14:53:53 +0000
+++ b/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2011-05-17 23:29:55 +0000
@@ -150,6 +150,9 @@ public:
TableStorageType = 155,
+ ExtraRowGCIBits = 156,
+ ExtraRowAuthorBits = 157,
+
TableEnd = 999,
AttributeName = 1000, // String, Mandatory
@@ -381,6 +384,9 @@ public:
Uint32 TableStorageType;
+ Uint32 ExtraRowGCIBits;
+ Uint32 ExtraRowAuthorBits;
+
Table() {}
void init();
};
=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in 2011-04-28 09:42:34 +0000
+++ b/storage/ndb/include/ndb_version.h.in 2011-05-17 23:37:03 +0000
@@ -628,4 +628,28 @@ ndbd_deferred_unique_constraints(Uint32
return x >= NDBD_DEFERRED_UNIQUE_CONSTRAINTS_71;
}
+#define NDBD_TUP_EXTRABITS_70 NDB_MAKE_VERSION(7,0,25)
+#define NDBD_TUP_EXTRABITS_71 NDB_MAKE_VERSION(7,1,14)
+#define NDBD_TUP_EXTRABITS_72 NDB_MAKE_VERSION(7,2,1)
+
+static
+inline
+int
+ndb_tup_extrabits(Uint32 x)
+{
+ {
+ const Uint32 major = (x >> 16) & 0xFF;
+ const Uint32 minor = (x >> 8) & 0xFF;
+
+ if (major == 7 && minor < 2)
+ {
+ if (minor == 0)
+ return x >= NDBD_TUP_EXTRABITS_70;
+ else if (minor == 1)
+ return x >= NDBD_TUP_EXTRABITS_71;
+ }
+ return x >= NDBD_TUP_EXTRABITS_72;
+ }
+}
+
#endif
=== modified file 'storage/ndb/include/ndbapi/NdbDictionary.hpp'
--- a/storage/ndb/include/ndbapi/NdbDictionary.hpp 2011-02-18 19:43:58 +0000
+++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp 2011-05-17 23:37:03 +0000
@@ -603,6 +603,8 @@ public:
static const Column * RECORDS_IN_RANGE;
static const Column * ROWID;
static const Column * ROW_GCI;
+ static const Column * ROW_GCI64;
+ static const Column * ROW_AUTHOR;
static const Column * ANY_VALUE;
static const Column * COPY_ROWID;
static const Column * LOCK_REF;
@@ -1061,6 +1063,18 @@ public:
*/
void setStorageType(Column::StorageType);
Column::StorageType getStorageType() const;
+
+ /**
+ * Get/set extra GCI bits (max 31)
+ */
+ void setExtraRowGciBits(Uint32);
+ Uint32 getExtraRowGciBits() const;
+
+ /**
+ * Get/set extra row author bits (max 31)
+ */
+ void setExtraRowAuthorBits(Uint32);
+ Uint32 getExtraRowAuthorBits() const;
#endif
// these 2 are not de-doxygenated
=== modified file 'storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp 2011-02-16 14:53:53 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp 2011-05-17 23:29:55 +0000
@@ -73,6 +73,8 @@ DictTabInfo::TableMapping[] = {
DTIMAP(Table, HashMapObjectId, HashMapObjectId),
DTIMAP(Table, HashMapVersion, HashMapVersion),
DTIMAP(Table, TableStorageType, TableStorageType),
+ DTIMAP(Table, ExtraRowGCIBits, ExtraRowGCIBits),
+ DTIMAP(Table, ExtraRowAuthorBits, ExtraRowAuthorBits),
DTIBREAK(AttributeName)
};
@@ -184,6 +186,9 @@ DictTabInfo::Table::init(){
HashMapVersion = RNIL;
TableStorageType = NDB_STORAGETYPE_DEFAULT;
+
+ ExtraRowGCIBits = 0;
+ ExtraRowAuthorBits = 0;
}
void
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2011-05-12 09:01:21 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2011-05-17 23:29:55 +0000
@@ -745,6 +745,9 @@ Dbdict::packTableIntoPages(SimplePropert
w.add(DictTabInfo::SingleUserMode, tablePtr.p->singleUserMode);
w.add(DictTabInfo::HashMapObjectId, tablePtr.p->hashMapObjectId);
w.add(DictTabInfo::TableStorageType, tablePtr.p->storageType);
+ w.add(DictTabInfo::ExtraRowGCIBits, tablePtr.p->m_extra_row_gci_bits);
+ w.add(DictTabInfo::ExtraRowAuthorBits, tablePtr.p->m_extra_row_author_bits);
+
if (tablePtr.p->hashMapObjectId != RNIL)
{
@@ -3914,6 +3917,7 @@ Dbdict::checkPendingSchemaTrans(XSchemaF
}
}
+ transEntry->m_tableType = DictTabInfo::UndefTableType;
transEntry->m_tableState = SchemaFile::SF_UNUSED;
transEntry->m_transId = 0;
}
@@ -4944,6 +4948,8 @@ void Dbdict::handleTabInfoInit(Signal *
tablePtr.p->hashMapObjectId = c_tableDesc.HashMapObjectId;
tablePtr.p->hashMapVersion = c_tableDesc.HashMapVersion;
tablePtr.p->storageType = c_tableDesc.TableStorageType;
+ tablePtr.p->m_extra_row_gci_bits = c_tableDesc.ExtraRowGCIBits;
+ tablePtr.p->m_extra_row_author_bits = c_tableDesc.ExtraRowAuthorBits;
tabRequire(tablePtr.p->noOfAttributes <= MAX_ATTRIBUTES_IN_TABLE,
CreateTableRef::NoMoreAttributeRecords); // bad error code!
@@ -5463,6 +5469,27 @@ void Dbdict::handleTabInfo(SimplePropert
tabRequire(CHECK_SUMA_MESSAGE_SIZE(keyCount, keyLength, attrCount, recordLength),
CreateTableRef::RecordTooBig);
+ /* Check that all currently running nodes data support
+ * table features
+ */
+ for (Uint32 nodeId=1; nodeId < MAX_NODES; nodeId++)
+ {
+ const NodeInfo& ni = getNodeInfo(nodeId);
+
+ if (ni.m_connected &&
+ (ni.m_type == NODE_TYPE_DB))
+ {
+ /* Check that all nodes support extra bits */
+ if (tablePtr.p->m_extra_row_gci_bits ||
+ tablePtr.p->m_extra_row_author_bits)
+ {
+ tabRequire(ndb_tup_extrabits(ni.m_version),
+ CreateTableRef::FeatureRequiresUpgrade);
+ }
+ }
+ }
+
+
if(tablePtr.p->m_tablespace_id != RNIL || counts[3] || counts[4])
{
FilegroupPtr tablespacePtr;
@@ -6167,8 +6194,9 @@ Dbdict::createTab_local(Signal* signal,
req->noOfNullAttributes = tabPtr.p->noOfNullBits;
req->noOfKeyAttr = tabPtr.p->noOfPrimkey;
req->checksumIndicator = 1;
- req->GCPIndicator = 1;
+ req->GCPIndicator = 1 + tabPtr.p->m_extra_row_gci_bits;
req->noOfAttributes = tabPtr.p->noOfAttributes;
+ req->extraRowAuthorBits = tabPtr.p->m_extra_row_author_bits;
sendSignal(DBLQH_REF, GSN_CREATE_TAB_REQ, signal,
CreateTabReq::SignalLengthLDM, JBB);
@@ -9487,7 +9515,7 @@ Dbdict::alterTable_fromCommitComplete(Si
// Remark object as free
SchemaFile::TableEntry * objEntry =
objEntry = getTableEntry(alterTabPtr.p->m_newTable_realObjectId);
- objEntry->m_tableType = DictTabInfo::SchemaTransaction;
+ objEntry->m_tableType = DictTabInfo::UndefTableType;
objEntry->m_tableState = SchemaFile::SF_UNUSED;
objEntry->m_transId = 0;
}
@@ -9579,7 +9607,7 @@ Dbdict::alterTable_abortParse(Signal* si
// Remark object as free
SchemaFile::TableEntry * objEntry =
objEntry = getTableEntry(alterTabPtr.p->m_newTable_realObjectId);
- objEntry->m_tableType = DictTabInfo::SchemaTransaction;
+ objEntry->m_tableType = DictTabInfo::UndefTableType;
objEntry->m_tableState = SchemaFile::SF_UNUSED;
objEntry->m_transId = 0;
}
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2011-05-12 09:01:21 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2011-05-17 23:29:55 +0000
@@ -280,6 +280,8 @@ public:
TR_Temporary = 0x8,
TR_ForceVarPart = 0x10
};
+ Uint8 m_extra_row_gci_bits;
+ Uint8 m_extra_row_author_bits;
Uint16 m_bits;
/* Number of attibutes in table */
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2011-04-29 11:36:28 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2011-05-17 23:37:03 +0000
@@ -4685,8 +4685,11 @@ void Dblqh::execLQHKEYREQ(Signal* signal
sig2 = lqhKeyReq->variableData[nextPos + 0];
sig3 = cnewestGci;
+ /* If gci_hi provided, take it and set gci_lo to max value
+ * Otherwise, it will be decided by TUP at commit time as normal
+ */
regTcPtr->gci_hi = LqhKeyReq::getGCIFlag(Treqinfo) ? sig2 : sig3;
- regTcPtr->gci_lo = 0;
+ regTcPtr->gci_lo = LqhKeyReq::getGCIFlag(Treqinfo) ? ~Uint32(0) : 0;
nextPos += LqhKeyReq::getGCIFlag(Treqinfo);
if (LqhKeyReq::getRowidFlag(Treqinfo))
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp 2011-05-17 23:29:55 +0000
@@ -420,6 +420,8 @@ struct Fragoperrec {
Uint32 attributeCount;
Uint32 charsetIndex;
Uint32 m_null_bits[2];
+ Uint32 m_extra_row_gci_bits;
+ Uint32 m_extra_row_author_bits;
union {
BlockReference lqhBlockrefFrag;
Uint32 m_senderRef;
@@ -827,10 +829,11 @@ struct Operationrec {
unsigned int m_disk_preallocated : 1;
unsigned int m_load_diskpage_on_commit : 1;
unsigned int m_wait_log_buffer : 1;
+ unsigned int m_gci_written : 1;
};
union {
OpBitFields op_struct;
- Uint16 op_bit_fields;
+ Uint32 op_bit_fields;
};
/*
@@ -1019,7 +1022,9 @@ ArrayPool<TupTriggerData> c_triggerPool;
TR_Checksum = 0x1, // Need to be 1
TR_RowGCI = 0x2,
TR_ForceVarPart = 0x4,
- TR_DiskPart = 0x8
+ TR_DiskPart = 0x8,
+ TR_ExtraRowGCIBits = 0x10,
+ TR_ExtraRowAuthorBits = 0x20
};
Uint16 m_bits;
Uint16 total_rec_size; // Max total size for entire tuple in words
@@ -1032,6 +1037,7 @@ ArrayPool<TupTriggerData> c_triggerPool;
Uint16 noOfKeyAttr;
Uint16 noOfCharsets;
Uint16 m_dyn_null_bits[2];
+ Uint16 m_no_of_extra_columns; // "Hidden" columns
bool need_expand() const {
return m_no_of_attributes > m_attributes[MM].m_no_of_fixsize;
@@ -1057,6 +1063,17 @@ ArrayPool<TupTriggerData> c_triggerPool;
(disk && m_attributes[DD].m_no_of_varsize > 0);
}
+ template <Uint32 bit> Uint32 getExtraAttrId() const {
+ if (bit == TR_ExtraRowGCIBits)
+ return 0;
+ Uint32 no = 0;
+ if (m_bits & TR_ExtraRowGCIBits)
+ no++;
+ assert(bit == TR_ExtraRowAuthorBits);
+ //if (bit == TR_ExtraRowAuthorBits)
+ return no;
+ }
+
/**
* Descriptors for MM and DD part
*/
@@ -2950,10 +2967,15 @@ private:
void initData();
void initRecords();
+ // 2 words for optional GCI64 + AUTHOR info
+#define EXTRA_COPY_PROC_WORDS 2
+#define MAX_COPY_PROC_LEN (MAX_ATTRIBUTES_IN_TABLE + EXTRA_COPY_PROC_WORDS)
+
+
void deleteScanProcedure(Signal* signal, Operationrec* regOperPtr);
void allocCopyProcedure();
void freeCopyProcedure();
- void prepareCopyProcedure(Uint32 numAttrs);
+ void prepareCopyProcedure(Uint32 numAttrs, Uint16 tableBits);
void releaseCopyProcedure();
void copyProcedure(Signal* signal,
TablerecPtr regTabPtr,
@@ -2972,7 +2994,7 @@ private:
//-----------------------------------------------------------------------------
// Public methods
- Uint32 getTabDescrOffsets(Uint32, Uint32, Uint32, Uint32*);
+ Uint32 getTabDescrOffsets(Uint32, Uint32, Uint32, Uint32, Uint32*);
Uint32 getDynTabDescrOffsets(Uint32 MaskSize, Uint32* offset);
Uint32 allocTabDescr(Uint32 allocSize);
void releaseTabDescr(Uint32 desc);
@@ -3173,6 +3195,8 @@ private:
Uint32 czero;
Uint32 cCopyProcedure;
Uint32 cCopyLastSeg;
+ Uint32 cCopyOverwrite;
+ Uint32 cCopyOverwriteLen;
// A little bit bigger to cover overwrites in copy algorithms (16384 real size).
#define ZATTR_BUFFER_SIZE 16384
@@ -3379,15 +3403,19 @@ private:
void findFirstOp(OperationrecPtr&);
bool is_rowid_lcp_scanned(const Local_key& key1,
const Dbtup::ScanOp& op);
- void commit_operation(Signal*, Uint32, Tuple_header*, PagePtr,
+ void commit_operation(Signal*, Uint32, Uint32, Tuple_header*, PagePtr,
Operationrec*, Fragrecord*, Tablerec*);
int retrieve_data_page(Signal*,
Page_cache_client::Request,
OperationrecPtr);
int retrieve_log_page(Signal*, FragrecordPtr, OperationrecPtr);
- void dealloc_tuple(Signal* signal, Uint32, Page*, Tuple_header*,
+ void dealloc_tuple(Signal* signal, Uint32, Uint32, Page*, Tuple_header*,
KeyReqStruct*, Operationrec*, Fragrecord*, Tablerec*);
+ bool store_extra_row_bits(Uint32, const Tablerec*, Tuple_header*, Uint32,
+ bool);
+ void read_extra_row_bits(Uint32, const Tablerec*, Tuple_header*, Uint32 *,
+ bool);
int handle_size_change_after_update(KeyReqStruct* req_struct,
Tuple_header* org,
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp 2011-05-17 23:29:55 +0000
@@ -147,7 +147,8 @@ Dbtup::is_rowid_lcp_scanned(const Local_
void
Dbtup::dealloc_tuple(Signal* signal,
- Uint32 gci,
+ Uint32 gci_hi,
+ Uint32 gci_lo,
Page* page,
Tuple_header* ptr,
KeyReqStruct * req_struct,
@@ -168,7 +169,7 @@ Dbtup::dealloc_tuple(Signal* signal,
tmpptr.i = m_pgman_ptr.i;
tmpptr.p = reinterpret_cast<Page*>(m_pgman_ptr.p);
disk_page_free(signal, regTabPtr, regFragPtr,
- &disk, tmpptr, gci);
+ &disk, tmpptr, gci_hi);
}
if (! (bits & (Tuple_header::LCP_SKIP | Tuple_header::ALLOC)) &&
@@ -199,7 +200,12 @@ Dbtup::dealloc_tuple(Signal* signal,
if (regTabPtr->m_bits & Tablerec::TR_RowGCI)
{
jam();
- * ptr->get_mm_gci(regTabPtr) = gci;
+ * ptr->get_mm_gci(regTabPtr) = gci_hi;
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId = regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ store_extra_row_bits(attrId, regTabPtr, ptr, gci_lo, /* truncate */true);
+ }
}
}
@@ -288,7 +294,8 @@ static void dump_buf_hex(unsigned char *
void
Dbtup::commit_operation(Signal* signal,
- Uint32 gci,
+ Uint32 gci_hi,
+ Uint32 gci_lo,
Tuple_header* tuple_ptr,
PagePtr pagePtr,
Operationrec* regOperPtr,
@@ -309,6 +316,7 @@ Dbtup::commit_operation(Signal* signal,
Uint32 fixsize= regTabPtr->m_offsets[MM].m_fix_header_size;
Uint32 mm_vars= regTabPtr->m_attributes[MM].m_no_of_varsize;
Uint32 mm_dyns= regTabPtr->m_attributes[MM].m_no_of_dynamic;
+ bool update_gci_at_commit = ! regOperPtr->op_struct.m_gci_written;
if((mm_vars+mm_dyns) == 0)
{
jam();
@@ -399,7 +407,7 @@ Dbtup::commit_operation(Signal* signal,
if(copy_bits & Tuple_header::DISK_ALLOC)
{
jam();
- disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci);
+ disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci_hi);
}
if(regTabPtr->m_attributes[DD].m_no_of_varsize == 0)
@@ -419,7 +427,7 @@ Dbtup::commit_operation(Signal* signal,
{
jam();
disk_page_undo_update(diskPagePtr.p,
- &key, dst, sz, gci, logfile_group_id);
+ &key, dst, sz, gci_hi, logfile_group_id);
}
memcpy(dst, disk_ptr, 4*sz);
@@ -452,10 +460,17 @@ Dbtup::commit_operation(Signal* signal,
tuple_ptr->m_header_bits= copy_bits;
tuple_ptr->m_operation_ptr_i= save;
- if (regTabPtr->m_bits & Tablerec::TR_RowGCI)
+ if (regTabPtr->m_bits & Tablerec::TR_RowGCI &&
+ update_gci_at_commit)
{
jam();
- * tuple_ptr->get_mm_gci(regTabPtr) = gci;
+ * tuple_ptr->get_mm_gci(regTabPtr) = gci_hi;
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId = regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ store_extra_row_bits(attrId, regTabPtr, tuple_ptr, gci_lo,
+ /* truncate */true);
+ }
}
if (regTabPtr->m_bits & Tablerec::TR_Checksum) {
@@ -837,7 +852,7 @@ skip_disk:
if(regOperPtr.p->op_struct.op_type != ZDELETE)
{
jam();
- commit_operation(signal, gci_hi, tuple_ptr, page,
+ commit_operation(signal, gci_hi, gci_lo, tuple_ptr, page,
regOperPtr.p, regFragPtr.p, regTabPtr.p);
}
else
@@ -847,7 +862,7 @@ skip_disk:
{
ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART);
}
- dealloc_tuple(signal, gci_hi, page.p, tuple_ptr,
+ dealloc_tuple(signal, gci_hi, gci_lo, page.p, tuple_ptr,
&req_struct, regOperPtr.p, regFragPtr.p, regTabPtr.p);
}
}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2011-05-17 23:29:55 +0000
@@ -192,6 +192,8 @@ Dbtup::insertActiveOpList(OperationrecPt
prevOpPtr.p->op_struct.m_wait_log_buffer;
regOperPtr.p->op_struct.m_load_diskpage_on_commit=
prevOpPtr.p->op_struct.m_load_diskpage_on_commit;
+ regOperPtr.p->op_struct.m_gci_written=
+ prevOpPtr.p->op_struct.m_gci_written;
regOperPtr.p->m_undo_buffer_space= prevOpPtr.p->m_undo_buffer_space;
// start with prev mask (matters only for UPD o UPD)
@@ -629,6 +631,8 @@ void Dbtup::execTUPKEYREQ(Signal* signal
req_struct.attrinfo_len,
attrInfoIVal);
+ regOperPtr->op_struct.m_gci_written = 0;
+
if (Roptype == ZINSERT && Local_key::isInvalid(pageid, pageidx))
{
// No tuple allocatated yet
@@ -1114,6 +1118,15 @@ int Dbtup::handleUpdateReq(Signal* signa
if (!req_struct->interpreted_exec) {
jam();
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ jam();
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, dst, /* default */ 0, false);
+ }
int retValue = updateAttributes(req_struct,
&cinBuffer[0],
req_struct->attrinfo_len);
@@ -1660,6 +1673,14 @@ int Dbtup::handleInsertReq(Signal* signa
terrorCode = ZAI_INCONSISTENCY_ERROR;
goto update_error;
}
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, tuple_ptr, /* default */ 0, false);
+ }
if (!regTabPtr->m_default_value_location.isNull())
{
@@ -2209,6 +2230,28 @@ int Dbtup::interpreterStartLab(Signal* s
return -1;
}
}
+
+ if ((RlogSize > 0) ||
+ (RfinalUpdateLen > 0))
+ {
+ /* Operation updates row,
+ * reset author pseudo-col before update takes effect
+ * This should probably occur only if the interpreted program
+ * did not explicitly write the value, but that requires a bit
+ * to record whether the value has been written.
+ */
+ Tablerec* regTabPtr = req_struct->tablePtrP;
+ Tuple_header* dst = req_struct->m_tuple_ptr;
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ store_extra_row_bits(attrId, regTabPtr, dst, /* default */ 0, false);
+ }
+ }
+
if (RfinalUpdateLen > 0) {
jam();
/* ---------------------------------------------------------------- */
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp 2011-05-17 23:29:55 +0000
@@ -51,6 +51,8 @@ void Dbtup::initData()
cCopyProcedure = RNIL;
cCopyLastSeg = RNIL;
+ cCopyOverwrite = 0;
+ cCopyOverwriteLen = 0;
// Records with constant sizes
init_list_sizes();
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp 2011-05-17 23:29:55 +0000
@@ -76,6 +76,9 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
memset(fragOperPtr.p->m_null_bits, 0, sizeof(fragOperPtr.p->m_null_bits));
fragOperPtr.p->charsetIndex = 0;
fragOperPtr.p->lqhBlockrefFrag = req->senderRef;
+ fragOperPtr.p->m_extra_row_gci_bits =
+ req->GCPIndicator > 1 ? req->GCPIndicator - 1 : 0;
+ fragOperPtr.p->m_extra_row_author_bits = req->extraRowAuthorBits;
regTabPtr.p->m_createTable.m_fragOpPtrI = fragOperPtr.i;
regTabPtr.p->m_createTable.defValSectionI = RNIL;
@@ -84,6 +87,9 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
regTabPtr.p->m_bits |= (req->checksumIndicator ? Tablerec::TR_Checksum : 0);
regTabPtr.p->m_bits |= (req->GCPIndicator ? Tablerec::TR_RowGCI : 0);
regTabPtr.p->m_bits |= (req->forceVarPartFlag? Tablerec::TR_ForceVarPart : 0);
+ regTabPtr.p->m_bits |=
+ (req->GCPIndicator > 1 ? Tablerec::TR_ExtraRowGCIBits : 0);
+ regTabPtr.p->m_bits |= (req->extraRowAuthorBits ? Tablerec::TR_ExtraRowAuthorBits : 0);
regTabPtr.p->m_offsets[MM].m_disk_ref_offset= 0;
regTabPtr.p->m_offsets[MM].m_null_words= 0;
@@ -118,12 +124,26 @@ Dbtup::execCREATE_TAB_REQ(Signal* signal
regTabPtr.p->m_no_of_attributes= req->noOfAttributes;
regTabPtr.p->dynTabDescriptor[MM]= RNIL;
regTabPtr.p->dynTabDescriptor[DD]= RNIL;
+ regTabPtr.p->m_no_of_extra_columns = 0;
+
+ if (regTabPtr.p->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ jam();
+ regTabPtr.p->m_no_of_extra_columns++;
+ }
+
+ if (regTabPtr.p->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ jam();
+ regTabPtr.p->m_no_of_extra_columns++;
+ }
{
Uint32 offset[10];
Uint32 allocSize= getTabDescrOffsets(req->noOfAttributes,
req->noOfCharsets,
req->noOfKeyAttr,
+ regTabPtr.p->m_no_of_extra_columns,
offset);
Uint32 tableDescriptorRef= allocTabDescr(allocSize);
if (tableDescriptorRef == RNIL)
@@ -178,6 +198,8 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
fragOperPtr.p->attributeCount--;
const bool lastAttr = (fragOperPtr.p->attributeCount == 0);
+ Uint32 extraAttrId = 0;
+
Uint32 firstTabDesIndex= regTabPtr.p->tabDescriptor + (attrId * ZAD_SIZE);
setTabDescrWord(firstTabDesIndex, attrDescriptor);
Uint32 attrLen = AttributeDescriptor::getSize(attrDescriptor);
@@ -321,7 +343,71 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal*
signal, 2, JBB);
return;
}
-
+
+ if (fragOperPtr.p->m_extra_row_gci_bits)
+ {
+ jam();
+
+ const Uint32 bits = fragOperPtr.p->m_extra_row_gci_bits;
+
+ /**
+ * Create attribute descriptor for extra row gci bits...
+ */
+ Uint32 desc = 0;
+ Uint32 off = 0;
+
+ AttributeDescriptor::setSize(desc, 0); // bit
+ AttributeDescriptor::setArraySize(desc, bits);
+ AttributeOffset::setNullFlagPos(off, fragOperPtr.p->m_null_bits[MM]);
+ fragOperPtr.p->m_null_bits[MM] += bits;
+
+ if (fragOperPtr.p->m_null_bits[MM] > AO_NULL_FLAG_POS_MASK)
+ {
+ jam();
+ terrorCode = ZTOO_MANY_BITS_ERROR;
+ goto error;
+ }
+
+ Uint32 idx = regTabPtr.p->tabDescriptor;
+ idx += ZAD_SIZE * (regTabPtr.p->m_no_of_attributes + extraAttrId);
+ setTabDescrWord(idx, desc);
+ setTabDescrWord(idx + 1, off);
+
+ extraAttrId++;
+ }
+
+ if (fragOperPtr.p->m_extra_row_author_bits)
+ {
+ jam();
+
+ const Uint32 bits = fragOperPtr.p->m_extra_row_author_bits;
+
+ /**
+ * Create attribute descriptor for extra row gci bits...
+ */
+ Uint32 desc = 0;
+ Uint32 off = 0;
+
+ AttributeDescriptor::setSize(desc, 0); // bit
+ AttributeDescriptor::setArraySize(desc, bits);
+ AttributeOffset::setNullFlagPos(off, fragOperPtr.p->m_null_bits[MM]);
+ fragOperPtr.p->m_null_bits[MM] += bits;
+
+ if (fragOperPtr.p->m_null_bits[MM] > AO_NULL_FLAG_POS_MASK)
+ {
+ jam();
+ terrorCode = ZTOO_MANY_BITS_ERROR;
+ goto error;
+ }
+
+ Uint32 idx = regTabPtr.p->tabDescriptor;
+ idx += ZAD_SIZE * (regTabPtr.p->m_no_of_attributes + extraAttrId);
+ setTabDescrWord(idx, desc);
+ setTabDescrWord(idx + 1, off);
+
+ extraAttrId++;
+ }
+
#define BTW(x) ((x+31) >> 5)
regTabPtr.p->m_offsets[MM].m_null_words= BTW(fragOperPtr.p->m_null_bits[MM]);
regTabPtr.p->m_offsets[DD].m_null_words= BTW(fragOperPtr.p->m_null_bits[DD]);
@@ -1027,6 +1113,7 @@ Dbtup::handleAlterTablePrepare(Signal *s
/* Allocate a new (possibly larger) table descriptor buffer. */
Uint32 allocSize= getTabDescrOffsets(newNoOfAttr, newNoOfCharsets,
newNoOfKeyAttrs,
+ regTabPtr->m_no_of_extra_columns,
regAlterTabOpPtr.p->tabDesOffset);
Uint32 tableDescriptorRef= allocTabDescr(allocSize);
if (tableDescriptorRef == RNIL) {
@@ -1047,11 +1134,24 @@ Dbtup::handleAlterTablePrepare(Signal *s
(CHARSET_INFO**)(desc + regAlterTabOpPtr.p->tabDesOffset[2]);
memcpy(CharsetArray, regTabPtr->charsetArray,
sizeof(*CharsetArray)*regTabPtr->noOfCharsets);
- Uint32 *attrDesPtr= desc + regAlterTabOpPtr.p->tabDesOffset[4];
+ Uint32 * const attrDesPtrStart = desc + regAlterTabOpPtr.p->tabDesOffset[4];
+ Uint32 * attrDesPtr = attrDesPtrStart;
memcpy(attrDesPtr,
&tableDescriptor[regTabPtr->tabDescriptor].tabDescr,
- (ZAD_SIZE<<2)*oldNoOfAttr);
- attrDesPtr+= ZAD_SIZE*oldNoOfAttr;
+ 4 * ZAD_SIZE * oldNoOfAttr);
+
+ /**
+ * Copy extra columns descriptors to end of attrDesPtr
+ */
+ {
+ const Uint32 * src = &tableDescriptor[regTabPtr->tabDescriptor].tabDescr;
+ src += ZAD_SIZE * oldNoOfAttr;
+
+ Uint32 * dst = attrDesPtr + (ZAD_SIZE * newNoOfAttr);
+ memcpy(dst, src, 4 * ZAD_SIZE * regTabPtr->m_no_of_extra_columns);
+ }
+
+ attrDesPtr+= ZAD_SIZE * oldNoOfAttr;
/*
Loop over the new attributes to add.
@@ -1122,6 +1222,7 @@ Dbtup::handleAlterTablePrepare(Signal *s
*attrDesPtr++= attrDes2;
}
ndbassert(newNoOfCharsets==charsetIndex);
+ ndbrequire(attrDesPtr == attrDesPtrStart + (ZAD_SIZE * newNoOfAttr));
regAlterTabOpPtr.p->noOfDynNullBits= dyn_nullbits;
ndbassert(noDynamic ==
@@ -1841,6 +1942,7 @@ void Dbtup::releaseTabDescr(Tablerec* co
getTabDescrOffsets(regTabPtr->m_no_of_attributes,
regTabPtr->noOfCharsets,
regTabPtr->noOfKeyAttr,
+ regTabPtr->m_no_of_extra_columns,
offset);
regTabPtr->tabDescriptor= RNIL;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2011-04-13 08:51:04 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2011-05-17 23:29:55 +0000
@@ -25,6 +25,7 @@
#include <AttributeDescriptor.hpp>
#include "AttributeOffset.hpp"
#include <AttributeHeader.hpp>
+#include <dblqh/Dblqh.hpp>
void
Dbtup::setUpQueryRoutines(Tablerec *regTabPtr)
@@ -1743,6 +1744,63 @@ int Dbtup::updateAttributes(KeyReqStruct
inBufIndex += 1 + sz;
req_struct->in_buf_index = inBufIndex;
}
+ else if (attributeId == AttributeHeader::ROW_AUTHOR)
+ {
+ jam();
+ Uint32 sz= ahIn.getDataSize();
+ ndbrequire(sz == 1);
+
+ Uint32 value = * (inBuffer + inBufIndex + 1);
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ if (unlikely(!(regTabPtr->m_bits & Tablerec::TR_ExtraRowAuthorBits)))
+ {
+ return -ZATTRIBUTE_ID_ERROR;
+ }
+
+ if (unlikely(store_extra_row_bits(attrId, regTabPtr,
+ req_struct->m_tuple_ptr,
+ value, /* truncate */ false) == false))
+ {
+ return -ZAI_INCONSISTENCY_ERROR;
+ }
+ inBufIndex += 1 + sz;
+ req_struct->in_buf_index = inBufIndex;
+ }
+ else if (attributeId == AttributeHeader::ROW_GCI64)
+ {
+ jam();
+ Uint32 sz= ahIn.getDataSize();
+ ndbrequire(sz == 2);
+ Uint32 attrId =
+ regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ Uint32 gciLo = * (inBuffer + inBufIndex + 1);
+ Uint32 gciHi = * (inBuffer + inBufIndex + 2);
+
+ if (unlikely(!(regTabPtr->m_bits & Tablerec::TR_RowGCI)))
+ {
+ return -ZATTRIBUTE_ID_ERROR;
+ }
+
+ /* Record that GCI has been set explicitly */
+ regOperPtr->op_struct.m_gci_written = 1;
+
+ *req_struct->m_tuple_ptr->get_mm_gci(regTabPtr) = gciHi;
+
+ if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ if (unlikely(store_extra_row_bits(attrId, regTabPtr,
+ req_struct->m_tuple_ptr,
+ gciLo, /*truncate*/ true) == false))
+ {
+ return -ZAI_INCONSISTENCY_ERROR;
+ }
+ }
+
+ inBufIndex+= 1 + sz;
+ req_struct->in_buf_index = inBufIndex;
+ }
else
{
jam();
@@ -2502,6 +2560,48 @@ Dbtup::read_pseudo(const Uint32 * inBuff
sz = 2;
}
break;
+ case AttributeHeader::ROW_GCI64:
+ {
+ sz = 0;
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_RowGCI)
+ {
+ Uint32 tmp0 = *req_struct->m_tuple_ptr->get_mm_gci(req_struct->tablePtrP);
+ Uint32 tmp1 = ~Uint32(0);
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ Uint32 attrId =
+ req_struct->tablePtrP->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>();
+ read_extra_row_bits(attrId,
+ req_struct->tablePtrP,
+ req_struct->m_tuple_ptr,
+ &tmp1,
+ /* extend */ true);
+ }
+ Uint64 tmp = Uint64(tmp0) << 32 | tmp1;
+ memcpy(outBuffer + 1, &tmp, sizeof(tmp));
+ sz = 2;
+ }
+ break;
+ }
+ case AttributeHeader::ROW_AUTHOR:
+ {
+ sz = 0;
+ if (req_struct->tablePtrP->m_bits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ Uint32 attrId = req_struct->tablePtrP
+ ->getExtraAttrId<Tablerec::TR_ExtraRowAuthorBits>();
+
+ Uint32 tmp;
+ read_extra_row_bits(attrId,
+ req_struct->tablePtrP,
+ req_struct->m_tuple_ptr,
+ &tmp,
+ /* extend */ false);
+ outBuffer[1] = tmp;
+ sz = 1;
+ }
+ break;
+ }
case AttributeHeader::ANY_VALUE:
{
/**
@@ -3426,3 +3526,85 @@ Dbtup::read_lcp_keys(Uint32 tableId,
return ret;
}
+
+bool
+Dbtup::store_extra_row_bits(Uint32 extra_no,
+ const Tablerec* regTabPtr,
+ Tuple_header* ptr,
+ Uint32 value,
+ bool truncate)
+{
+ jam();
+ if (unlikely(extra_no >= regTabPtr->m_no_of_extra_columns))
+ return false;
+ /**
+ * ExtraRowGCIBits are using regTabPtr->m_no_of_attributes + extra_no
+ */
+ Uint32 num_attr= regTabPtr->m_no_of_attributes;
+ Uint32 attrId = num_attr + extra_no;
+ Uint32 descr_start = regTabPtr->tabDescriptor;
+ TableDescriptor *tab_descr = &tableDescriptor[descr_start];
+ ndbrequire(descr_start + (attrId << ZAD_LOG_SIZE)<= cnoOfTabDescrRec);
+
+ Uint32 attrDescriptorIndex = attrId << ZAD_LOG_SIZE;
+ Uint32 attrDescriptor = tab_descr[attrDescriptorIndex].tabDescr;
+ Uint32 attrOffset = tab_descr[attrDescriptorIndex + 1].tabDescr;
+
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrOffset);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 maxVal = (1 << bitCount) - 1;
+ Uint32 *bits= ptr->get_null_bits(regTabPtr);
+
+ if (value > maxVal)
+ {
+ if (truncate)
+ {
+ value = maxVal;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ Uint32 check = regTabPtr->m_offsets[MM].m_null_words;
+ BitmaskImpl::setField(check, bits, pos, bitCount, &value);
+ return true;
+}
+
+void
+Dbtup::read_extra_row_bits(Uint32 extra_no,
+ const Tablerec* regTabPtr,
+ Tuple_header* ptr,
+ Uint32 * value,
+ bool extend)
+{
+ /**
+ * ExtraRowGCIBits are using regTabPtr->m_no_of_attributes + extra_no
+ */
+ ndbrequire(extra_no < regTabPtr->m_no_of_extra_columns);
+ Uint32 num_attr= regTabPtr->m_no_of_attributes;
+ Uint32 attrId = num_attr + extra_no;
+ Uint32 descr_start = regTabPtr->tabDescriptor;
+ TableDescriptor *tab_descr = &tableDescriptor[descr_start];
+ ndbrequire(descr_start + (attrId << ZAD_LOG_SIZE)<= cnoOfTabDescrRec);
+
+ Uint32 attrDescriptorIndex = attrId << ZAD_LOG_SIZE;
+ Uint32 attrDescriptor = tab_descr[attrDescriptorIndex].tabDescr;
+ Uint32 attrOffset = tab_descr[attrDescriptorIndex + 1].tabDescr;
+
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrOffset);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 maxVal = (1 << bitCount) - 1;
+ Uint32 *bits= ptr->get_null_bits(regTabPtr);
+
+ Uint32 tmp;
+ Uint32 check = regTabPtr->m_offsets[MM].m_null_words;
+ BitmaskImpl::getField(check, bits, pos, bitCount, &tmp);
+
+ if (tmp == maxVal && extend)
+ {
+ tmp = ~Uint32(0);
+ }
+ * value = tmp;
+}
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp 2011-02-08 14:45:27 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp 2011-05-17 23:29:55 +0000
@@ -189,8 +189,15 @@ void Dbtup::allocCopyProcedure()
ndbrequire(appendToSection(iVal, &ahWord, 1));
}
+ /* Add space for extra attrs */
+ ahWord = 0;
+ for (Uint32 extra=0; extra < EXTRA_COPY_PROC_WORDS; extra++)
+ ndbrequire(appendToSection(iVal, &ahWord, 1));
+
cCopyProcedure= iVal;
cCopyLastSeg= RNIL;
+ cCopyOverwrite= 0;
+ cCopyOverwriteLen= 0;
}
void Dbtup::freeCopyProcedure()
@@ -201,7 +208,8 @@ void Dbtup::freeCopyProcedure()
cCopyProcedure=RNIL;
}
-void Dbtup::prepareCopyProcedure(Uint32 numAttrs)
+void Dbtup::prepareCopyProcedure(Uint32 numAttrs,
+ Uint16 tableBits)
{
/* Set length of copy procedure section to the
* number of attributes supplied
@@ -209,22 +217,49 @@ void Dbtup::prepareCopyProcedure(Uint32
ndbassert(numAttrs <= MAX_ATTRIBUTES_IN_TABLE);
ndbassert(cCopyProcedure != RNIL);
ndbassert(cCopyLastSeg == RNIL);
+ ndbassert(cCopyOverwrite == 0);
+ ndbassert(cCopyOverwriteLen == 0);
Ptr<SectionSegment> first;
g_sectionSegmentPool.getPtr(first, cCopyProcedure);
/* Record original 'last segment' of section */
cCopyLastSeg= first.p->m_lastSegment;
+ /* Check table bits to see if we need to do extra reads */
+ Uint32 extraAttrIds[EXTRA_COPY_PROC_WORDS];
+ Uint32 extraReads = 0;
+
+ if (tableBits & Tablerec::TR_ExtraRowGCIBits)
+ {
+ AttributeHeader ah(AttributeHeader::ROW_GCI64,0);
+ extraAttrIds[extraReads++] = ah.m_value;
+ }
+ if (tableBits & Tablerec::TR_ExtraRowAuthorBits)
+ {
+ AttributeHeader ah(AttributeHeader::ROW_AUTHOR,0);
+ extraAttrIds[extraReads++] = ah.m_value;
+ }
+
/* Modify section to represent relevant prefix
* of code by modifying size and lastSegment
*/
- first.p->m_sz= numAttrs;
+ Uint32 newSize = numAttrs + extraReads;
+ first.p->m_sz= newSize;
+ if (extraReads)
+ {
+ cCopyOverwrite= numAttrs;
+ cCopyOverwriteLen = extraReads;
+
+ ndbrequire(writeToSection(first.i, numAttrs, extraAttrIds, extraReads));
+ }
+
+ /* Trim section size and lastSegment */
Ptr<SectionSegment> curr= first;
- while(numAttrs > SectionSegment::DataLength)
+ while(newSize > SectionSegment::DataLength)
{
g_sectionSegmentPool.getPtr(curr, curr.p->m_nextSegment);
- numAttrs-= SectionSegment::DataLength;
+ newSize-= SectionSegment::DataLength;
}
first.p->m_lastSegment= curr.i;
}
@@ -238,10 +273,24 @@ void Dbtup::releaseCopyProcedure()
Ptr<SectionSegment> first;
g_sectionSegmentPool.getPtr(first, cCopyProcedure);
- ndbassert(first.p->m_sz <= MAX_ATTRIBUTES_IN_TABLE);
- first.p->m_sz= MAX_ATTRIBUTES_IN_TABLE;
+ ndbassert(first.p->m_sz <= MAX_COPY_PROC_LEN);
+ first.p->m_sz= MAX_COPY_PROC_LEN;
first.p->m_lastSegment= cCopyLastSeg;
+ if (cCopyOverwriteLen)
+ {
+ ndbassert(cCopyOverwriteLen <= EXTRA_COPY_PROC_WORDS);
+ Uint32 attrids[EXTRA_COPY_PROC_WORDS];
+ for (Uint32 i=0; i < cCopyOverwriteLen; i++)
+ {
+ AttributeHeader ah(cCopyOverwrite + i, 0);
+ attrids[i] = ah.m_value;
+ }
+ ndbrequire(writeToSection(first.i, cCopyOverwrite, attrids, cCopyOverwriteLen));
+ cCopyOverwriteLen= 0;
+ cCopyOverwrite= 0;
+ }
+
cCopyLastSeg= RNIL;
}
@@ -257,8 +306,13 @@ void Dbtup::copyProcedure(Signal* signal
* This assumes that there is only one fragment copy going
* on at any time, which is verified by checking
* cCopyLastSeg == RNIL before starting each copy
+ *
+ * If the table has extra per-row metainformation that
+ * needs copied then we add that to the copy procedure
+ * as well.
*/
- prepareCopyProcedure(regTabPtr.p->m_no_of_attributes);
+ prepareCopyProcedure(regTabPtr.p->m_no_of_attributes,
+ regTabPtr.p->m_bits);
SectionHandle handle(this);
handle.m_cnt=1;
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp 2011-04-19 15:59:06 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp 2011-05-17 23:29:55 +0000
@@ -38,8 +38,11 @@
*/
Uint32
-Dbtup::getTabDescrOffsets(Uint32 noOfAttrs, Uint32 noOfCharsets,
- Uint32 noOfKeyAttr, Uint32* offset)
+Dbtup::getTabDescrOffsets(Uint32 noOfAttrs,
+ Uint32 noOfCharsets,
+ Uint32 noOfKeyAttr,
+ Uint32 extraColumns,
+ Uint32* offset)
{
// belongs to configure.in
unsigned sizeOfPointer = sizeof(CHARSET_INFO*);
@@ -53,7 +56,7 @@ Dbtup::getTabDescrOffsets(Uint32 noOfAtt
offset[2] = allocSize += noOfAttrs * sizeOfReadFunction();
offset[3] = allocSize += noOfCharsets * sizeOfPointer;
offset[4] = allocSize += noOfKeyAttr;
- offset[5] = allocSize += noOfAttrs * ZAD_SIZE;
+ offset[5] = allocSize += (noOfAttrs + extraColumns) * ZAD_SIZE;
offset[6] = allocSize += (noOfAttrs+1) >> 1; // real order
allocSize += ZTD_TRAILER_SIZE;
// return number of words
@@ -322,6 +325,7 @@ Dbtup::verifytabdes()
const Uint32 alloc = getTabDescrOffsets(ptr.p->m_no_of_attributes,
ptr.p->noOfCharsets,
ptr.p->noOfKeyAttr,
+ ptr.p->m_no_of_extra_columns,
offset);
const Uint32 desc = ptr.p->readKeyArray - offset[3];
Uint32 size = alloc;
=== modified file 'storage/ndb/src/kernel/vm/LongSignal.cpp'
--- a/storage/ndb/src/kernel/vm/LongSignal.cpp 2011-02-22 06:57:40 +0000
+++ b/storage/ndb/src/kernel/vm/LongSignal.cpp 2011-05-17 23:29:55 +0000
@@ -414,3 +414,58 @@ releaseSection(SPC_ARG Uint32 firstSegme
p->m_lastSegment);
}
}
+
+bool
+writeToSection(Uint32 firstSegmentIVal, Uint32 offset,
+ const Uint32* src,
+ Uint32 len)
+{
+ Ptr<SectionSegment> segPtr;
+
+ if (len == 0)
+ return true;
+
+ if (firstSegmentIVal == RNIL)
+ {
+ return false;
+ }
+ else
+ {
+ /* Section has at least one segment with data already */
+ g_sectionSegmentPool.getPtr(segPtr, firstSegmentIVal);
+
+ Uint32 existingLen= segPtr.p->m_sz;
+
+ assert(existingLen > 0);
+ if (offset >= existingLen)
+ return false; /* No sparse sections or extension */
+ if (len > (existingLen - offset))
+ return false; /* Would be extending beyond current length */
+
+ /* Advance through segments to the one containing the start offset */
+ while (offset >= SectionSegment::DataLength)
+ {
+ g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
+ offset-= SectionSegment::DataLength;
+ }
+
+ /* Now overwrite the words */
+ while (true)
+ {
+ Uint32 wordsToCopy = MIN(len,
+ SectionSegment::DataLength - offset);
+ memcpy(&segPtr.p->theData[offset], src, (wordsToCopy << 2));
+ src+= wordsToCopy;
+ len-= wordsToCopy;
+
+ if (!len)
+ {
+ return true;
+ }
+
+ offset = 0;
+ g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
+ }
+ }
+}
+
=== modified file 'storage/ndb/src/kernel/vm/LongSignalImpl.hpp'
--- a/storage/ndb/src/kernel/vm/LongSignalImpl.hpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/kernel/vm/LongSignalImpl.hpp 2011-05-17 23:29:55 +0000
@@ -48,6 +48,8 @@ bool import(SPC_ARG Ptr<SectionSegment>
bool appendToSection(SPC_ARG Uint32& firstSegmentIVal, const Uint32* src, Uint32 len);
/* dupSection : Create new section as copy of src section */
bool dupSection(SPC_ARG Uint32& copyFirstIVal, Uint32 srcFirstIVal);
+/* writeToSection : Overwrite section from offset with data. */
+bool writeToSection(Uint32 firstSegmentIVal, Uint32 offset, const Uint32* src, Uint32 len);
void release(SPC_ARG SegmentedSectionPtr & ptr);
void releaseSection(SPC_ARG Uint32 firstSegmentIVal);
=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.cpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp 2011-05-16 12:24:55 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp 2011-05-17 23:29:55 +0000
@@ -1578,6 +1578,13 @@ SimulatedBlock::dupSection(Uint32& copyF
return ::dupSection(SB_SP_ARG copyFirstIVal, srcFirstIVal);
}
+bool
+SimulatedBlock::writeToSection(Uint32 firstSegmentIVal, Uint32 offset,
+ const Uint32* src, Uint32 len)
+{
+ return ::writeToSection(firstSegmentIVal, offset, src, len);
+}
+
class SectionSegmentPool&
SimulatedBlock::getSectionSegmentPool(){
return g_sectionSegmentPool;
=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.hpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp 2011-05-16 12:24:55 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp 2011-05-17 23:29:55 +0000
@@ -350,6 +350,7 @@ protected:
bool import(SegmentedSectionPtr& ptr, const Uint32* src, Uint32 len);
bool appendToSection(Uint32& firstSegmentIVal, const Uint32* src, Uint32 len);
bool dupSection(Uint32& copyFirstIVal, Uint32 srcFirstIVal);
+ bool writeToSection(Uint32 firstSegmentIVal, Uint32 offset, const Uint32* src, Uint32 len);
void handle_invalid_sections_in_send_signal(Signal*) const;
void handle_lingering_sections_after_execute(Signal*) const;
=== modified file 'storage/ndb/src/ndbapi/NdbDictionary.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionary.cpp 2011-02-18 19:43:58 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp 2011-05-17 23:37:03 +0000
@@ -934,6 +934,36 @@ NdbDictionary::Table::getRowGCIIndicator
}
void
+NdbDictionary::Table::setExtraRowGciBits(Uint32 val)
+{
+ if (val <= 31)
+ {
+ m_impl.m_extra_row_gci_bits = val;
+ }
+}
+
+Uint32
+NdbDictionary::Table::getExtraRowGciBits() const
+{
+ return m_impl.m_extra_row_gci_bits;
+}
+
+void
+NdbDictionary::Table::setExtraRowAuthorBits(Uint32 val)
+{
+ if (val <= 31)
+ {
+ m_impl.m_extra_row_author_bits = val;
+ }
+}
+
+Uint32
+NdbDictionary::Table::getExtraRowAuthorBits() const
+{
+ return m_impl.m_extra_row_author_bits;
+}
+
+void
NdbDictionary::Table::setForceVarPart(bool val){
m_impl.m_force_var_part = val;
}
=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2011-05-12 09:40:20 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2011-05-17 23:37:03 +0000
@@ -378,6 +378,10 @@ NdbColumnImpl::create_pseudo_columns()
NdbColumnImpl::create_pseudo("NDB$ROWID");
NdbDictionary::Column::ROW_GCI=
NdbColumnImpl::create_pseudo("NDB$ROW_GCI");
+ NdbDictionary::Column::ROW_GCI64 =
+ NdbColumnImpl::create_pseudo("NDB$ROW_GCI64");
+ NdbDictionary::Column::ROW_AUTHOR =
+ NdbColumnImpl::create_pseudo("NDB$ROW_AUTHOR");
NdbDictionary::Column::ANY_VALUE=
NdbColumnImpl::create_pseudo("NDB$ANY_VALUE");
NdbDictionary::Column::COPY_ROWID=
@@ -408,6 +412,8 @@ NdbColumnImpl::destory_pseudo_columns()
delete NdbDictionary::Column::RECORDS_IN_RANGE;
delete NdbDictionary::Column::ROWID;
delete NdbDictionary::Column::ROW_GCI;
+ delete NdbDictionary::Column::ROW_GCI64;
+ delete NdbDictionary::Column::ROW_AUTHOR;
delete NdbDictionary::Column::ANY_VALUE;
delete NdbDictionary::Column::OPTIMIZE;
NdbDictionary::Column::FRAGMENT= 0;
@@ -421,6 +427,8 @@ NdbColumnImpl::destory_pseudo_columns()
NdbDictionary::Column::RECORDS_IN_RANGE= 0;
NdbDictionary::Column::ROWID= 0;
NdbDictionary::Column::ROW_GCI= 0;
+ NdbDictionary::Column::ROW_GCI64= 0;
+ NdbDictionary::Column::ROW_AUTHOR= 0;
NdbDictionary::Column::ANY_VALUE= 0;
NdbDictionary::Column::OPTIMIZE= 0;
@@ -499,6 +507,18 @@ NdbColumnImpl::create_pseudo(const char
col->m_impl.m_attrSize = 8;
col->m_impl.m_arraySize = 1;
col->m_impl.m_nullable = true;
+ } else if(!strcmp(name, "NDB$ROW_GCI64")){
+ col->setType(NdbDictionary::Column::Bigunsigned);
+ col->m_impl.m_attrId = AttributeHeader::ROW_GCI64;
+ col->m_impl.m_attrSize = 8;
+ col->m_impl.m_arraySize = 1;
+ col->m_impl.m_nullable = true;
+ } else if(!strcmp(name, "NDB$ROW_AUTHOR")){
+ col->setType(NdbDictionary::Column::Unsigned);
+ col->m_impl.m_attrId = AttributeHeader::ROW_AUTHOR;
+ col->m_impl.m_attrSize = 4;
+ col->m_impl.m_arraySize = 1;
+ col->m_impl.m_nullable = true;
} else if(!strcmp(name, "NDB$ANY_VALUE")){
col->setType(NdbDictionary::Column::Unsigned);
col->m_impl.m_attrId = AttributeHeader::ANY_VALUE;
@@ -638,6 +658,8 @@ NdbTableImpl::init(){
m_hash_map_id = RNIL;
m_hash_map_version = ~0;
m_storageType = NDB_STORAGETYPE_DEFAULT;
+ m_extra_row_gci_bits = 0;
+ m_extra_row_author_bits = 0;
}
bool
@@ -832,6 +854,22 @@ NdbTableImpl::equal(const NdbTableImpl&
DBUG_RETURN(false);
}
+ if (m_extra_row_gci_bits != obj.m_extra_row_gci_bits)
+ {
+ DBUG_PRINT("info",("m_extra_row_gci_bits %d != %d",
+ (int32)m_extra_row_gci_bits,
+ (int32)obj.m_extra_row_gci_bits));
+ DBUG_RETURN(false);
+ }
+
+ if (m_extra_row_author_bits != obj.m_extra_row_author_bits)
+ {
+ DBUG_PRINT("info",("m_extra_row_author_bits %d != %d",
+ (int32)m_extra_row_author_bits,
+ (int32)obj.m_extra_row_author_bits));
+ DBUG_RETURN(false);
+ }
+
DBUG_RETURN(true);
}
@@ -897,6 +935,8 @@ NdbTableImpl::assign(const NdbTableImpl&
m_fragmentCount = org.m_fragmentCount;
m_single_user_mode = org.m_single_user_mode;
+ m_extra_row_gci_bits = org.m_extra_row_gci_bits;
+ m_extra_row_author_bits = org.m_extra_row_author_bits;
if (m_index != 0)
delete m_index;
@@ -2751,6 +2791,8 @@ NdbDictInterface::parseTableInfo(NdbTabl
impl->m_maxLoadFactor = tableDesc->MaxLoadFactor;
impl->m_single_user_mode = tableDesc->SingleUserMode;
impl->m_storageType = tableDesc->TableStorageType;
+ impl->m_extra_row_gci_bits = tableDesc->ExtraRowGCIBits;
+ impl->m_extra_row_author_bits = tableDesc->ExtraRowAuthorBits;
impl->m_indexType = (NdbDictionary::Object::Type)
getApiConstant(tableDesc->TableType,
@@ -3346,7 +3388,9 @@ NdbDictInterface::compChangeMask(const N
impl.m_tablespace_version != old_impl.m_tablespace_version ||
impl.m_id != old_impl.m_id ||
impl.m_version != old_impl.m_version ||
- sz < old_sz)
+ sz < old_sz ||
+ impl.m_extra_row_gci_bits != old_impl.m_extra_row_gci_bits ||
+ impl.m_extra_row_author_bits != old_impl.m_extra_row_author_bits)
{
DBUG_PRINT("info", ("Old and new table not compatible"));
goto invalid_alter_table;
@@ -3534,6 +3578,8 @@ NdbDictInterface::serializeTableDesc(Ndb
tmpTab->LinearHashFlag = impl.m_linear_flag;
tmpTab->SingleUserMode = impl.m_single_user_mode;
tmpTab->ForceVarPartFlag = impl.m_force_var_part;
+ tmpTab->ExtraRowGCIBits = impl.m_extra_row_gci_bits;
+ tmpTab->ExtraRowAuthorBits = impl.m_extra_row_author_bits;
tmpTab->FragmentType = getKernelConstant(impl.m_fragmentType,
fragmentTypeMapping,
@@ -8425,6 +8471,8 @@ const NdbDictionary::Column * NdbDiction
const NdbDictionary::Column * NdbDictionary::Column::RECORDS_IN_RANGE = 0;
const NdbDictionary::Column * NdbDictionary::Column::ROWID = 0;
const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI = 0;
+const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI64 = 0;
+const NdbDictionary::Column * NdbDictionary::Column::ROW_AUTHOR = 0;
const NdbDictionary::Column * NdbDictionary::Column::ANY_VALUE = 0;
const NdbDictionary::Column * NdbDictionary::Column::COPY_ROWID = 0;
const NdbDictionary::Column * NdbDictionary::Column::OPTIMIZE = 0;
=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2011-05-12 09:40:20 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2011-05-17 23:37:03 +0000
@@ -238,6 +238,8 @@ public:
Uint16 m_fragmentCount;
Uint8 m_single_user_mode;
Uint8 m_storageType; // NDB_STORAGETYPE_MEMORY or _DISK or DEFAULT
+ Uint8 m_extra_row_gci_bits;
+ Uint8 m_extra_row_author_bits;
NdbIndexImpl * m_index;
NdbColumnImpl * getColumn(unsigned attrId);
=== modified file 'storage/ndb/test/ndbapi/testRestartGci.cpp'
--- a/storage/ndb/test/ndbapi/testRestartGci.cpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/test/ndbapi/testRestartGci.cpp 2011-05-17 23:29:55 +0000
@@ -28,10 +28,12 @@
*/
struct SavedRecord {
- int m_gci;
+ Uint64 m_gci;
+ Uint32 m_author;
BaseString m_str;
- SavedRecord(int _gci, BaseString _str){
+ SavedRecord(Uint64 _gci, Uint32 _author, BaseString _str){
m_gci = _gci;
+ m_author = _author;
m_str.assign(_str);
}
SavedRecord(){
@@ -40,7 +42,7 @@ struct SavedRecord {
};
};
Vector<SavedRecord> savedRecords;
-
+Uint64 highestExpectedGci;
#define CHECK(b) if (!(b)) { \
ndbout << "ERR: "<< step->getName() \
@@ -48,14 +50,80 @@ Vector<SavedRecord> savedRecords;
result = NDBT_FAILED; \
break; }
+static
+int
+maybeExtraBits(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
+{
+ switch(when){
+ case 0: // Before
+ break;
+ case 1: // After
+ return 0;
+ default:
+ return 0;
+ }
+
+ bool useExtendedBits = ((rand() % 5) != 0);
+ Uint32 numGciBits= rand() % 32; /* 0 -> 31 */
+ Uint32 numAuthorBits = rand() % 32; /* 0 -> 31 */
+
+ if (useExtendedBits && (numGciBits || numAuthorBits))
+ {
+ ndbout_c("Creating table %s with %u extra Gci and %u extra Author bits",
+ tab.getName(), numGciBits, numAuthorBits);
+ tab.setExtraRowGciBits(numGciBits);
+ tab.setExtraRowAuthorBits(numAuthorBits);
+ }
+ else
+ {
+ ndbout_c("Table has no extra bits");
+ }
+
+ return 0;
+}
+
+int runDropTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+ GETNDB(step)->getDictionary()->dropTable(ctx->getTab()->getName());
+ return NDBT_OK;
+}
+
+int runCreateTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+
+ runDropTable(ctx, step);
+
+ /* Use extra proc to control whether we have extra bits */
+ if (NDBT_Tables::createTable(GETNDB(step),
+ ctx->getTab()->getName(),
+ false, false,
+ maybeExtraBits) == NDBT_OK)
+ {
+ ctx->setTab(GETNDB(step)->
+ getDictionary()->
+ getTable(ctx->getTab()->getName()));
+ return NDBT_OK;
+ }
+ return NDBT_FAILED;
+}
+
int runInsertRememberGci(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
int records = ctx->getNumRecords();
HugoOperations hugoOps(*ctx->getTab());
+ HugoCalculator hugoCalc(*ctx->getTab());
Ndb* pNdb = GETNDB(step);
int i = 0;
- while(ctx->isTestStopped() == false && i < records){
+ ndbout_c("Inserting %u records", records);
+ Uint64 minGci = 0xffffffffffffffff;
+ Uint64 maxGci = 0;
+ Uint32 numAuthorBits = ctx->getTab()->getExtraRowAuthorBits();
+ Uint32 authorMask = (1 << numAuthorBits) -1;
+ ndbout_c("numAuthor bits is %u, mask is %x",
+ numAuthorBits, authorMask);
+
+ while(i < records){
// Insert record and read it in same transaction
CHECK(hugoOps.startTransaction(pNdb) == 0);
CHECK(hugoOps.pkInsertRecord(pNdb, i) == 0);
@@ -64,14 +132,50 @@ int runInsertRememberGci(NDBT_Context* c
result = NDBT_FAILED;
break;
}
+ /* Set the author column (if present) */
+ Uint32 authorVal = 0;
+ if (ctx->getTab()->getExtraRowAuthorBits() > 0)
+ {
+ authorVal = (rand() & authorMask);
+ /* Pain here due to need to use NdbRecord */
+ char rowBuff[NDB_MAX_TUPLE_SIZE];
+ const NdbDictionary::Table* tab = ctx->getTab();
+ CHECK(hugoCalc.setValues((Uint8*) rowBuff, tab->getDefaultRecord(),
+ i, 0) == 0);
+ NdbOperation::SetValueSpec setValueSpec;
+ setValueSpec.column = NdbDictionary::Column::ROW_AUTHOR;
+ setValueSpec.value = &authorVal;
+ NdbOperation::OperationOptions opts;
+ opts.optionsPresent= NdbOperation::OperationOptions::OO_SETVALUE;
+ opts.extraSetValues= &setValueSpec;
+ opts.numExtraSetValues = 1;
+
+ const NdbOperation* update = hugoOps.getTransaction()->
+ updateTuple(tab->getDefaultRecord(), rowBuff,
+ tab->getDefaultRecord(), rowBuff,
+ NULL, /* mask */
+ &opts,
+ sizeof(opts));
+ CHECK(update != NULL);
+ }
+ /* Read row back */
CHECK(hugoOps.pkReadRecord(pNdb, i) == 0);
if (hugoOps.execute_Commit(pNdb) != 0){
ndbout << "Did not find record in DB " << i << endl;
result = NDBT_FAILED;
break;
}
- savedRecords.push_back(SavedRecord(hugoOps.getRecordGci(0),
- hugoOps.getRecordStr(0)));
+ Uint64 gci;
+ CHECK(hugoOps.getTransaction()->getGCI(&gci) == 0);
+
+ if (gci < minGci)
+ minGci = gci;
+ if (gci > maxGci)
+ maxGci = gci;
+
+ savedRecords.push_back(SavedRecord(gci,
+ authorVal,
+ hugoOps.getRecordStr(0)));
CHECK(hugoOps.closeTransaction(pNdb) == 0);
i++;
@@ -79,13 +183,21 @@ int runInsertRememberGci(NDBT_Context* c
NdbSleep_MilliSleep(10);
};
+ ndbout_c(" Inserted records from gci %x/%x to gci %x/%x",
+ (Uint32) (minGci >> 32), (Uint32) (minGci & 0xffffffff),
+ (Uint32) (maxGci >> 32), (Uint32) (maxGci & 0xffffffff));
+
+ highestExpectedGci = maxGci;
+
return result;
}
-int runRestart(NDBT_Context* ctx, NDBT_Step* step){
+int runRestartAll(NDBT_Context* ctx, NDBT_Step* step){
Ndb* pNdb = GETNDB(step);
NdbRestarter restarter;
+ ndbout_c("Restart of all nodes");
+
// Restart cluster with abort
if (restarter.restartAll(false, false, true) != 0){
ctx->stopTest();
@@ -103,6 +215,42 @@ int runRestart(NDBT_Context* ctx, NDBT_S
return NDBT_OK;
}
+int runRestartOneInitial(NDBT_Context* ctx, NDBT_Step* step){
+ Ndb* pNdb = GETNDB(step);
+ NdbRestarter restarter;
+
+ if (restarter.getNumDbNodes() < 2)
+ return NDBT_OK;
+
+ /* We don't restart the Master as we need to know a
+ * non-restarted node to reliably get the restartGci
+ * afterwards!
+ * Should be no real reason not to restart the master.
+ */
+ int node = restarter.getRandomNotMasterNodeId(rand());
+ ndbout_c("Restarting node %u initial", node);
+
+ if (restarter.restartOneDbNode(node,
+ true, /* Initial */
+ false, /* Nostart */
+ true) /* Abort */
+ != 0)
+ {
+ ctx->stopTest();
+ return NDBT_FAILED;
+ }
+
+ if (restarter.waitClusterStarted(300) != 0){
+ return NDBT_FAILED;
+ }
+
+ if (pNdb->waitUntilReady() != 0){
+ return NDBT_FAILED;
+ }
+
+ return NDBT_OK;
+}
+
int runRestartGciControl(NDBT_Context* ctx, NDBT_Step* step){
int records = ctx->getNumRecords();
Ndb* pNdb = GETNDB(step);
@@ -118,10 +266,38 @@ int runRestartGciControl(NDBT_Context* c
NdbSleep_MilliSleep(10);
}
- // Stop the other thread
- ctx->stopTest();
+ return runRestartAll(ctx,step);
+}
+
+int runDetermineRestartGci(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* pNdb = GETNDB(step);
+ Uint32 restartGci;
+ int res = pNdb->getDictionary()->getRestartGCI(&restartGci);
+ if (res != 0)
+ {
+ ndbout << "Failed to retrieve restart gci" << endl;
+ ndbout << pNdb->getDictionary()->getNdbError() << endl;
+ return NDBT_FAILED;
+ }
+
+ ndbout_c("Restart GCI is %u (0x%x)",
+ restartGci, restartGci);
- return runRestart(ctx,step);
+ ndbout_c("Highest expected GCI was %x/%x",
+ (Uint32) (highestExpectedGci >> 32),
+ (Uint32) (highestExpectedGci & 0xffffffff));
+
+ highestExpectedGci = ((Uint64) restartGci) << 32 | 0xffffffff;
+ ndbout_c("Resetting Highest expected GCI to align with restart Gci (%x/%x)",
+ (Uint32) (highestExpectedGci >> 32),
+ (Uint32) (highestExpectedGci & 0xffffffff));
+ return NDBT_OK;
+}
+
+int runRequireExact(NDBT_Context* ctx, NDBT_Step* step){
+ ctx->incProperty("ExactGCI");
+ return NDBT_OK;
}
int runVerifyInserts(NDBT_Context* ctx, NDBT_Step* step){
@@ -130,17 +306,9 @@ int runVerifyInserts(NDBT_Context* ctx,
UtilTransactions utilTrans(*ctx->getTab());
HugoOperations hugoOps(*ctx->getTab());
NdbRestarter restarter;
+ Uint32 extraGciBits = ctx->getTab()->getExtraRowGciBits();
+ Uint32 firstSaturatedValue = (1 << extraGciBits) -1;
- Uint32 restartGCI;
- int res = pNdb->getDictionary()->getRestartGCI(&restartGCI);
- if (res != 0)
- {
- ndbout << "Failed to retreive restart gci" << endl;
- ndbout << pNdb->getDictionary()->getNdbError() << endl;
- return NDBT_FAILED;
- }
-
- ndbout << "restartGCI = " << restartGCI << endl;
int count = 0;
if (utilTrans.selectCount(pNdb, 64, &count) != 0){
return NDBT_FAILED;
@@ -151,7 +319,7 @@ int runVerifyInserts(NDBT_Context* ctx,
int recordsWithLowerOrSameGci = 0;
unsigned i;
for (i = 0; i < savedRecords.size(); i++){
- if (savedRecords[i].m_gci <= (int)restartGCI)
+ if (savedRecords[i].m_gci <= highestExpectedGci)
recordsWithLowerOrSameGci++;
}
if (recordsWithLowerOrSameGci != count){
@@ -159,10 +327,13 @@ int runVerifyInserts(NDBT_Context* ctx,
result = NDBT_FAILED;
}
+ bool exactGCIonly = ctx->getProperty("ExactGCI", (unsigned) 0);
// RULE2: The records found in db should have same or lower
// gci as in the vector
int recordsWithIncorrectGci = 0;
+ int recordsWithRoundedGci = 0;
+ int recordsWithIncorrectAuthor = 0;
for (i = 0; i < savedRecords.size(); i++){
CHECK(hugoOps.startTransaction(pNdb) == 0);
/* First read of row to check contents */
@@ -173,13 +344,15 @@ int runVerifyInserts(NDBT_Context* ctx,
CHECK(readOp != NULL);
CHECK(readOp->readTuple() == 0);
CHECK(hugoOps.equalForRow(readOp, i) == 0);
- NdbRecAttr* rowGci = readOp->getValue(NdbDictionary::Column::ROW_GCI);
+ NdbRecAttr* rowGci = readOp->getValue(NdbDictionary::Column::ROW_GCI64);
+ NdbRecAttr* rowAuthor = readOp->getValue(NdbDictionary::Column::ROW_AUTHOR);
CHECK(rowGci != NULL);
+ CHECK(rowAuthor != NULL);
if (hugoOps.execute_Commit(pNdb) != 0){
// Record was not found in db'
// Check record gci
- if (savedRecords[i].m_gci <= (int)restartGCI){
+ if (savedRecords[i].m_gci <= highestExpectedGci) {
ndbout << "ERR: Record "<<i<<" should have existed" << endl;
result = NDBT_FAILED;
}
@@ -189,7 +362,7 @@ int runVerifyInserts(NDBT_Context* ctx,
* Let's disappear it, so that it doesn't cause confusion
* after further restarts.
*/
- savedRecords[i].m_gci = (Uint32(1) << 31) -1; // Big number
+ savedRecords[i].m_gci = (Uint64(1) << 63) -1; // Big number
}
} else {
// Record was found in db
@@ -200,16 +373,50 @@ int runVerifyInserts(NDBT_Context* ctx,
result = NDBT_FAILED;
}
// Check record gci in range
- if (savedRecords[i].m_gci > (int)restartGCI){
+ Uint64 expectedRecordGci = savedRecords[i].m_gci;
+ if (expectedRecordGci > highestExpectedGci){
ndbout << "ERR: Record "<<i<<" should not have existed" << endl;
result = NDBT_FAILED;
}
+ bool expectRounding = (expectedRecordGci && 0xffffffff) >= firstSaturatedValue;
+ Uint64 expectedRoundedGci = (expectedRecordGci | 0xffffffff);
+ Uint64 readGci = rowGci->u_64_value();
+ Uint64 expectedRead = (expectRounding)?expectedRoundedGci :
+ expectedRecordGci;
// Check record gci is exactly correct
- if (savedRecords[i].m_gci != rowGci->int32_value()){
- ndbout << "ERR: Record "<<i<<" should have GCI " <<
- savedRecords[i].m_gci << ", but has " <<
- rowGci->int32_value() << endl;
- recordsWithIncorrectGci++;
+ if (expectedRead != readGci){
+ if ((!exactGCIonly) &&
+ (expectedRoundedGci == readGci))
+ {
+ /* Record rounded, though bits can be represented
+ * presumably due to Redo gci truncation
+ */
+ recordsWithRoundedGci++;
+ }
+ else
+ {
+ ndbout_c("ERR: Record %u should have GCI %x/%x, but has "
+ "%x/%x.",
+ i,
+ (Uint32) (expectedRead >> 32),
+ (Uint32) (expectedRead & 0xffffffff),
+ (Uint32) (readGci >> 32),
+ (Uint32) (readGci & 0xffffffff));
+ recordsWithIncorrectGci++;
+ result = NDBT_FAILED;
+ }
+ }
+
+ // Check author value is correct.
+ Uint32 expectedAuthor = savedRecords[i].m_author;
+
+ if (rowAuthor->u_32_value() != expectedAuthor)
+ {
+ ndbout_c("ERR: Record %u should have Author %d, but has %d.",
+ i,
+ expectedAuthor,
+ rowAuthor->u_32_value());
+ recordsWithIncorrectAuthor++;
result = NDBT_FAILED;
}
}
@@ -222,17 +429,26 @@ int runVerifyInserts(NDBT_Context* ctx,
ndbout << "There are " << savedRecords.size()
<< " records in vector" << endl;
- ndbout << "There are " << recordsWithLowerOrSameGci
- << " records with lower or same gci than " << restartGCI << endl;
+ ndbout_c("There are %u records with lower or same gci than %x/%x",
+ recordsWithLowerOrSameGci,
+ (Uint32)(highestExpectedGci >> 32),
+ (Uint32)(highestExpectedGci & 0xffffffff));
+ ndbout_c("There are %u records with rounded Gcis. Exact GCI flag is %u",
+ recordsWithRoundedGci, exactGCIonly);
+
ndbout << "There are " << recordsWithIncorrectGci
<< " records with incorrect Gci on recovery." << endl;
+ ndbout << "There are " << recordsWithIncorrectAuthor
+ << " records with incorrect Author on recovery." << endl;
+
return result;
}
int runClearGlobals(NDBT_Context* ctx, NDBT_Step* step){
savedRecords.clear();
+ highestExpectedGci = 0;
return NDBT_OK;
}
@@ -247,27 +463,276 @@ int runClearTable(NDBT_Context* ctx, NDB
}
+int runLoadTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int records = ctx->getNumRecords();
+ HugoTransactions hugoTrans(*ctx->getTab());
+ if (hugoTrans.loadTable(GETNDB(step), records, 512, false, 0, true) != 0){
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+int runNodeInitialRestarts(NDBT_Context* ctx, NDBT_Step* step)
+{
+ NdbRestarter restarter;
+ const Uint32 numRestarts = 4;
+ for (Uint32 nr = 0; nr < numRestarts; nr++)
+ {
+ if (ctx->isTestStopped())
+ {
+ return NDBT_OK;
+ }
+ int nodeId = restarter.getNode(NdbRestarter::NS_RANDOM);
+ ndbout_c("Restarting node %u", nodeId);
+
+ if (restarter.restartOneDbNode(nodeId, NdbRestarter::NRRF_INITIAL) != 0)
+ {
+ ndbout_c("Error restarting node");
+ ctx->stopTest();
+ return NDBT_FAILED;
+ }
+
+ if (restarter.waitClusterStarted(300) != 0)
+ {
+ ctx->stopTest();
+ return NDBT_FAILED;
+ }
+
+ if (GETNDB(step)->waitUntilReady() != 0)
+ {
+ ctx->stopTest();
+ return NDBT_FAILED;
+ }
+ }
+
+ ctx->stopTest();
+
+ return NDBT_OK;
+}
+
+int runUpdateVerifyGCI(NDBT_Context* ctx, NDBT_Step* step)
+{
+ HugoOperations hugoOps(*ctx->getTab());
+ HugoCalculator hugoCalc(*ctx->getTab());
+ Ndb* pNdb = GETNDB(step);
+
+ /* Loop, updating the first record in the table, and checking
+ * that it has the GCI it should
+ */
+ Uint64 loopCount = 0;
+ Uint64 distinctCount = 0;
+ Uint64 expectedGCI = 0;
+ Uint64 lastGoodReadGCI = 0;
+ Uint32 extraGciBits = ctx->getTab()->getExtraRowGciBits();
+ Uint32 firstSaturatedValue = (1 << extraGciBits) -1;
+ ndbout_c("Extra GCI bits : %u, firstSaturatedValue : %u",
+ extraGciBits,
+ firstSaturatedValue);
+ int result = NDBT_OK;
+ while (!ctx->isTestStopped())
+ {
+ CHECK(hugoOps.startTransaction(pNdb) == 0);
+ /* Define a read op to get the 'existing' GCI */
+ NdbTransaction* trans = hugoOps.getTransaction();
+ CHECK(hugoOps.pkReadRecord(pNdb,
+ 0,
+ 1) == 0);
+ NdbOperation* readOp = trans->getNdbOperation(ctx->getTab());
+ CHECK(readOp != NULL);
+ CHECK(readOp->readTuple() == 0);
+ CHECK(hugoOps.equalForRow(readOp, 0) == 0);
+ NdbRecAttr* rowGci = readOp->getValue(NdbDictionary::Column::ROW_GCI64);
+ CHECK(rowGci != NULL);
+
+ /* Define an update op to set the next GCI */
+ CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, loopCount+1) == 0);
+
+ if (hugoOps.execute_Commit(pNdb) != 0)
+ {
+ if (hugoOps.getNdbError().classification ==
+ NdbError::NodeRecoveryError)
+ {
+ hugoOps.closeTransaction(pNdb);
+ ndbout_c("Temporary error at loopCount %llu", loopCount);
+ continue;
+ }
+
+ ndbout << "Error executing : " << hugoOps.getNdbError() << endl;
+ return NDBT_FAILED;
+ }
+
+ /* First check the data is as expected */
+ CHECK(hugoCalc.verifyRowValues(&hugoOps.get_row(0)) == 0);
+ CHECK(hugoCalc.getUpdatesValue(&hugoOps.get_row(0)) == loopCount);
+ //ndbout_c("Updates value is %u", hugoCalc.getUpdatesValue(&hugoOps.get_row(0)));
+
+ Uint64 committedGCI;
+ CHECK(trans->getGCI(&committedGCI) == 0);
+ Uint32 gci_lo = Uint32(committedGCI & 0xffffffff);
+
+ Uint64 saturatedCommittedGCI = (gci_lo >= firstSaturatedValue) ?
+ committedGCI | 0xffffffff : committedGCI;
+ Uint64 rowGCI64 = rowGci->u_64_value();
+
+// ndbout_c("Read row GCI64 %x/%x. Committed GCI64 : %x/%x. Saturated GCI64 :%x/%x Last good read : %x/%x",
+// Uint32(rowGCI64 >> 32),
+// Uint32(rowGCI64 & 0xffffffff),
+// Uint32(committedGCI >> 32),
+// Uint32(committedGCI & 0xffffffff),
+// Uint32(saturatedCommittedGCI >> 32),
+// Uint32(saturatedCommittedGCI & 0xffffffff),
+// Uint32(lastGoodReadGCI >> 32),
+// Uint32(lastGoodReadGCI & 0xffffffff));
+
+
+ if (rowGCI64 < lastGoodReadGCI)
+ {
+ ndbout_c("ERROR : Read row GCI value (%x/%x) lower than previous value (%x/%x)",
+ (Uint32) (rowGCI64 >> 32),
+ (Uint32) (rowGCI64 & 0xffffffff),
+ Uint32(lastGoodReadGCI >> 32),
+ Uint32(lastGoodReadGCI & 0xffffffff));
+ }
+ /* We certainly should not read a committed GCI value that's
+ * bigger than the read's commit-point GCI
+ */
+ if (saturatedCommittedGCI < rowGCI64)
+ {
+ ndbout_c("ERROR : Saturated committed GCI (%x/%x) lower than actual read GCI (%x/%x)",
+ Uint32(saturatedCommittedGCI >>32),
+ Uint32(saturatedCommittedGCI & 0xffffffff),
+ (Uint32) (rowGCI64 >> 32),
+ (Uint32) (rowGCI64 & 0xffffffff));
+ }
+ /* If we've read a committed GCI then we should certainly not
+ * be committing at lower values
+ */
+ if (saturatedCommittedGCI < lastGoodReadGCI)
+ {
+ ndbout_c("ERROR : Saturated committed GCI (%x/%x) lower than a previously"
+ "read GCI (%x/%x)",
+ Uint32(saturatedCommittedGCI >>32),
+ Uint32(saturatedCommittedGCI & 0xffffffff),
+ Uint32(lastGoodReadGCI >> 32),
+ Uint32(lastGoodReadGCI & 0xffffffff));
+ };
+ /* If we've previously had a particular committed GCI then we
+ * should certainly not now have a lower committed GCI
+ */
+ if (saturatedCommittedGCI < expectedGCI)
+ {
+ ndbout_c("ERROR : Saturated committed GCI (%x/%x) lower than expected GCI"
+ " (%x/%x)",
+ Uint32(saturatedCommittedGCI >>32),
+ Uint32(saturatedCommittedGCI & 0xffffffff),
+ Uint32(expectedGCI >> 32),
+ Uint32(expectedGCI & 0xffffffff));
+ }
+
+ if (loopCount > 0)
+ {
+ if (rowGCI64 != expectedGCI)
+ {
+ ndbout_c("MISMATCH : Expected GCI of %x/%x, but found %x/%x",
+ (Uint32) (expectedGCI >> 32),
+ (Uint32) (expectedGCI & 0xffffffff),
+ (Uint32) (rowGCI64 >> 32),
+ (Uint32) (rowGCI64 & 0xffffffff));
+ ndbout_c("At loopcount %llu", loopCount);
+ ndbout_c("Last good read GCI %x/%x",
+ Uint32(lastGoodReadGCI >> 32),
+ Uint32(lastGoodReadGCI & 0xffffffff));
+ ndbout_c("Read committed GCI : %x/%x",
+ Uint32(saturatedCommittedGCI >>32),
+ Uint32(saturatedCommittedGCI & 0xffffffff));
+ ndbout_c("Transaction coordinator node : %u",
+ trans->getConnectedNodeId());
+ return NDBT_FAILED;
+ }
+
+ if (saturatedCommittedGCI != expectedGCI)
+ {
+ distinctCount++;
+ }
+ }
+
+ expectedGCI = saturatedCommittedGCI;
+ lastGoodReadGCI = rowGCI64;
+
+ hugoOps.closeTransaction(pNdb);
+ loopCount++;
+
+ /* Sleep to avoid excessive updating */
+ NdbSleep_MilliSleep(10);
+ }
+
+ ndbout_c("%llu updates with %llu distinct GCI values",
+ loopCount,
+ distinctCount);
+
+ return result;
+}
+
NDBT_TESTSUITE(testRestartGci);
TESTCASE("InsertRestartGci",
"Verify that only expected records are still in NDB\n"
"after a restart" ){
- INITIALIZER(runClearTable);
+ INITIALIZER(runCreateTable);
INITIALIZER(runClearGlobals);
- STEP(runInsertRememberGci);
- STEP(runRestartGciControl);
+ INITIALIZER(runInsertRememberGci);
+ INITIALIZER(runRestartGciControl);
+ INITIALIZER(runDetermineRestartGci);
+ TC_PROPERTY("ExactGCI", Uint32(0)); /* Recovery from Redo == inexact low word */
VERIFIER(runVerifyInserts);
/* Restart again - LCP after first restart will mean that this
* time we recover from LCP, not Redo
*/
- VERIFIER(runRestart);
+ VERIFIER(runRestartAll);
+ VERIFIER(runDetermineRestartGci);
+ VERIFIER(runVerifyInserts); // Check GCIs again
+ /* Restart again - one node, initial. This will check
+ * COPYFRAG behaviour
+ */
+ VERIFIER(runRestartOneInitial);
VERIFIER(runVerifyInserts); // Check GCIs again
+ VERIFIER(runClearTable);
+ /* Re-fill table with records, will just be in Redo
+ * Then restart, testing COPYFRAG behaviour with
+ * non #ffff... low word
+ */
+ VERIFIER(runClearGlobals);
+ VERIFIER(runInsertRememberGci);
+ VERIFIER(runRestartOneInitial);
+ /* Require exact GCI match from here - no Redo messing it up */
+ VERIFIER(runRequireExact);
+ VERIFIER(runVerifyInserts);
+ /* Now-restart all nodes - all inserts should be
+ * in LCP, and should be restored correctly
+ */
+ VERIFIER(runRestartAll);
+ VERIFIER(runDetermineRestartGci);
+ VERIFIER(runVerifyInserts);
+ FINALIZER(runClearTable);
+ FINALIZER(runDropTable);
+}
+TESTCASE("InitialNodeRestartUpdate",
+ "Check that initial node restart (copyfrag) does "
+ "not affect GCI recording")
+{
+ INITIALIZER(runCreateTable);
+ INITIALIZER(runLoadTable);
+ STEP(runNodeInitialRestarts);
+ STEP(runUpdateVerifyGCI);
FINALIZER(runClearTable);
+ FINALIZER(runDropTable);
}
NDBT_TESTSUITE_END(testRestartGci);
int main(int argc, const char** argv){
ndb_init();
NDBT_TESTSUITE_INSTANCE(testRestartGci);
+ testRestartGci.setCreateTable(false);
return testRestartGci.execute(argc, argv);
}
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2011-05-07 06:17:02 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2011-05-17 23:29:55 +0000
@@ -930,9 +930,9 @@ max-time: 7200
cmd: testTransactions
args:
-max-time: 1500
+max-time: 3000
cmd: testRestartGci
-args: T6
+args: T6 D1
max-time: 1500
cmd: testBlobs
=== modified file 'storage/ndb/test/src/NDBT_Table.cpp'
--- a/storage/ndb/test/src/NDBT_Table.cpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/test/src/NDBT_Table.cpp 2011-05-17 23:29:55 +0000
@@ -39,6 +39,8 @@ operator <<(class NdbOut& ndbout, const
ndbout << "SingleUserMode: " << (Uint32) tab.getSingleUserMode() << endl;
ndbout << "ForceVarPart: " << tab.getForceVarPart() << endl;
ndbout << "FragmentCount: " << tab.getFragmentCount() << endl;
+ ndbout << "ExtraRowGciBits: " << tab.getExtraRowGciBits() << endl;
+ ndbout << "ExtraRowAuthorBits: " << tab.getExtraRowAuthorBits() << endl;
//<< ((tab.getTupleKey() == TupleId) ? " tupleid" : "") <<endl;
ndbout << "TableStatus: ";
=== modified file 'storage/ndb/tools/select_all.cpp'
--- a/storage/ndb/tools/select_all.cpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/tools/select_all.cpp 2011-05-17 23:29:55 +0000
@@ -49,6 +49,8 @@ static int _dumpDisk = 0;
static int use_rowid = 0;
static int nodata = 0;
static int use_gci = 0;
+static int use_gci64 = 0;
+static int use_author = 0;
static struct my_option my_long_options[] =
{
@@ -86,6 +88,12 @@ static struct my_option my_long_options[
{ "gci", NDB_OPT_NOSHORT, "Dump gci",
(uchar**) &use_gci, (uchar**) &use_gci, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "gci64", NDB_OPT_NOSHORT, "Dump ROW$GCI64",
+ (uchar**) &use_gci64, (uchar**) &use_gci64, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "author", NDB_OPT_NOSHORT, "Dump ROW$AUTHOR",
+ (uchar**) &use_author, (uchar**) &use_author, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "tupscan", 't', "Scan in tup order",
(uchar**) &_tup, (uchar**) &_tup, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
@@ -328,7 +336,7 @@ int scanReadRecords(Ndb* pNdb,
if(_dumpDisk && disk)
disk_ref = pOp->getValue(NdbDictionary::Column::DISK_REF);
- NdbRecAttr * rowid= 0, *frag = 0, *gci = 0;
+ NdbRecAttr * rowid= 0, *frag = 0, *gci = 0, *gci64 = 0, *author = 0;
if (use_rowid)
{
frag = pOp->getValue(NdbDictionary::Column::FRAGMENT);
@@ -339,7 +347,17 @@ int scanReadRecords(Ndb* pNdb,
{
gci = pOp->getValue(NdbDictionary::Column::ROW_GCI);
}
+
+ if (use_gci64)
+ {
+ gci64 = pOp->getValue(NdbDictionary::Column::ROW_GCI64);
+ }
+ if (use_author)
+ {
+ author = pOp->getValue(NdbDictionary::Column::ROW_AUTHOR);
+ }
+
check = pTrans->execute(NdbTransaction::NoCommit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -386,6 +404,18 @@ int scanReadRecords(Ndb* pNdb,
ndbout << "DISK_REF";
}
+ if (gci64)
+ {
+ DELIMITER;
+ ndbout << "ROW$GCI64";
+ }
+
+ if (author)
+ {
+ DELIMITER;
+ ndbout << "ROW$AUTHOR";
+ }
+
ndbout << endl;
}
#undef DELIMITER
@@ -426,8 +456,30 @@ int scanReadRecords(Ndb* pNdb,
<< " m_page: " << disk_ref->u_32_value()
<< " m_page_idx: " << *(Uint16*)(disk_ref->aRef() + 4) << " ]";
}
+
+ if (gci64)
+ {
+ if (gci64->isNULL())
+ ndbout << "\tNULL";
+ else
+ {
+ Uint64 tmp = gci64->u_64_value();
+ ndbout << "\t" << Uint32(tmp >> 32) << "/" << Uint32(tmp);
+ }
+ }
+
+ if (author)
+ {
+ if (author->isNULL())
+ ndbout << "\tNULL";
+ else
+ {
+ ndbout << "\t" << author->u_32_value();
+ }
+ }
+
- if (rowid || disk_ref || gci || !nodata)
+ if (rowid || disk_ref || gci || !nodata || gci64 || author)
ndbout << endl;
eof = pOp->nextResult();
}
No bundle (reason: revision is a merge (you can force generation of a bundle with env var BZR_FORCE_BUNDLE=1)).
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.1 branch (frazer.clement:4205) | Frazer Clement | 19 May |