From: Frazer Clement Date: May 17 2011 11:39pm Subject: bzr push into mysql-5.1-telco-7.1 branch (frazer.clement:4204 to 4205) List-Archive: http://lists.mysql.com/commits/137563 Message-Id: <201105172339.p4HNdBPI025769@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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 4204 Craig L Russell 2011-05-17 Update clusterj DeleteAllByClassTest to ignore existing instances modified: storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/DeleteAllByClassTest.java === 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 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 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 c_triggerPool; (disk && m_attributes[DD].m_no_of_varsize > 0); } + template 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(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(); + 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(); + 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(); + + 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(); + + 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(); + + 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 #include "AttributeOffset.hpp" #include +#include 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(); + + 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(); + 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(); + 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(); + + 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 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 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 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 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 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 savedRecords; - +Uint64 highestExpectedGci; #define CHECK(b) if (!(b)) { \ ndbout << "ERR: "<< step->getName() \ @@ -48,14 +50,80 @@ Vector 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 "< (int)restartGCI){ + Uint64 expectedRecordGci = savedRecords[i].m_gci; + if (expectedRecordGci > highestExpectedGci){ ndbout << "ERR: Record "<= 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 "<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" : "") <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: useless for push emails).