4428 Jonas Oreland 2011-05-31 [merge]
ndb - wl4124 - kernel part
added:
storage/ndb/include/kernel/signaldata/IndexStatSignal.hpp
storage/ndb/src/common/debugger/signaldata/IndexStatSignal.cpp
modified:
storage/ndb/include/kernel/AttributeHeader.hpp
storage/ndb/include/kernel/GlobalSignalNumbers.h
storage/ndb/include/kernel/ndb_limits.h
storage/ndb/include/kernel/signaldata/AccScan.hpp
storage/ndb/include/kernel/signaldata/ScanFrag.hpp
storage/ndb/include/kernel/signaldata/SignalData.hpp
storage/ndb/include/kernel/signaldata/SumaImpl.hpp
storage/ndb/include/kernel/signaldata/TuxBound.hpp
storage/ndb/include/kernel/signaldata/TuxContinueB.hpp
storage/ndb/include/kernel/signaldata/UtilRelease.hpp
storage/ndb/include/mgmapi/mgmapi_config_parameters.h
storage/ndb/include/ndb_constants.h
storage/ndb/src/common/debugger/signaldata/CMakeLists.txt
storage/ndb/src/common/debugger/signaldata/Makefile.am
storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp
storage/ndb/src/common/debugger/signaldata/SchemaTransImpl.cpp
storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
storage/ndb/src/kernel/blocks/ERROR_codes.txt
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxBuild.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.hpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
storage/ndb/src/kernel/blocks/suma/Suma.cpp
storage/ndb/src/kernel/blocks/suma/Suma.hpp
storage/ndb/src/kernel/blocks/trix/Trix.cpp
storage/ndb/src/kernel/blocks/trix/Trix.hpp
storage/ndb/src/mgmsrv/ConfigInfo.cpp
storage/ndb/src/ndbapi/ndberror.c
storage/ndb/tools/restore/Restore.cpp
4427 Jonas Oreland 2011-05-30
ndb - kill warnings for gcc 4.4.3
modified:
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp
storage/ndb/src/kernel/blocks/suma/Suma.cpp
=== modified file 'storage/ndb/include/kernel/AttributeHeader.hpp'
--- a/storage/ndb/include/kernel/AttributeHeader.hpp 2011-05-17 23:29:55 +0000
+++ b/storage/ndb/include/kernel/AttributeHeader.hpp 2011-05-25 15:03:11 +0000
@@ -84,6 +84,10 @@ public:
STATIC_CONST( OPTIMIZE_MOVE_VARPART = 0x0001 ); //option to move varpart
STATIC_CONST( OPTIMIZE_MOVE_FIXPART = 0x0002 ); //option to move fixpart
+ // index stats pseudo columns
+ STATIC_CONST( INDEX_STAT_KEY = 0xFFD0 );
+ STATIC_CONST( INDEX_STAT_VALUE = 0xFFD1 );
+
// NOTE: in 5.1 ctors and init take size in bytes
/** Initialize AttributeHeader at location aHeaderPtr */
=== modified file 'storage/ndb/include/kernel/GlobalSignalNumbers.h'
--- a/storage/ndb/include/kernel/GlobalSignalNumbers.h 2011-04-28 07:47:53 +0000
+++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h 2011-05-19 09:16:32 +0000
@@ -866,15 +866,6 @@ extern const GlobalSignalNumber NO_OF_SI
#define GSN_648
#define GSN_649
-#define GSN_650
-#define GSN_651
-#define GSN_652
-#define GSN_653
-#define GSN_654
-#define GSN_655
-
-#define GSN_656
-
#define GSN_UTIL_CREATE_LOCK_REQ 132
#define GSN_UTIL_CREATE_LOCK_REF 133
#define GSN_UTIL_CREATE_LOCK_CONF 188
@@ -1079,4 +1070,12 @@ extern const GlobalSignalNumber NO_OF_SI
#define GSN_RELEASE_PAGES_REQ 680
#define GSN_RELEASE_PAGES_CONF 681
+#define GSN_INDEX_STAT_REQ 650
+#define GSN_INDEX_STAT_CONF 651
+#define GSN_INDEX_STAT_REF 652
+#define GSN_INDEX_STAT_IMPL_REQ 653
+#define GSN_INDEX_STAT_IMPL_CONF 654
+#define GSN_INDEX_STAT_IMPL_REF 655
+#define GSN_INDEX_STAT_REP 656
+
#endif
=== modified file 'storage/ndb/include/kernel/ndb_limits.h'
--- a/storage/ndb/include/kernel/ndb_limits.h 2011-05-26 11:49:47 +0000
+++ b/storage/ndb/include/kernel/ndb_limits.h 2011-05-29 10:55:32 +0000
@@ -219,4 +219,19 @@
*/
#define NDB_SPJ_MAX_TREE_NODES 32
+/*
+ * Stored ordered index stats uses 2 Longvarbinary pseudo-columns: the
+ * packed index keys and the packed values. Key size is limited by
+ * SAMPLES table which has 3 other PK attributes. Also length bytes is
+ * counted as 1 word. Values currently contain RIR (one word) and RPK
+ * (one word for each key level). The SAMPLEs table STAT_VALUE column
+ * is longer to allow future changes.
+ */
+#define MAX_INDEX_STAT_KEY_COUNT MAX_ATTRIBUTES_IN_INDEX
+#define MAX_INDEX_STAT_KEY_SIZE (MAX_KEY_SIZE_IN_WORDS - 3 - 1)
+#define MAX_INDEX_STAT_VALUE_COUNT (1 + MAX_INDEX_STAT_KEY_COUNT)
+#define MAX_INDEX_STAT_VALUE_SIZE MAX_INDEX_STAT_VALUE_COUNT
+#define MAX_INDEX_STAT_VALUE_CSIZE 512 /* Longvarbinary(2048) */
+#define MAX_INDEX_STAT_VALUE_FORMAT 1
+
#endif
=== modified file 'storage/ndb/include/kernel/signaldata/AccScan.hpp'
--- a/storage/ndb/include/kernel/signaldata/AccScan.hpp 2011-02-01 21:05:11 +0000
+++ b/storage/ndb/include/kernel/signaldata/AccScan.hpp 2011-05-19 09:16:32 +0000
@@ -72,6 +72,9 @@ private:
static Uint32 getLcpScanFlag(const Uint32 & requestInfo);
static void setLcpScanFlag(Uint32 & requestInfo, Uint32 nr);
+
+ static Uint32 getStatScanFlag(const Uint32 & requestInfo);
+ static void setStatScanFlag(Uint32 & requestInfo, Uint32 nr);
};
/**
@@ -83,10 +86,11 @@ private:
* d = No disk scan - 1 Bit 7
* n = Node recovery scan - 1 Bit 8
* c = LCP scan - 1 Bit 9
+ * s = Statistics scan - 1 Bit 4
*
* 1111111111222222222233
* 01234567890123456789012345678901
- * l hzdn
+ * l shzdn
*/
#define AS_LOCK_MODE_SHIFT (2)
#define AS_LOCK_MODE_MASK (1)
@@ -95,6 +99,7 @@ private:
#define AS_NO_DISK_SCAN (7)
#define AS_NR_SCAN (8)
#define AS_LCP_SCAN (9)
+#define AS_STAT_SCAN (4)
inline
Uint32
@@ -174,6 +179,19 @@ AccScanReq::setLcpScanFlag(UintR & reque
requestInfo |= (val << AS_LCP_SCAN);
}
+inline
+Uint32
+AccScanReq::getStatScanFlag(const Uint32 & requestInfo){
+ return (requestInfo >> AS_STAT_SCAN) & 1;
+}
+
+inline
+void
+AccScanReq::setStatScanFlag(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "AccScanReq::setStatScanScanFlag");
+ requestInfo |= (val << AS_STAT_SCAN);
+}
+
class AccScanConf {
/**
* Sender(s)
@@ -212,7 +230,9 @@ class AccScanRef {
enum ErrorCode {
TuxNoFreeScanOp = 909,
- TuxIndexNotOnline = 910
+ TuxIndexNotOnline = 910,
+ TuxNoFreeStatOp = 911,
+ TuxInvalidLockMode = 912
};
public:
=== added file 'storage/ndb/include/kernel/signaldata/IndexStatSignal.hpp'
--- a/storage/ndb/include/kernel/signaldata/IndexStatSignal.hpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/include/kernel/signaldata/IndexStatSignal.hpp 2011-05-19 09:16:32 +0000
@@ -0,0 +1,121 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef INDEX_STAT_SIGNAL_DATA_HPP
+#define INDEX_STAT_SIGNAL_DATA_HPP
+
+#include "SignalData.hpp"
+
+struct IndexStatReq {
+ enum RequestType {
+ // update
+ RT_UPDATE_STAT = 1,
+ RT_CLEAN_NEW = 2,
+ RT_SCAN_FRAG = 3,
+ RT_CLEAN_OLD = 4,
+ RT_START_MON = 5,
+ // delete
+ RT_DELETE_STAT = 6,
+ RT_STOP_MON = 7,
+ RT_DROP_HEAD = 8,
+ RT_CLEAN_ALL = 9
+ };
+ STATIC_CONST( SignalLength = 9 );
+ Uint32 clientRef;
+ Uint32 clientData;
+ Uint32 transId;
+ Uint32 transKey;
+ Uint32 requestInfo;
+ Uint32 requestFlag;
+ Uint32 indexId;
+ Uint32 indexVersion;
+ Uint32 tableId;
+};
+
+struct IndexStatImplReq {
+ STATIC_CONST( SignalLength = 10 );
+ Uint32 senderRef;
+ Uint32 senderData;
+ Uint32 transId;
+ Uint32 requestType;
+ Uint32 requestFlag;
+ Uint32 indexId;
+ Uint32 indexVersion;
+ Uint32 tableId;
+ Uint32 fragId;
+ Uint32 fragCount;
+};
+
+struct IndexStatConf {
+ STATIC_CONST( SignalLength = 3 );
+ Uint32 senderRef;
+ union { Uint32 senderData; Uint32 clientData; };
+ Uint32 transId;
+};
+
+struct IndexStatImplConf {
+ STATIC_CONST( SignalLength = 2 );
+ Uint32 senderRef;
+ Uint32 senderData;
+};
+
+struct IndexStatRef {
+ enum ErrorCode {
+ Busy = 701,
+ NotMaster = 702,
+ InvalidIndex = 913,
+ InvalidRequest = 914,
+ NoFreeStatOp = 915,
+ InvalidSysTable = 916,
+ InvalidSysTableData = 917,
+ BusyUtilPrepare = 918,
+ BusyUtilExecute = 919
+ };
+ STATIC_CONST( SignalLength = 7 );
+ Uint32 senderRef;
+ union { Uint32 senderData; Uint32 clientData; };
+ Uint32 transId;
+ Uint32 errorCode;
+ Uint32 errorLine;
+ Uint32 errorNodeId;
+ Uint32 masterNodeId;
+};
+
+struct IndexStatImplRef {
+ STATIC_CONST( SignalLength = 4 );
+ Uint32 senderRef;
+ Uint32 senderData;
+ Uint32 errorCode;
+ Uint32 errorLine;
+};
+
+struct IndexStatRep {
+ enum RequestType {
+ RT_UPDATE_REQ = 1, // TUX->DICT request stats update
+ RT_UPDATE_CONF = 2 // TRIX->TUX report stats update
+ };
+ STATIC_CONST( SignalLength = 9 );
+ Uint32 senderRef;
+ Uint32 senderData;
+ Uint32 requestType;
+ Uint32 requestFlag;
+ Uint32 indexId;
+ Uint32 indexVersion;
+ Uint32 tableId;
+ Uint32 fragId;
+ Uint32 loadTime;
+};
+
+#endif
=== modified file 'storage/ndb/include/kernel/signaldata/ScanFrag.hpp'
--- a/storage/ndb/include/kernel/signaldata/ScanFrag.hpp 2011-02-23 19:28:26 +0000
+++ b/storage/ndb/include/kernel/signaldata/ScanFrag.hpp 2011-05-19 09:16:32 +0000
@@ -79,6 +79,7 @@ public:
static Uint32 getScanPrio(const Uint32 & requestInfo);
static Uint32 getNoDiskFlag(const Uint32 & requestInfo);
static Uint32 getLcpScanFlag(const Uint32 & requestInfo);
+ static Uint32 getStatScanFlag(const Uint32 & requestInfo);
static void setLockMode(Uint32 & requestInfo, Uint32 lockMode);
static void setHoldLockFlag(Uint32 & requestInfo, Uint32 holdLock);
@@ -91,6 +92,7 @@ public:
static void setScanPrio(Uint32& requestInfo, Uint32 prio);
static void setNoDiskFlag(Uint32& requestInfo, Uint32 val);
static void setLcpScanFlag(Uint32 & requestInfo, Uint32 val);
+ static void setStatScanFlag(Uint32 & requestInfo, Uint32 val);
static void setReorgFlag(Uint32 & requestInfo, Uint32 val);
static Uint32 getReorgFlag(const Uint32 & requestInfo);
@@ -270,11 +272,12 @@ public:
* p = Scan prio - 4 Bits (12-15) -> max 15
* r = Reorg flag - 2 Bits (1-2)
* C = corr value flag - 1 Bit (16)
+ * s = Stat scan - 1 Bit 17
*
* 1111111111222222222233
* 01234567890123456789012345678901
* rrcdlxhkrztppppaaaaaaaaaaaaaaaa Short variant ( < 6.4.0)
- * rrcdlxhkrztppppA Long variant (6.4.0 +)
+ * rrcdlxhkrztppppAs Long variant (6.4.0 +)
*/
#define SF_LOCK_MODE_SHIFT (5)
#define SF_LOCK_MODE_MASK (1)
@@ -299,6 +302,8 @@ public:
#define SF_CORR_FACTOR_SHIFT (16)
+#define SF_STAT_SCAN_SHIFT (17)
+
inline
Uint32
ScanFragReq::getLockMode(const Uint32 & requestInfo){
@@ -488,6 +493,19 @@ ScanFragReq::setCorrFactorFlag(UintR & r
requestInfo |= (val << SF_CORR_FACTOR_SHIFT);
}
+inline
+Uint32
+ScanFragReq::getStatScanFlag(const Uint32 & requestInfo){
+ return (requestInfo >> SF_STAT_SCAN_SHIFT) & 1;
+}
+
+inline
+void
+ScanFragReq::setStatScanFlag(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "ScanFragReq::setStatScanFlag");
+ requestInfo |= (val << SF_STAT_SCAN_SHIFT);
+}
+
/**
* Request Info (SCAN_NEXTREQ)
*
=== modified file 'storage/ndb/include/kernel/signaldata/SignalData.hpp'
--- a/storage/ndb/include/kernel/signaldata/SignalData.hpp 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/include/kernel/signaldata/SignalData.hpp 2011-05-19 09:16:32 +0000
@@ -309,4 +309,12 @@ GSN_PRINT_SIGNATURE(printDBINFO_SCAN_REF
GSN_PRINT_SIGNATURE(printNODE_PING_REQ);
GSN_PRINT_SIGNATURE(printNODE_PING_CONF);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_REQ);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_CONF);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_REF);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_IMPL_REQ);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_IMPL_CONF);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_IMPL_REF);
+GSN_PRINT_SIGNATURE(printINDEX_STAT_REP);
+
#endif
=== modified file 'storage/ndb/include/kernel/signaldata/SumaImpl.hpp'
--- a/storage/ndb/include/kernel/signaldata/SumaImpl.hpp 2011-05-25 14:31:47 +0000
+++ b/storage/ndb/include/kernel/signaldata/SumaImpl.hpp 2011-05-29 10:55:32 +0000
@@ -250,7 +250,7 @@ struct SubSyncReq {
friend class Suma;
friend bool printSUB_SYNC_REQ(FILE *, const Uint32 *, Uint32, Uint16);
- STATIC_CONST( SignalLength = 7 );
+ STATIC_CONST( SignalLength = 8 );
Uint32 senderRef;
Uint32 senderData;
@@ -259,16 +259,21 @@ struct SubSyncReq {
Uint32 part; // SubscriptionData::Part
Uint32 requestInfo;
Uint32 fragCount;
+ Uint32 fragId; // ZNIL if not used
enum {
LM_Exclusive = 0x1
,Reorg = 0x2
,NoDisk = 0x4
,TupOrder = 0x8
+ ,LM_CommittedRead = 0x10
+ ,RangeScan = 0x20
+ ,StatScan = 0x40
};
SECTION( ATTRIBUTE_LIST = 0); // Used when doing SingelTableScan
SECTION( TABLE_LIST = 1 );
+ SECTION( TUX_BOUND_INFO = 1); // If range scan
};
struct SubSyncRef {
=== modified file 'storage/ndb/include/kernel/signaldata/TuxBound.hpp'
--- a/storage/ndb/include/kernel/signaldata/TuxBound.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/kernel/signaldata/TuxBound.hpp 2011-05-19 09:40:36 +0000
@@ -31,7 +31,10 @@ public:
BoundLT = 1, // bit 0 for strict
BoundGE = 2,
BoundGT = 3,
- BoundEQ = 4
+ BoundEQ = 4,
+ // stats scan parameter ids
+ StatSaveSize = 11,
+ StatSaveScale = 12
};
enum ErrorCode {
InvalidAttrInfo = 4110,
=== modified file 'storage/ndb/include/kernel/signaldata/TuxContinueB.hpp'
--- a/storage/ndb/include/kernel/signaldata/TuxContinueB.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/kernel/signaldata/TuxContinueB.hpp 2011-05-19 09:40:36 +0000
@@ -25,7 +25,8 @@ class TuxContinueB {
friend class Dbtux;
private:
enum {
- DropIndex = 1
+ DropIndex = 1, // unused
+ StatMon = 2
};
};
=== modified file 'storage/ndb/include/kernel/signaldata/UtilRelease.hpp'
--- a/storage/ndb/include/kernel/signaldata/UtilRelease.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/kernel/signaldata/UtilRelease.hpp 2011-05-19 09:38:03 +0000
@@ -17,7 +17,7 @@
*/
#ifndef UTIL_RELEASE_HPP
-#define UTIL_PREPARE_HPP
+#define UTIL_RELEASE_HPP
#include "SignalData.hpp"
=== modified file 'storage/ndb/include/mgmapi/mgmapi_config_parameters.h'
--- a/storage/ndb/include/mgmapi/mgmapi_config_parameters.h 2011-04-15 13:52:53 +0000
+++ b/storage/ndb/include/mgmapi/mgmapi_config_parameters.h 2011-05-31 08:28:58 +0000
@@ -186,6 +186,14 @@
#define CFG_DB_START_NO_NODEGROUP_TIMEOUT 619
+#define CFG_DB_INDEX_STAT_AUTO_CREATE 620
+#define CFG_DB_INDEX_STAT_AUTO_UPDATE 621
+#define CFG_DB_INDEX_STAT_SAVE_SIZE 622
+#define CFG_DB_INDEX_STAT_SAVE_SCALE 623
+#define CFG_DB_INDEX_STAT_TRIGGER_PCT 624
+#define CFG_DB_INDEX_STAT_TRIGGER_SCALE 625
+#define CFG_DB_INDEX_STAT_UPDATE_DELAY 626
+
#define CFG_NODE_ARBIT_RANK 200
#define CFG_NODE_ARBIT_DELAY 201
#define CFG_RESERVED_SEND_BUFFER_MEMORY 202
=== modified file 'storage/ndb/include/ndb_constants.h'
--- a/storage/ndb/include/ndb_constants.h 2011-02-16 14:53:53 +0000
+++ b/storage/ndb/include/ndb_constants.h 2011-05-31 08:28:58 +0000
@@ -112,4 +112,16 @@
*/
#define NDB_BACKUP_SEQUENCE 0x1F000000
+/**
+ * Defines for index statistics
+ */
+#define NDB_INDEX_STAT_DB "mysql"
+#define NDB_INDEX_STAT_SCHEMA "def"
+
+#define NDB_INDEX_STAT_HEAD_TABLE "NDB$IS_HEAD"
+#define NDB_INDEX_STAT_SAMPLE_TABLE "NDB$IS_SAMPLE"
+#define NDB_INDEX_STAT_SAMPLE_INDEX1 "NDB$IS_SAMPLE_X1"
+
+#define NDB_INDEX_STAT_PREFIX "NDB$IS"
+
#endif
=== modified file 'storage/ndb/src/common/debugger/signaldata/CMakeLists.txt'
--- a/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt 2011-05-23 15:46:53 +0000
@@ -44,5 +44,6 @@ ADD_LIBRARY(ndbsignaldata STATIC
LqhTrans.cpp ReadNodesConf.cpp CntrStart.cpp
ScanFrag.cpp ApiVersion.cpp
LocalRouteOrd.cpp
- DbinfoScan.cpp NodePing.cpp)
+ DbinfoScan.cpp NodePing.cpp
+ IndexStatSignal.cpp)
=== added file 'storage/ndb/src/common/debugger/signaldata/IndexStatSignal.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/IndexStatSignal.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/IndexStatSignal.cpp 2011-05-19 09:16:32 +0000
@@ -0,0 +1,152 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <signaldata/IndexStatSignal.hpp>
+
+static void
+get_req_rt_name(Uint32 rt, char* rt_name)
+{
+ strcpy(rt_name, "Unknown");
+#define set_req_rt_name(x) if (rt == IndexStatReq::x) strcpy(rt_name, #x)
+ set_req_rt_name(RT_UPDATE_STAT);
+ set_req_rt_name(RT_CLEAN_NEW);
+ set_req_rt_name(RT_SCAN_FRAG);
+ set_req_rt_name(RT_CLEAN_OLD);
+ set_req_rt_name(RT_START_MON);
+ set_req_rt_name(RT_DELETE_STAT);
+ set_req_rt_name(RT_STOP_MON);
+ set_req_rt_name(RT_DROP_HEAD);
+ set_req_rt_name(RT_CLEAN_ALL);
+#undef set_req_rt_name
+}
+
+static void
+get_rep_rt_name(Uint32 rt, char* rt_name)
+{
+ strcpy(rt_name, "Unknown");
+#define set_rep_rt_name(x) if (rt == IndexStatRep::x) strcpy(rt_name, #x)
+ set_rep_rt_name(RT_UPDATE_REQ);
+ set_rep_rt_name(RT_UPDATE_CONF);
+#undef set_rep_rt_name
+}
+
+bool
+printINDEX_STAT_REQ(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatReq* sig = (const IndexStatReq*)theData;
+ fprintf(output, " clientRef: 0x%x", sig->clientRef);
+ fprintf(output, " clientData: %u", sig->clientData);
+ fprintf(output, "\n");
+ Uint32 rt = sig->requestInfo & 0xFF;
+ char rt_name[40];
+ get_req_rt_name(rt, rt_name);
+ fprintf(output, " requestType: %s[%u]", rt_name, rt);
+ fprintf(output, " requestFlag: 0x%x", sig->requestFlag);
+ fprintf(output, "\n");
+ fprintf(output, " indexId: %u", sig->indexId);
+ fprintf(output, " indexVersion: %u", sig->indexVersion);
+ fprintf(output, " tableId: %u", sig->tableId);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_IMPL_REQ(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatImplReq* sig = (const IndexStatImplReq*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, "\n");
+ Uint32 rt = sig->requestType;
+ char rt_name[40];
+ get_req_rt_name(rt, rt_name);
+ fprintf(output, " requestType: %s[%u]", rt_name, rt);
+ fprintf(output, " requestFlag: 0x%x", sig->requestFlag);
+ fprintf(output, "\n");
+ fprintf(output, " indexId: %u", sig->indexId);
+ fprintf(output, " indexVersion: %u", sig->indexVersion);
+ fprintf(output, " tableId: %u", sig->tableId);
+ fprintf(output, " fragId: %u", sig->fragId);
+ fprintf(output, " fragCount: %u", sig->fragCount);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_CONF(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatConf* sig = (const IndexStatConf*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_IMPL_CONF(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatImplConf* sig = (const IndexStatImplConf*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_REF(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatRef* sig = (const IndexStatRef*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, " errorCode: %u", sig->errorCode);
+ fprintf(output, " errorLine: %u", sig->errorLine);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_IMPL_REF(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatImplRef* sig = (const IndexStatImplRef*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, " errorCode: %u", sig->errorCode);
+ fprintf(output, " errorLine: %u", sig->errorLine);
+ fprintf(output, "\n");
+ return true;
+}
+
+bool
+printINDEX_STAT_REP(FILE* output, const Uint32* theData, Uint32 len, Uint16)
+{
+ const IndexStatRep* sig = (const IndexStatRep*)theData;
+ fprintf(output, " senderRef: 0x%x", sig->senderRef);
+ fprintf(output, " senderData: %u", sig->senderData);
+ fprintf(output, "\n");
+ Uint32 rt = sig->requestType;
+ char rt_name[40];
+ get_rep_rt_name(rt, rt_name);
+ fprintf(output, " requestType: %s[%u]", rt_name, rt);
+ fprintf(output, " requestFlag: 0x%x", sig->requestFlag);
+ fprintf(output, "\n");
+ fprintf(output, " indexId: %u", sig->indexId);
+ fprintf(output, " indexVersion: %u", sig->indexVersion);
+ fprintf(output, " tableId: %u", sig->tableId);
+ fprintf(output, "\n");
+ fprintf(output, " fragId: %u", sig->fragId);
+ fprintf(output, " loadTime: %u", sig->loadTime);
+ fprintf(output, "\n");
+ return true;
+}
=== modified file 'storage/ndb/src/common/debugger/signaldata/Makefile.am'
--- a/storage/ndb/src/common/debugger/signaldata/Makefile.am 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/Makefile.am 2011-05-19 09:16:32 +0000
@@ -46,7 +46,8 @@ libsignaldataprint_la_SOURCES = \
CreateTrigImpl.cpp DropTrigImpl.cpp \
CreateIndxImpl.cpp DropIndxImpl.cpp AlterIndxImpl.cpp \
BuildIndx.cpp BuildIndxImpl.cpp ApiVersion.cpp \
- LocalRouteOrd.cpp DbinfoScan.cpp NodePing.cpp
+ LocalRouteOrd.cpp DbinfoScan.cpp NodePing.cpp \
+ IndexStatSignal.cpp
include $(top_srcdir)/storage/ndb/config/common.mk.am
include $(top_srcdir)/storage/ndb/config/type_ndbapi.mk.am
=== modified file 'storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp 2011-02-08 13:55:54 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp 2011-05-19 09:16:32 +0000
@@ -51,8 +51,11 @@ printSCAN_FRAGREQ(FILE * output, const U
ScanFragReq::getAttrLen(sig->requestInfo));
fprintf(output, " reorg: %u",
ScanFragReq::getReorgFlag(sig->requestInfo));
- fprintf(output, " corr: %u\n",
+ fprintf(output, " corr: %u",
ScanFragReq::getCorrFactorFlag(sig->requestInfo));
+ fprintf(output, " stat: %u",
+ ScanFragReq::getStatScanFlag(sig->requestInfo));
+ fprintf(output, "\n");
fprintf(output, " tableId: %u\n", sig->tableId);
fprintf(output, " fragmentNo: %u\n", sig->fragmentNoKeyLen & 0xFFFF);
=== modified file 'storage/ndb/src/common/debugger/signaldata/SchemaTransImpl.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SchemaTransImpl.cpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SchemaTransImpl.cpp 2011-05-19 09:16:32 +0000
@@ -137,6 +137,9 @@ printSCHEMA_TRANS_IMPL_REQ(FILE* output,
case GSN_BUILD_INDX_IMPL_REQ:
printBUILD_INDX_IMPL_REQ(output, pb_data, pb_len, rbn);
break;
+ case GSN_INDEX_STAT_IMPL_REQ:
+ printINDEX_STAT_IMPL_REQ(output, pb_data, pb_len, rbn);
+ break;
default:
{
Uint32 i;
=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp 2011-05-19 09:16:32 +0000
@@ -260,6 +260,14 @@ SignalDataPrintFunctions[] = {
,{ GSN_NODE_PING_REQ, printNODE_PING_REQ }
,{ GSN_NODE_PING_CONF, printNODE_PING_CONF }
+ ,{ GSN_INDEX_STAT_REQ, printINDEX_STAT_REQ }
+ ,{ GSN_INDEX_STAT_CONF, printINDEX_STAT_CONF }
+ ,{ GSN_INDEX_STAT_REF, printINDEX_STAT_REF }
+ ,{ GSN_INDEX_STAT_IMPL_REQ, printINDEX_STAT_IMPL_REQ }
+ ,{ GSN_INDEX_STAT_IMPL_CONF, printINDEX_STAT_IMPL_CONF }
+ ,{ GSN_INDEX_STAT_IMPL_REF, printINDEX_STAT_IMPL_REF }
+ ,{ GSN_INDEX_STAT_REP, printINDEX_STAT_REP }
+
,{ 0, 0 }
};
=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalNames.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp 2011-05-19 09:16:32 +0000
@@ -763,5 +763,13 @@ const GsnName SignalNames [] = {
,{ GSN_NODE_PING_REQ, "NODE_PING_REQ" }
,{ GSN_NODE_PING_CONF, "NODE_PING_CONF" }
+
+ ,{ GSN_INDEX_STAT_REQ, "INDEX_STAT_REQ" }
+ ,{ GSN_INDEX_STAT_CONF, "INDEX_STAT_CONF" }
+ ,{ GSN_INDEX_STAT_REF, "INDEX_STAT_REF" }
+ ,{ GSN_INDEX_STAT_IMPL_REQ, "INDEX_STAT_IMPL_REQ" }
+ ,{ GSN_INDEX_STAT_IMPL_CONF, "INDEX_STAT_IMPL_CONF" }
+ ,{ GSN_INDEX_STAT_IMPL_REF, "INDEX_STAT_IMPL_REF" }
+ ,{ GSN_INDEX_STAT_REP, "INDEX_STAT_REP" }
};
const unsigned short NO_OF_SIGNAL_NAMES = sizeof(SignalNames)/sizeof(GsnName);
=== modified file 'storage/ndb/src/kernel/blocks/ERROR_codes.txt'
--- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2011-05-19 07:32:39 +0000
+++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt 2011-05-25 15:03:11 +0000
@@ -30,6 +30,7 @@ Next SUMA 13047
Next LGMAN 15001
Next TSMAN 16001
Next DBSPJ 17000
+Next TRIX 18000
TESTING NODE FAILURE, ARBITRATION
---------------------------------
@@ -721,3 +722,15 @@ ACC bug#34348
3002: limit frags to 2 directory pages (instead of 256)
print (if VM_TRACE) LH variables at expand and shrink
apply before mass data load, reset with error insert 0
+
+TRIX
+----
+Index stats:
+18001: fail to seize statOp
+18002: fail to seize associated subRec
+18011: fail HEAD read - simulate UtilExecuteRef::AllocationError
+18012: fail HEAD insert/update/delete - as in 18011
+18021: fail RT_CLEAN_NEW - simulate TC error 626
+18022: fail RT_CLEAN_OLD (non-fatal) - as in 18021
+18023: fail RT_CLEAN_ALL (non-fatal) - as in 18021
+18024: fail RT_SCAN_FRAG - simulate TC error 630
=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2011-05-19 07:32:39 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp 2011-05-25 15:03:11 +0000
@@ -1436,6 +1436,11 @@ void Cmvmi::execTAMPER_ORD(Signal* signa
jam();
tuserblockref = DBSPJ_REF;
}
+ else if (errNo < 19000)
+ {
+ jam();
+ tuserblockref = TRIX_REF;
+ }
else if (errNo < 30000)
{
/*--------------------------------------------------------------------*/
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2011-05-17 23:29:55 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp 2011-05-31 08:28:58 +0000
@@ -101,6 +101,8 @@ extern EventLogger * g_eventLogger;
#include <signaldata/DbinfoScan.hpp>
#include <signaldata/TransIdAI.hpp>
+#include <signaldata/IndexStatSignal.hpp>
+
#define ZNOT_FOUND 626
#define ZALREADYEXIST 630
@@ -380,6 +382,12 @@ void Dbdict::execDBINFO_SCANREQ(Signal *
c_buildIndexRecPool.getEntrySize(),
c_buildIndexRecPool.getUsedHi(),
{ 0,0,0,0 }},
+ { "Index Stat Record",
+ c_indexStatRecPool.getUsed(),
+ c_indexStatRecPool.getSize(),
+ c_indexStatRecPool.getEntrySize(),
+ c_indexStatRecPool.getUsedHi(),
+ { 0,0,0,0 }},
{ "Create Hash Map Record",
c_createHashMapRecPool.getUsed(),
c_createHashMapRecPool.getSize(),
@@ -505,6 +513,10 @@ void Dbdict::execCONTINUEB(Signal* signa
execDICT_TAKEOVER_REQ(signal);
}
break;
+ case ZINDEX_STAT_BG_PROCESS:
+ jam();
+ indexStatBg_process(signal);
+ break;
#ifdef ERROR_INSERT
case 6103: // search for it
jam();
@@ -2257,6 +2269,14 @@ Dbdict::Dbdict(Block_context& ctx):
addRecSignal(GSN_DROP_NODEGROUP_REQ, &Dbdict::execDROP_NODEGROUP_REQ);
addRecSignal(GSN_DROP_NODEGROUP_IMPL_REF, &Dbdict::execDROP_NODEGROUP_IMPL_REF);
addRecSignal(GSN_DROP_NODEGROUP_IMPL_CONF, &Dbdict::execDROP_NODEGROUP_IMPL_CONF);
+
+ // ordered index statistics
+ addRecSignal(GSN_INDEX_STAT_REQ, &Dbdict::execINDEX_STAT_REQ);
+ addRecSignal(GSN_INDEX_STAT_CONF, &Dbdict::execINDEX_STAT_CONF);
+ addRecSignal(GSN_INDEX_STAT_REF, &Dbdict::execINDEX_STAT_REF);
+ addRecSignal(GSN_INDEX_STAT_IMPL_CONF, &Dbdict::execINDEX_STAT_IMPL_CONF);
+ addRecSignal(GSN_INDEX_STAT_IMPL_REF, &Dbdict::execINDEX_STAT_IMPL_REF);
+ addRecSignal(GSN_INDEX_STAT_REP, &Dbdict::execINDEX_STAT_REP);
}//Dbdict::Dbdict()
Dbdict::~Dbdict()
@@ -2457,6 +2477,9 @@ void Dbdict::initialiseTableRecord(Table
tablePtr.p->buildTriggerId = RNIL;
tablePtr.p->m_read_locked= 0;
tablePtr.p->storageType = NDB_STORAGETYPE_DEFAULT;
+ tablePtr.p->indexStatFragId = ZNIL;
+ tablePtr.p->indexStatNodeId = ZNIL;
+ tablePtr.p->indexStatBgRequest = 0;
}//Dbdict::initialiseTableRecord()
void Dbdict::initTriggerRecords()
@@ -2680,6 +2703,14 @@ void Dbdict::execSTTOR(Signal* signal)
c_restartType == NodeState::ST_INITIAL_NODE_RESTART ||
c_restartType == NodeState::ST_NODE_RESTART);
break;
+ case 7:
+ /*
+ * config cannot yet be changed dynamically but we start the
+ * loop always anyway because the cost is minimal
+ */
+ c_indexStatBgId = 0;
+ indexStatBg_sendContinueB(signal);
+ break;
}
sendSTTORRY(signal);
}//execSTTOR()
@@ -2691,8 +2722,9 @@ void Dbdict::sendSTTORRY(Signal* signal)
signal->theData[2] = 0; /* garbage */
signal->theData[3] = 1; /* first wanted start phase */
signal->theData[4] = 3; /* get type of start */
- signal->theData[5] = ZNOMOREPHASES;
- sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 6, JBB);
+ signal->theData[5] = 7; /* start index stat bg loop */
+ signal->theData[6] = ZNOMOREPHASES;
+ sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 7, JBB);
}
/* ---------------------------------------------------------------- */
@@ -2716,6 +2748,10 @@ void Dbdict::execREAD_CONFIG_REQ(Signal*
&c_maxNoOfTriggers));
ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_ATTRIBUTE,&attributesize));
ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_TABLE, &tablerecSize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_AUTO_CREATE,
+ &c_indexStatAutoCreate));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_AUTO_UPDATE,
+ &c_indexStatAutoUpdate));
c_attributeRecordPool.setSize(attributesize);
c_attributeRecordHash.setSize(64);
@@ -2763,6 +2799,7 @@ void Dbdict::execREAD_CONFIG_REQ(Signal*
c_dropIndexRecPool.setSize(2 * MAX_INDEXES);
c_alterIndexRecPool.setSize(2 * MAX_INDEXES);
c_buildIndexRecPool.setSize(2 * 2 * MAX_INDEXES);
+ c_indexStatRecPool.setSize((1 + 4) * MAX_INDEXES); //main + 4 subs
c_createFilegroupRecPool.setSize(32);
c_createFileRecPool.setSize(32);
c_dropFilegroupRecPool.setSize(32);
@@ -11192,6 +11229,7 @@ Dbdict::createIndex_fromCreateTable(Sign
ndbrequire(conf->transId == trans_ptr.p->m_transId);
impl_req->indexVersion = conf->tableVersion;
createIndexPtr.p->m_sub_create_table = true;
+
createSubOps(signal, op_ptr);
} else {
jam();
@@ -11984,6 +12022,15 @@ Dbdict::alterIndex_parse(Signal* signal,
}
c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+ // get name for system index check later
+ char indexName[MAX_TAB_NAME_SIZE];
+ memset(indexName, 0, sizeof(indexName));
+ {
+ ConstRope r(c_rope_pool, indexPtr.p->tableName);
+ r.copy(indexName);
+ }
+ D("index " << indexName);
+
if (indexPtr.p->tableVersion != impl_req->indexVersion) {
jam();
setError(error, AlterIndxRef::InvalidIndexVersion, __LINE__);
@@ -12101,6 +12148,46 @@ Dbdict::alterIndex_parse(Signal* signal,
// set attribute mask (of primary table attribute ids)
getIndexAttrMask(indexPtr, alterIndexPtr.p->m_attrMask);
+ // ordered index stats
+ if (indexPtr.p->tableType == DictTabInfo::OrderedIndex) {
+ jam();
+
+ // always compute monitored replica
+ if (requestType == AlterIndxImplReq::AlterIndexOnline) {
+ jam();
+ set_index_stat_frag(signal, indexPtr);
+ }
+
+ // skip system indexes (at least index stats indexes)
+ if (strstr(indexName, "/" NDB_INDEX_STAT_PREFIX) != 0) {
+ jam();
+ D("skip index stats operations for system index");
+ alterIndexPtr.p->m_sub_index_stat_dml = true;
+ alterIndexPtr.p->m_sub_index_stat_mon = true;
+ }
+
+ // disable update/delete if db not up
+ if (getNodeState().startLevel != NodeState::SL_STARTED &&
+ getNodeState().startLevel != NodeState::SL_SINGLEUSER) {
+ jam();
+ alterIndexPtr.p->m_sub_index_stat_dml = true;
+ }
+
+ // disable update on create if not auto
+ if (requestType == AlterIndxImplReq::AlterIndexOnline &&
+ !c_indexStatAutoCreate) {
+ jam();
+ alterIndexPtr.p->m_sub_index_stat_dml = true;
+ }
+
+ // always delete on drop because manual update may have been done
+ if (requestType == AlterIndxImplReq::AlterIndexOffline) {
+ jam();
+ }
+
+ // always assign/remove monitored replica in TUX instances
+ }
+
if (ERROR_INSERTED(6123)) {
jam();
CLEAR_ERROR_INSERT_VALUE;
@@ -12109,6 +12196,32 @@ Dbdict::alterIndex_parse(Signal* signal,
}
}
+void
+Dbdict::set_index_stat_frag(Signal* signal, TableRecordPtr indexPtr)
+{
+ jam();
+ const Uint32 indexId = indexPtr.i;
+ Uint32 err = get_fragmentation(signal, indexId);
+ ndbrequire(err == 0);
+ // format: R F { fragId node1 .. nodeR } x { F }
+ // fragId: 0 1 2 .. (or whatever)
+ const Uint16* frag_data = (Uint16*)(signal->theData+25);
+ const Uint32 noOfFragments = frag_data[1];
+ const Uint32 noOfReplicas = frag_data[0];
+ ndbrequire(noOfFragments != 0 && noOfReplicas != 0);
+
+ // distribute by table and index id
+ const Uint32 value = indexPtr.p->primaryTableId + indexPtr.i;
+ const Uint32 fragId = value % noOfFragments;
+ const Uint32 fragIndex = 2 + (1 + noOfReplicas) * fragId;
+ const Uint32 nodeIndex = value % noOfReplicas;
+ const Uint32 nodeId = frag_data[fragIndex + 1 + nodeIndex];
+
+ D("set_index_stat_frag" << V(indexId) << V(fragId) << V(nodeId));
+ indexPtr.p->indexStatFragId = fragId;
+ indexPtr.p->indexStatNodeId = nodeId;
+}
+
bool
Dbdict::alterIndex_subOps(Signal* signal, SchemaOpPtr op_ptr)
{
@@ -12118,6 +12231,8 @@ Dbdict::alterIndex_subOps(Signal* signal
getOpRec(op_ptr, alterIndexPtr);
const AlterIndxImplReq* impl_req = &alterIndexPtr.p->m_request;
Uint32 requestType = impl_req->requestType;
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
// ops to create or drop triggers
if (alterIndexPtr.p->m_sub_trigger == false)
@@ -12169,6 +12284,19 @@ Dbdict::alterIndex_subOps(Signal* signal
return true;
}
+ if (indexPtr.p->isOrderedIndex() &&
+ (!alterIndexPtr.p->m_sub_index_stat_dml ||
+ !alterIndexPtr.p->m_sub_index_stat_mon)) {
+ jam();
+ Callback c = {
+ safe_cast(&Dbdict::alterIndex_fromIndexStat),
+ op_ptr.p->op_key
+ };
+ op_ptr.p->m_callback = c;
+ alterIndex_toIndexStat(signal, op_ptr);
+ return true;
+ }
+
return false;
}
@@ -12404,6 +12532,93 @@ Dbdict::alterIndex_fromBuildIndex(Signal
}
void
+Dbdict::alterIndex_toIndexStat(Signal* signal, SchemaOpPtr op_ptr)
+{
+ D("alterIndex_toIndexStat");
+
+ SchemaTransPtr trans_ptr = op_ptr.p->m_trans_ptr;
+ AlterIndexRecPtr alterIndexPtr;
+ getOpRec(op_ptr, alterIndexPtr);
+ const AlterIndxImplReq* impl_req = &alterIndexPtr.p->m_request;
+
+ IndexStatReq* req = (IndexStatReq*)signal->getDataPtrSend();
+
+ Uint32 requestType = 0;
+ switch (impl_req->requestType) {
+ case AlterIndxImplReq::AlterIndexOnline:
+ if (!alterIndexPtr.p->m_sub_index_stat_dml)
+ requestType = IndexStatReq::RT_UPDATE_STAT;
+ else
+ requestType = IndexStatReq::RT_START_MON;
+ break;
+ case AlterIndxImplReq::AlterIndexOffline:
+ if (!alterIndexPtr.p->m_sub_index_stat_dml)
+ requestType = IndexStatReq::RT_DELETE_STAT;
+ else
+ requestType = IndexStatReq::RT_STOP_MON;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+
+ Uint32 requestInfo = 0;
+ DictSignal::setRequestType(requestInfo, requestType);
+ DictSignal::addRequestFlagsGlobal(requestInfo, op_ptr.p->m_requestInfo);
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+
+ req->clientRef = reference();
+ req->clientData = op_ptr.p->op_key;
+ req->transId = trans_ptr.p->m_transId;
+ req->transKey = trans_ptr.p->trans_key;
+ req->requestInfo = requestInfo;
+ req->requestFlag = 0;
+ req->indexId = impl_req->indexId;
+ req->indexVersion = indexPtr.p->tableVersion;
+ req->tableId = impl_req->tableId;
+
+ sendSignal(reference(), GSN_INDEX_STAT_REQ,
+ signal, IndexStatReq::SignalLength, JBB);
+}
+
+void
+Dbdict::alterIndex_fromIndexStat(Signal* signal, Uint32 op_key, Uint32 ret)
+{
+ jam();
+ D("alterIndex_fromIndexStat");
+
+ SchemaOpPtr op_ptr;
+ AlterIndexRecPtr alterIndexPtr;
+
+ findSchemaOp(op_ptr, alterIndexPtr, op_key);
+ ndbrequire(!op_ptr.isNull());
+ SchemaTransPtr trans_ptr = op_ptr.p->m_trans_ptr;
+
+ if (ret == 0) {
+ jam();
+ const IndexStatConf* conf =
+ (const IndexStatConf*)signal->getDataPtr();
+
+ ndbrequire(conf->transId == trans_ptr.p->m_transId);
+ ndbrequire(!alterIndexPtr.p->m_sub_index_stat_dml ||
+ !alterIndexPtr.p->m_sub_index_stat_mon);
+ alterIndexPtr.p->m_sub_index_stat_dml = true;
+ alterIndexPtr.p->m_sub_index_stat_mon = true;
+ createSubOps(signal, op_ptr);
+ } else {
+ jam();
+ const IndexStatRef* ref =
+ (const IndexStatRef*)signal->getDataPtr();
+
+ ErrorInfo error;
+ setError(error, ref);
+ abortSubOps(signal, op_ptr, error);
+ }
+}
+
+void
Dbdict::alterIndex_reply(Signal* signal, SchemaOpPtr op_ptr, ErrorInfo error)
{
D("alterIndex_reply" << V(op_ptr.i) << *op_ptr.p);
@@ -13645,6 +13860,755 @@ Dbdict::execBUILD_INDX_IMPL_REF(Signal*
// BuildIndex: END
+// MODULE: IndexStat
+
+const Dbdict::OpInfo
+Dbdict::IndexStatRec::g_opInfo = {
+ { 'S', 'I', 'n', 0 },
+ GSN_INDEX_STAT_IMPL_REQ,
+ IndexStatImplReq::SignalLength,
+ //
+ &Dbdict::indexStat_seize,
+ &Dbdict::indexStat_release,
+ //
+ &Dbdict::indexStat_parse,
+ &Dbdict::indexStat_subOps,
+ &Dbdict::indexStat_reply,
+ //
+ &Dbdict::indexStat_prepare,
+ &Dbdict::indexStat_commit,
+ &Dbdict::indexStat_complete,
+ //
+ &Dbdict::indexStat_abortParse,
+ &Dbdict::indexStat_abortPrepare
+};
+
+bool
+Dbdict::indexStat_seize(SchemaOpPtr op_ptr)
+{
+ return seizeOpRec<IndexStatRec>(op_ptr);
+}
+
+void
+Dbdict::indexStat_release(SchemaOpPtr op_ptr)
+{
+ releaseOpRec<IndexStatRec>(op_ptr);
+}
+
+void
+Dbdict::execINDEX_STAT_REQ(Signal* signal)
+{
+ jamEntry();
+ if (!assembleFragments(signal)) {
+ jam();
+ return;
+ }
+ SectionHandle handle(this, signal);
+
+ const IndexStatReq req_copy =
+ *(const IndexStatReq*)signal->getDataPtr();
+ const IndexStatReq* req = &req_copy;
+
+ ErrorInfo error;
+ do {
+ SchemaOpPtr op_ptr;
+ IndexStatRecPtr indexStatPtr;
+ IndexStatImplReq* impl_req;
+
+ startClientReq(op_ptr, indexStatPtr, req, impl_req, error);
+ if (hasError(error)) {
+ jam();
+ break;
+ }
+
+ // senderRef, senderData, requestType have been set already
+ impl_req->transId = req->transId;
+ impl_req->requestFlag = req->requestFlag;
+ impl_req->indexId = req->indexId;
+ impl_req->indexVersion = req->indexVersion;
+ impl_req->tableId = req->tableId;
+ impl_req->fragId = ZNIL;
+ impl_req->fragCount = ZNIL;
+
+ handleClientReq(signal, op_ptr, handle);
+ return;
+ } while (0);
+
+ releaseSections(handle);
+
+ IndexStatRef* ref = (IndexStatRef*)signal->getDataPtrSend();
+ ref->senderRef = reference();
+ ref->clientData = req->clientData;
+ ref->transId = req->transId;
+ getError(error, ref);
+
+ sendSignal(req->clientRef, GSN_INDEX_STAT_REF, signal,
+ IndexStatRef::SignalLength, JBB);
+}
+
+// IndexStat: PARSE
+
+void
+Dbdict::indexStat_parse(Signal* signal, bool master,
+ SchemaOpPtr op_ptr,
+ SectionHandle& handle, ErrorInfo& error)
+{
+ D("indexStat_parse");
+
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ // get index
+ TableRecordPtr indexPtr;
+ if (!(impl_req->indexId < c_tableRecordPool.getSize())) {
+ jam();
+ setError(error, IndexStatRef::InvalidIndex, __LINE__);
+ return;
+ }
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+
+ if (!indexPtr.p->isOrderedIndex()) {
+ jam();
+ setError(error, IndexStatRef::InvalidIndex, __LINE__);
+ return;
+ }
+
+ XSchemaFile* xsf = &c_schemaFile[SchemaRecord::NEW_SCHEMA_FILE];
+ const SchemaFile::TableEntry* te = getTableEntry(xsf, impl_req->indexId);
+ if (te->m_tableState != SchemaFile::SF_CREATE &&
+ te->m_tableState != SchemaFile::SF_IN_USE) {
+ jam();
+ setError(error, IndexStatRef::InvalidIndex, __LINE__);
+ return;
+ }
+
+ // fragmentId is defined only in signals from DICT to TRIX,TUX
+ if (impl_req->fragId != ZNIL) {
+ jam();
+ setError(error, IndexStatRef::InvalidRequest, __LINE__);
+ return;
+ }
+ impl_req->fragCount = indexPtr.p->fragmentCount;
+
+ switch (impl_req->requestType) {
+ case IndexStatReq::RT_UPDATE_STAT:
+ jam();
+ // clean new samples, scan, clean old samples, start frag monitor
+ indexStatPtr.p->m_subOpCount = 4;
+ indexStatPtr.p->m_subOpIndex = 0;
+ break;
+ case IndexStatReq::RT_DELETE_STAT:
+ jam();
+ // stop frag monitor, delete head, clean all samples
+ indexStatPtr.p->m_subOpCount = 3;
+ indexStatPtr.p->m_subOpIndex = 0;
+ break;
+ case IndexStatReq::RT_SCAN_FRAG:
+ case IndexStatReq::RT_CLEAN_NEW:
+ case IndexStatReq::RT_CLEAN_OLD:
+ case IndexStatReq::RT_CLEAN_ALL:
+ case IndexStatReq::RT_DROP_HEAD:
+ case IndexStatReq::RT_START_MON:
+ case IndexStatReq::RT_STOP_MON:
+ jam();
+ // sub-operations can be invoked only by DICT
+ if (master && refToBlock(op_ptr.p->m_clientRef) != DBDICT) {
+ jam();
+ setError(error, IndexStatRef::InvalidRequest, __LINE__);
+ return;
+ }
+ indexStatPtr.p->m_subOpCount = 0;
+ indexStatPtr.p->m_subOpIndex = 0;
+ break;
+ default:
+ jam();
+ setError(error, IndexStatRef::InvalidRequest, __LINE__);
+ return;
+ }
+}
+
+bool
+Dbdict::indexStat_subOps(Signal* signal, SchemaOpPtr op_ptr)
+{
+ D("indexStat_subOps" << V(op_ptr.i) << V(*op_ptr.p));
+
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ const Uint32 subOpIndex = indexStatPtr.p->m_subOpIndex;
+ const Uint32 subOpCount = indexStatPtr.p->m_subOpCount;
+ if (subOpIndex >= subOpCount) {
+ jam();
+ ndbrequire(subOpIndex == subOpCount);
+ return false;
+ }
+
+ Uint32 requestType = 0;
+
+ switch (impl_req->requestType) {
+ case IndexStatReq::RT_UPDATE_STAT:
+ if (subOpIndex == 0)
+ requestType = IndexStatReq::RT_CLEAN_NEW;
+ else if (subOpIndex == 1)
+ requestType = IndexStatReq::RT_SCAN_FRAG;
+ else if (subOpIndex == 2)
+ requestType = IndexStatReq::RT_CLEAN_OLD;
+ else if (subOpIndex == 3)
+ requestType = IndexStatReq::RT_START_MON;
+ break;
+
+ case IndexStatReq::RT_DELETE_STAT:
+ jam();
+ if (subOpIndex == 0)
+ requestType = IndexStatReq::RT_STOP_MON;
+ else if (subOpIndex == 1)
+ requestType = IndexStatReq::RT_DROP_HEAD;
+ else if (subOpIndex == 2)
+ requestType = IndexStatReq::RT_CLEAN_ALL;
+ break;
+ };
+
+ ndbrequire(requestType != 0);
+ Callback c = {
+ safe_cast(&Dbdict::indexStat_fromIndexStat),
+ op_ptr.p->op_key
+ };
+ op_ptr.p->m_callback = c;
+ indexStat_toIndexStat(signal, op_ptr, requestType);
+ return true;
+}
+
+void
+Dbdict::indexStat_toIndexStat(Signal* signal, SchemaOpPtr op_ptr,
+ Uint32 requestType)
+{
+ D("indexStat_toIndexStat");
+
+ SchemaTransPtr trans_ptr = op_ptr.p->m_trans_ptr;
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ IndexStatReq* req = (IndexStatReq*)signal->getDataPtrSend();
+
+ Uint32 requestInfo = 0;
+ DictSignal::setRequestType(requestInfo, requestType);
+ DictSignal::addRequestFlagsGlobal(requestInfo, op_ptr.p->m_requestInfo);
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+
+ req->clientRef = reference();
+ req->clientData = op_ptr.p->op_key;
+ req->transId = trans_ptr.p->m_transId;
+ req->transKey = trans_ptr.p->trans_key;
+ req->requestInfo = requestInfo;
+ req->requestFlag = 0;
+ req->indexId = impl_req->indexId;
+ req->indexVersion = indexPtr.p->tableVersion;
+ req->tableId = impl_req->tableId;
+
+ sendSignal(reference(), GSN_INDEX_STAT_REQ,
+ signal, IndexStatReq::SignalLength, JBB);
+}
+
+void
+Dbdict::indexStat_fromIndexStat(Signal* signal, Uint32 op_key, Uint32 ret)
+{
+ jam();
+ D("indexStat_fromIndexStat");
+
+ SchemaOpPtr op_ptr;
+ IndexStatRecPtr indexStatPtr;
+
+ findSchemaOp(op_ptr, indexStatPtr, op_key);
+ ndbrequire(!op_ptr.isNull());
+ SchemaTransPtr trans_ptr = op_ptr.p->m_trans_ptr;
+
+ if (ret == 0) {
+ jam();
+ const IndexStatConf* conf =
+ (const IndexStatConf*)signal->getDataPtr();
+
+ ndbrequire(conf->transId == trans_ptr.p->m_transId);
+ ndbrequire(indexStatPtr.p->m_subOpIndex < indexStatPtr.p->m_subOpCount);
+ indexStatPtr.p->m_subOpIndex += 1;
+ createSubOps(signal, op_ptr);
+ } else {
+ jam();
+ const IndexStatRef* ref =
+ (const IndexStatRef*)signal->getDataPtr();
+
+ ErrorInfo error;
+ setError(error, ref);
+ abortSubOps(signal, op_ptr, error);
+ }
+}
+
+void
+Dbdict::indexStat_reply(Signal* signal, SchemaOpPtr op_ptr, ErrorInfo error)
+{
+ jam();
+
+ SchemaTransPtr& trans_ptr = op_ptr.p->m_trans_ptr;
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ D("indexStat_reply" << V(impl_req->indexId));
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+
+ if (!hasError(error)) {
+ IndexStatConf* conf = (IndexStatConf*)signal->getDataPtrSend();
+ conf->senderRef = reference();
+ conf->clientData = op_ptr.p->m_clientData;
+ conf->transId = trans_ptr.p->m_transId;
+
+ Uint32 clientRef = op_ptr.p->m_clientRef;
+ sendSignal(clientRef, GSN_INDEX_STAT_CONF, signal,
+ IndexStatConf::SignalLength, JBB);
+ } else {
+ jam();
+ IndexStatRef* ref = (IndexStatRef*)signal->getDataPtrSend();
+ ref->senderRef = reference();
+ ref->clientData = op_ptr.p->m_clientData;
+ ref->transId = trans_ptr.p->m_transId;
+ getError(error, ref);
+
+ Uint32 clientRef = op_ptr.p->m_clientRef;
+ sendSignal(clientRef, GSN_INDEX_STAT_REF, signal,
+ IndexStatRef::SignalLength, JBB);
+ }
+}
+
+// IndexStat: PREPARE
+
+void
+Dbdict::indexStat_prepare(Signal* signal, SchemaOpPtr op_ptr)
+{
+ jam();
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ D("indexStat_prepare" << V(*op_ptr.p));
+
+ if (impl_req->requestType == IndexStatReq::RT_UPDATE_STAT ||
+ impl_req->requestType == IndexStatReq::RT_DELETE_STAT) {
+ // the main op of stat update or delete does nothing
+ sendTransConf(signal, op_ptr);
+ return;
+ }
+
+ indexStat_toLocalStat(signal, op_ptr);
+}
+
+void
+Dbdict::indexStat_toLocalStat(Signal* signal, SchemaOpPtr op_ptr)
+{
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+ SchemaTransPtr trans_ptr = op_ptr.p->m_trans_ptr;
+
+ D("indexStat_toLocalStat");
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, impl_req->indexId);
+ ndbrequire(indexPtr.p->isOrderedIndex());
+
+ Callback c = {
+ safe_cast(&Dbdict::indexStat_fromLocalStat),
+ op_ptr.p->op_key
+ };
+ op_ptr.p->m_callback = c;
+
+ IndexStatImplReq* req = (IndexStatImplReq*)signal->getDataPtrSend();
+ *req = *impl_req;
+ req->senderRef = reference();
+ req->senderData = op_ptr.p->op_key;
+ ndbrequire(req->fragId == ZNIL);
+ ndbrequire(indexPtr.p->indexStatFragId != ZNIL);
+ BlockReference ref = 0;
+
+ switch (impl_req->requestType) {
+ case IndexStatReq::RT_SCAN_FRAG:
+ req->fragId = indexPtr.p->indexStatFragId;
+ if (indexPtr.p->indexStatNodeId != getOwnNodeId()) {
+ jam();
+ D("skip" << V(impl_req->requestType));
+ execute(signal, c, 0);
+ return;
+ }
+ ref = TRIX_REF;
+ break;
+
+ case IndexStatReq::RT_CLEAN_NEW:
+ case IndexStatReq::RT_CLEAN_OLD:
+ case IndexStatReq::RT_CLEAN_ALL:
+ /*
+ * Index stats "v4" does scan deletes via TRIX-SUMA. But SUMA does
+ * only local scans so do it on all nodes.
+ */
+ req->fragId = ZNIL;
+ ref = TRIX_REF;
+ break;
+
+ case IndexStatReq::RT_DROP_HEAD:
+ req->fragId = indexPtr.p->indexStatFragId;
+ if (indexPtr.p->indexStatNodeId != getOwnNodeId()) {
+ jam();
+ D("skip" << V(impl_req->requestType));
+ execute(signal, c, 0);
+ return;
+ }
+ ref = TRIX_REF;
+ break;
+
+ case IndexStatReq::RT_START_MON:
+ req->fragId = indexPtr.p->indexStatFragId;
+ if (indexPtr.p->indexStatNodeId != getOwnNodeId()) {
+ jam();
+ req->fragId = ZNIL;
+ }
+ ref = DBTUX_REF;
+ break;
+
+ case IndexStatReq::RT_STOP_MON:
+ req->fragId = ZNIL;
+ ref = DBTUX_REF;
+ break;
+
+ default:
+ ndbrequire(false); // only sub-ops seen here
+ break;
+ }
+
+ sendSignal(ref, GSN_INDEX_STAT_IMPL_REQ,
+ signal, IndexStatImplReq::SignalLength, JBB);
+}
+
+void
+Dbdict::indexStat_fromLocalStat(Signal* signal, Uint32 op_key, Uint32 ret)
+{
+ SchemaOpPtr op_ptr;
+ IndexStatRecPtr indexStatPtr;
+ findSchemaOp(op_ptr, indexStatPtr, op_key);
+ ndbrequire(!op_ptr.isNull());
+ const IndexStatImplReq* impl_req = &indexStatPtr.p->m_request;
+
+ if (ret != 0) {
+ jam();
+ if (impl_req->requestType != IndexStatReq::RT_CLEAN_OLD &&
+ impl_req->requestType != IndexStatReq::RT_CLEAN_ALL &&
+ impl_req->requestType != IndexStatReq::RT_DROP_HEAD) {
+ jam();
+ setError(op_ptr, ret, __LINE__);
+ sendTransRef(signal, op_ptr);
+ return;
+ }
+ D("ignore failed index stat cleanup");
+ }
+ sendTransConf(signal, op_ptr);
+}
+
+// IndexStat: COMMIT
+
+void
+Dbdict::indexStat_commit(Signal* signal, SchemaOpPtr op_ptr)
+{
+ jam();
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ D("indexStat_commit" << *op_ptr.p);
+ sendTransConf(signal, op_ptr);
+}
+
+// IndexStat: COMPLETE
+
+void
+Dbdict::indexStat_complete(Signal* signal, SchemaOpPtr op_ptr)
+{
+ jam();
+ IndexStatRecPtr indexStatPtr;
+ getOpRec(op_ptr, indexStatPtr);
+ D("indexStat_complete" << *op_ptr.p);
+ sendTransConf(signal, op_ptr);
+}
+
+// IndexStat: ABORT
+
+void
+Dbdict::indexStat_abortParse(Signal* signal, SchemaOpPtr op_ptr)
+{
+ D("indexStat_abortParse" << *op_ptr.p);
+ // wl3600_todo
+ sendTransConf(signal, op_ptr);
+}
+
+void
+Dbdict::indexStat_abortPrepare(Signal* signal, SchemaOpPtr op_ptr)
+{
+ D("indexStat_abortPrepare" << *op_ptr.p);
+
+ // nothing to do, entire index table will be dropped
+ sendTransConf(signal, op_ptr);
+}
+
+// IndexStat: MISC
+
+void
+Dbdict::execINDEX_STAT_CONF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatConf* conf = (const IndexStatConf*)signal->getDataPtr();
+ handleDictConf(signal, conf);
+}
+
+void
+Dbdict::execINDEX_STAT_REF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatRef* ref = (const IndexStatRef*)signal->getDataPtr();
+ handleDictRef(signal, ref);
+}
+
+void
+Dbdict::execINDEX_STAT_IMPL_CONF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplConf* conf = (const IndexStatImplConf*)signal->getDataPtr();
+ handleDictConf(signal, conf);
+}
+
+void
+Dbdict::execINDEX_STAT_IMPL_REF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplRef* ref = (const IndexStatImplRef*)signal->getDataPtr();
+ handleDictRef(signal, ref);
+}
+
+// IndexStat: background processing
+
+/*
+ * Receive report that an index needs stats update. Request to
+ * non-master is sent to master. Index is marked for stats update.
+ * Invalid request is simply ignored. Master-NF really need not be
+ * handled but could be, by broadcasting all reports to all DICTs.
+ */
+void
+Dbdict::execINDEX_STAT_REP(Signal* signal)
+{
+ const IndexStatRep* rep = (const IndexStatRep*)signal->getDataPtr();
+
+ // non-master
+ if (c_masterNodeId != getOwnNodeId()) {
+ jam();
+ BlockReference dictRef = calcDictBlockRef(c_masterNodeId);
+ sendSignal(dictRef, GSN_INDEX_STAT_REP, signal,
+ IndexStatRep::SignalLength, JBB);
+ return;
+ }
+
+ // check
+ TableRecordPtr indexPtr;
+ if (rep->indexId >= c_tableRecordPool.getSize()) {
+ jam();
+ return;
+ }
+ XSchemaFile* xsf = &c_schemaFile[SchemaRecord::NEW_SCHEMA_FILE];
+ const SchemaFile::TableEntry* te = getTableEntry(xsf, rep->indexId);
+ if (te->m_tableState != SchemaFile::SF_IN_USE) {
+ jam();
+ return;
+ }
+ c_tableRecordPool.getPtr(indexPtr, rep->indexId);
+ if (rep->indexVersion != 0 &&
+ rep->indexVersion != indexPtr.p->tableVersion) {
+ jam();
+ return;
+ }
+ if (!indexPtr.p->isOrderedIndex()) {
+ jam();
+ return;
+ }
+ if (rep->requestType != IndexStatRep::RT_UPDATE_REQ) {
+ jam();
+ return;
+ }
+
+ D("index stat: " << copyRope<MAX_TAB_NAME_SIZE>(indexPtr.p->tableName)
+ << " request type:" << rep->requestType);
+
+ infoEvent("DICT: index %u stats auto-update requested", indexPtr.i);
+ indexPtr.p->indexStatBgRequest = rep->requestType;
+}
+
+void
+Dbdict::indexStatBg_process(Signal* signal)
+{
+ if (!c_indexStatAutoUpdate ||
+ c_masterNodeId != getOwnNodeId() ||
+ getNodeState().startLevel != NodeState::SL_STARTED) {
+ jam();
+ indexStatBg_sendContinueB(signal);
+ return;
+ }
+
+ D("indexStatBg_process" << V(c_indexStatBgId));
+ const uint maxloop = 32;
+ uint loop;
+ for (loop = 0; loop < maxloop; loop++, c_indexStatBgId++) {
+ jam();
+ c_indexStatBgId %= c_tableRecordPool.getSize();
+
+ // check
+ TableRecordPtr indexPtr;
+ XSchemaFile* xsf = &c_schemaFile[SchemaRecord::NEW_SCHEMA_FILE];
+ const SchemaFile::TableEntry* te = getTableEntry(xsf, c_indexStatBgId);
+ if (te->m_tableState != SchemaFile::SF_IN_USE) {
+ jam();
+ continue;
+ }
+ c_tableRecordPool.getPtr(indexPtr, c_indexStatBgId);
+ if (!indexPtr.p->isOrderedIndex()) {
+ jam();
+ continue;
+ }
+ if (indexPtr.p->indexStatBgRequest == 0) {
+ jam();
+ continue;
+ }
+ ndbrequire(indexPtr.p->indexStatBgRequest == IndexStatRep::RT_UPDATE_REQ);
+
+ TxHandlePtr tx_ptr;
+ if (!seizeTxHandle(tx_ptr)) {
+ jam();
+ return; // wait for one
+ }
+ Callback c = {
+ safe_cast(&Dbdict::indexStatBg_fromBeginTrans),
+ tx_ptr.p->tx_key
+ };
+ tx_ptr.p->m_callback = c;
+ beginSchemaTrans(signal, tx_ptr);
+ return;
+ }
+
+ indexStatBg_sendContinueB(signal);
+}
+
+void
+Dbdict::indexStatBg_fromBeginTrans(Signal* signal, Uint32 tx_key, Uint32 ret)
+{
+ D("indexStatBg_fromBeginTrans" << V(c_indexStatBgId) << V(tx_key) << V(ret));
+
+ TxHandlePtr tx_ptr;
+ findTxHandle(tx_ptr, tx_key);
+ ndbrequire(!tx_ptr.isNull());
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, c_indexStatBgId);
+
+ if (ret != 0) {
+ jam();
+ indexStatBg_sendContinueB(signal);
+ return;
+ }
+
+ Callback c = {
+ safe_cast(&Dbdict::indexStatBg_fromIndexStat),
+ tx_ptr.p->tx_key
+ };
+ tx_ptr.p->m_callback = c;
+
+ IndexStatReq* req = (IndexStatReq*)signal->getDataPtrSend();
+ req->clientRef = reference();
+ req->clientData = tx_ptr.p->tx_key;
+ req->transId = tx_ptr.p->m_transId;
+ req->transKey = tx_ptr.p->m_transKey;
+ req->requestInfo = IndexStatReq::RT_UPDATE_STAT;
+ req->requestFlag = 0;
+ req->indexId = c_indexStatBgId;
+ req->indexVersion = indexPtr.p->tableVersion;
+ req->tableId = indexPtr.p->primaryTableId;
+ sendSignal(reference(), GSN_INDEX_STAT_REQ,
+ signal, IndexStatReq::SignalLength, JBB);
+}
+
+void
+Dbdict::indexStatBg_fromIndexStat(Signal* signal, Uint32 tx_key, Uint32 ret)
+{
+ D("indexStatBg_fromIndexStat" << V(c_indexStatBgId) << V(tx_key) << (ret));
+
+ TxHandlePtr tx_ptr;
+ findTxHandle(tx_ptr, tx_key);
+ ndbrequire(!tx_ptr.isNull());
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, c_indexStatBgId);
+
+ if (ret != 0) {
+ jam();
+ setError(tx_ptr.p->m_error, ret, __LINE__);
+ warningEvent("DICT: index %u stats auto-update error: %d", indexPtr.i, ret);
+ }
+
+ Callback c = {
+ safe_cast(&Dbdict::indexStatBg_fromEndTrans),
+ tx_ptr.p->tx_key
+ };
+ tx_ptr.p->m_callback = c;
+
+ Uint32 flags = 0;
+ if (hasError(tx_ptr.p->m_error))
+ flags |= SchemaTransEndReq::SchemaTransAbort;
+ endSchemaTrans(signal, tx_ptr, flags);
+}
+
+void
+Dbdict::indexStatBg_fromEndTrans(Signal* signal, Uint32 tx_key, Uint32 ret)
+{
+ D("indexStatBg_fromEndTrans" << V(c_indexStatBgId) << V(tx_key) << (ret));
+
+ TxHandlePtr tx_ptr;
+ findTxHandle(tx_ptr, tx_key);
+ ndbrequire(!tx_ptr.isNull());
+
+ TableRecordPtr indexPtr;
+ c_tableRecordPool.getPtr(indexPtr, c_indexStatBgId);
+
+ if (ret != 0) {
+ jam();
+ // skip over but leave the request on
+ warningEvent("DICT: index %u stats auto-update error: %d", indexPtr.i, ret);
+ } else {
+ jam();
+ // mark request done
+ indexPtr.p->indexStatBgRequest = 0;
+ infoEvent("DICT: index %u stats auto-update done", indexPtr.i);
+ }
+
+ releaseTxHandle(tx_ptr);
+ c_indexStatBgId++;
+ indexStatBg_sendContinueB(signal);
+}
+
+void
+Dbdict::indexStatBg_sendContinueB(Signal* signal)
+{
+ D("indexStatBg_sendContinueB" << V(c_indexStatBgId));
+ signal->theData[0] = ZINDEX_STAT_BG_PROCESS;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 1000, 1);
+}
+
+// IndexStat: END
+
// MODULE: CopyData
const Dbdict::OpInfo
@@ -23058,6 +24022,7 @@ Dbdict::g_opInfoList[] = {
&Dbdict::DropIndexRec::g_opInfo,
&Dbdict::AlterIndexRec::g_opInfo,
&Dbdict::BuildIndexRec::g_opInfo,
+ &Dbdict::IndexStatRec::g_opInfo,
&Dbdict::CreateFilegroupRec::g_opInfo,
&Dbdict::CreateFileRec::g_opInfo,
&Dbdict::DropFilegroupRec::g_opInfo,
@@ -23273,7 +24238,7 @@ Dbdict::seizeSchemaOp(SchemaOpPtr& op_pt
D("seizeSchemaOp" << V(op_key) << V(info.m_opType));
return true;
}
- c_schemaOpHash.release(op_ptr);
+ c_schemaOpPool.release(op_ptr);
}
}
op_ptr.setNull();
=== modified file 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp'
--- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2011-05-24 05:27:15 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp 2011-05-25 15:03:11 +0000
@@ -53,6 +53,7 @@
#include <signaldata/AlterIndxImpl.hpp>
#include <signaldata/BuildIndx.hpp>
#include <signaldata/BuildIndxImpl.hpp>
+#include <signaldata/IndexStatSignal.hpp>
#include <signaldata/UtilPrepare.hpp>
#include <signaldata/CreateEvnt.hpp>
#include <signaldata/CreateTrig.hpp>
@@ -94,6 +95,7 @@
#define ZDICT_TAKEOVER_REQ 5
#define ZCOMMIT_WAIT_GCI 6
+#define ZINDEX_STAT_BG_PROCESS 7
/*--------------------------------------------------------------*/
// Other constants in alphabetical order
@@ -405,6 +407,18 @@ public:
* Access rights to table during single user mode
*/
Uint8 singleUserMode;
+
+ /*
+ * Fragment and node to use for index statistics. Not part of
+ * DICTTABINFO. Computed locally by each DICT. If the node is
+ * down, no automatic stats update takes place. This is not
+ * critical and is not worth fixing.
+ */
+ Uint16 indexStatFragId;
+ Uint16 indexStatNodeId;
+
+ // pending background request (IndexStatRep::RequestType)
+ Uint32 indexStatBgRequest;
};
typedef Ptr<TableRecord> TableRecordPtr;
@@ -920,6 +934,14 @@ private:
void execDICT_TAKEOVER_REF(Signal* signal);
void execDICT_TAKEOVER_CONF(Signal* signal);
+ // ordered index statistics
+ void execINDEX_STAT_REQ(Signal* signal);
+ void execINDEX_STAT_CONF(Signal* signal);
+ void execINDEX_STAT_REF(Signal* signal);
+ void execINDEX_STAT_IMPL_CONF(Signal* signal);
+ void execINDEX_STAT_IMPL_REF(Signal* signal);
+ void execINDEX_STAT_REP(Signal* signal);
+
/*
* 2.4 COMMON STORED VARIABLES
*/
@@ -2615,10 +2637,12 @@ private:
return dict->c_alterIndexRecPool;
}
- // sub-operation counters
+ // sub-operation counters (true = done or skip)
const TriggerTmpl* m_triggerTmpl;
bool m_sub_trigger;
bool m_sub_build_index;
+ bool m_sub_index_stat_dml;
+ bool m_sub_index_stat_mon;
// prepare phase
bool m_tc_index_done;
@@ -2633,9 +2657,11 @@ private:
memset(&m_attrList, 0, sizeof(m_attrList));
m_attrMask.clear();
m_triggerTmpl = 0;
+ m_sub_trigger = false;
m_sub_build_index = false;
+ m_sub_index_stat_dml = false;
+ m_sub_index_stat_mon = false;
m_tc_index_done = false;
- m_sub_trigger = false;
}
#ifdef VM_TRACE
@@ -2662,6 +2688,9 @@ private:
void alterIndex_abortParse(Signal*, SchemaOpPtr);
void alterIndex_abortPrepare(Signal*, SchemaOpPtr);
+ // parse phase sub-routine
+ void set_index_stat_frag(Signal*, TableRecordPtr indexPtr);
+
// sub-ops
void alterIndex_toCreateTrigger(Signal*, SchemaOpPtr);
void alterIndex_atCreateTrigger(Signal*, SchemaOpPtr);
@@ -2671,6 +2700,8 @@ private:
void alterIndex_fromDropTrigger(Signal*, Uint32 op_key, Uint32 ret);
void alterIndex_toBuildIndex(Signal*, SchemaOpPtr);
void alterIndex_fromBuildIndex(Signal*, Uint32 op_key, Uint32 ret);
+ void alterIndex_toIndexStat(Signal*, SchemaOpPtr);
+ void alterIndex_fromIndexStat(Signal*, Uint32 op_key, Uint32 ret);
// prepare phase
void alterIndex_toCreateLocal(Signal*, SchemaOpPtr);
@@ -2762,6 +2793,69 @@ private:
void buildIndex_toLocalOnline(Signal*, SchemaOpPtr);
void buildIndex_fromLocalOnline(Signal*, Uint32 op_key, Uint32 ret);
+ // MODULE: IndexStat
+
+ struct IndexStatRec : public OpRec {
+ static const OpInfo g_opInfo;
+
+ static ArrayPool<Dbdict::IndexStatRec>&
+ getPool(Dbdict* dict) {
+ return dict->c_indexStatRecPool;
+ }
+
+ IndexStatImplReq m_request;
+
+ // sub-operation counters
+ const TriggerTmpl* m_triggerTmpl;
+ Uint32 m_subOpCount;
+ Uint32 m_subOpIndex;
+
+ IndexStatRec() :
+ OpRec(g_opInfo, (Uint32*)&m_request) {
+ memset(&m_request, 0, sizeof(m_request));
+ m_subOpCount = 0;
+ m_subOpIndex = 0;
+ }
+ };
+
+ typedef Ptr<IndexStatRec> IndexStatRecPtr;
+ ArrayPool<IndexStatRec> c_indexStatRecPool;
+
+ Uint32 c_indexStatAutoCreate;
+ Uint32 c_indexStatAutoUpdate;
+ Uint32 c_indexStatBgId;
+
+ // OpInfo
+ bool indexStat_seize(SchemaOpPtr);
+ void indexStat_release(SchemaOpPtr);
+ //
+ void indexStat_parse(Signal*, bool master,
+ SchemaOpPtr, SectionHandle&, ErrorInfo&);
+ bool indexStat_subOps(Signal*, SchemaOpPtr);
+ void indexStat_reply(Signal*, SchemaOpPtr, ErrorInfo);
+ //
+ void indexStat_prepare(Signal*, SchemaOpPtr);
+ void indexStat_commit(Signal*, SchemaOpPtr);
+ void indexStat_complete(Signal*, SchemaOpPtr);
+ //
+ void indexStat_abortParse(Signal*, SchemaOpPtr);
+ void indexStat_abortPrepare(Signal*, SchemaOpPtr);
+
+ // parse phase
+ void indexStat_toIndexStat(Signal*, SchemaOpPtr, Uint32 requestType);
+ void indexStat_fromIndexStat(Signal*, Uint32 op_key, Uint32 ret);
+
+ // prepare phase
+ void indexStat_toLocalStat(Signal*, SchemaOpPtr);
+ void indexStat_fromLocalStat(Signal*, Uint32 op_key, Uint32 ret);
+
+ // background processing of stat requests
+ void indexStatBg_process(Signal*);
+ void indexStatBg_fromBeginTrans(Signal*, Uint32 tx_key, Uint32 ret);
+ void indexStatBg_fromIndexStat(Signal*, Uint32 tx_key, Uint32 ret);
+ void indexStatBg_fromEndTrans(Signal*, Uint32 tx_key, Uint32 ret);
+ void indexStatBg_sendContinueB(Signal*);
+
// MODULE: CreateHashMap
struct HashMapRecord {
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2011-05-25 14:31:47 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp 2011-05-29 10:55:32 +0000
@@ -563,6 +563,8 @@ public:
Uint8 scanKeyinfoFlag;
Uint8 m_last_row;
Uint8 m_reserved;
+ Uint8 statScan;
+ Uint8 dummy[3]; // align?
}; // Size 272 bytes
typedef Ptr<ScanRecord> ScanRecordPtr;
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2011-05-30 08:50:17 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2011-05-31 08:28:58 +0000
@@ -3397,6 +3397,8 @@ Dblqh::execREAD_PSEUDO_REQ(Signal* signa
break;
}
case AttributeHeader::RECORDS_IN_RANGE:
+ case AttributeHeader::INDEX_STAT_KEY:
+ case AttributeHeader::INDEX_STAT_VALUE:
{
jam();
// scanptr gets reset somewhere within the timeslice
@@ -10458,6 +10460,7 @@ void Dblqh::continueAfterReceivingAllAiL
AccScanReq::setLockMode(req->requestInfo, scanptr.p->scanLockMode);
AccScanReq::setReadCommittedFlag(req->requestInfo, scanptr.p->readCommitted);
AccScanReq::setDescendingFlag(req->requestInfo, scanptr.p->descending);
+ AccScanReq::setStatScanFlag(req->requestInfo, scanptr.p->statScan);
if (refToMain(tcConnectptr.p->clientBlockref) == BACKUP)
{
@@ -11529,6 +11532,7 @@ Uint32 Dblqh::initScanrec(const ScanFrag
scanptr.p->descending = descending;
scanptr.p->tupScan = tupScan;
scanptr.p->lcpScan = ScanFragReq::getLcpScanFlag(reqinfo);
+ scanptr.p->statScan = ScanFragReq::getStatScanFlag(reqinfo);
scanptr.p->scanState = ScanRecord::SCAN_FREE;
scanptr.p->scanFlag = ZFALSE;
scanptr.p->m_row_id.setNull();
=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2011-05-17 23:29:55 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2011-05-25 15:03:11 +0000
@@ -2476,7 +2476,8 @@ Dbtup::read_pseudo(const Uint32 * inBuff
Uint32* outBuffer = outBuf + ((outPos - 1) >> 2);
Uint32 sz;
- SignalT<4> signalT;
+ const Uint32 DataSz = MAX_INDEX_STAT_KEY_SIZE;
+ SignalT<DataSz> signalT;
Signal * signal = new (&signalT) Signal(0);
bzero(signal, sizeof(signalT));
switch(attrId){
@@ -2546,6 +2547,23 @@ Dbtup::read_pseudo(const Uint32 * inBuff
outBuffer[4] = signal->theData[3];
sz = 4;
break;
+ case AttributeHeader::INDEX_STAT_KEY:
+ case AttributeHeader::INDEX_STAT_VALUE:
+ {
+ signal->theData[0] = req_struct->operPtrP->userpointer;
+ signal->theData[1] = attrId;
+
+ EXECUTE_DIRECT(DBLQH, GSN_READ_PSEUDO_REQ, signal, 2);
+
+ const Uint8* src = (Uint8*)&signal->theData[0];
+ Uint32 byte_sz = 2 + src[0] + (src[1] << 8);
+ Uint8* dst = (Uint8*)&outBuffer[1];
+ memcpy(dst, src, byte_sz);
+ while (byte_sz % 4 != 0)
+ dst[byte_sz++] = 0;
+ sz = byte_sz / 4;
+ break;
+ }
case AttributeHeader::ROWID:
outBuffer[1] = req_struct->frag_page_id;
outBuffer[2] = req_struct->operPtrP->m_tuple_location.m_page_idx;
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp 2011-05-17 12:19:20 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp 2011-05-19 09:40:36 +0000
@@ -45,6 +45,7 @@
#include <signaldata/NextScan.hpp>
#include <signaldata/AccLock.hpp>
#include <signaldata/DumpStateOrd.hpp>
+#include <signaldata/IndexStatSignal.hpp>
// debug
#ifdef VM_TRACE
@@ -236,7 +237,6 @@ private:
Uint8 m_prefSize; // words in min prefix
Uint8 m_minOccup; // min entries in internal node
Uint8 m_maxOccup; // max entries in node
- Uint32 m_entryCount; // stat: current entries
TupLoc m_root; // root node
TreeHead();
// methods
@@ -386,6 +386,7 @@ private:
TreePos m_scanPos; // position
TreeEnt m_scanEnt; // latest entry found
Uint32 m_nodeScan; // next scan at node (single-linked)
+ Uint32 m_statOpPtrI; // RNIL unless this is a statistics scan
union {
Uint32 nextPool;
Uint32 nextList;
@@ -425,6 +426,8 @@ private:
Uint16 m_prefAttrs; // attributes in min prefix
Uint16 m_prefBytes; // max bytes in min prefix
KeySpec m_keySpec;
+ Uint32 m_statFragPtrI; // fragment to monitor if not RNIL
+ Uint32 m_statLoadTime; // load time of index stats
union {
bool m_storeNullKey;
Uint32 nextPool;
@@ -453,6 +456,9 @@ private:
Uint32 m_tupIndexFragPtrI;
Uint32 m_tupTableFragPtrI;
Uint32 m_accTableFragPtrI;
+ Uint64 m_entryCount; // current entries
+ Uint64 m_entryBytes; // sum of index key sizes
+ Uint64 m_entryOps; // ops since last index stats update
union {
Uint32 nextPool;
};
@@ -519,6 +525,76 @@ private:
void progError(int line, int cause, const char* file);
};
+ // stats scan
+ struct StatOp;
+ friend struct StatOp;
+ struct StatOp {
+ // the scan
+ Uint32 m_scanOpPtrI;
+ // parameters
+ Uint32 m_saveSize;
+ Uint32 m_saveScale;
+ Uint32 m_batchSize;
+ Uint32 m_estBytes;
+ // counters
+ Uint32 m_rowCount;
+ Uint32 m_batchCurr;
+ bool m_haveSample;
+ Uint32 m_sampleCount;
+ Uint32 m_keyBytes;
+ bool m_keyChange;
+ bool m_usePrev;
+ // metadata
+ enum { MaxKeyCount = MAX_INDEX_STAT_KEY_COUNT };
+ enum { MaxKeySize = MAX_INDEX_STAT_KEY_SIZE };
+ enum { MaxValueCount = MAX_INDEX_STAT_VALUE_COUNT };
+ enum { MaxValueSize = MAX_INDEX_STAT_VALUE_SIZE };
+ Uint32 m_keyCount;
+ Uint32 m_valueCount;
+ // pack
+ const KeySpec& m_keySpec;
+ NdbPack::Spec m_valueSpec;
+ NdbPack::Type m_valueSpecBuf[MaxValueCount];
+ // data previous current result
+ KeyData m_keyData1;
+ KeyData m_keyData2;
+ KeyData m_keyData;
+ NdbPack::Data m_valueData;
+ // buffers with one word for length bytes
+ Uint32 m_keyDataBuf1[1 + MaxKeySize];
+ Uint32 m_keyDataBuf2[1 + MaxKeySize];
+ Uint32 m_keyDataBuf[1 + MaxKeySize];
+ Uint32 m_valueDataBuf[1 + MaxValueCount];
+ // value collection
+ struct Value {
+ Uint32 m_rir;
+ Uint32 m_unq[MaxKeyCount];
+ Value();
+ };
+ Value m_value1;
+ Value m_value2;
+ union {
+ Uint32 nextPool;
+ };
+ StatOp(const Index&);
+ };
+ typedef Ptr<StatOp> StatOpPtr;
+ ArrayPool<StatOp> c_statOpPool;
+ RSS_AP_SNAPSHOT(c_statOpPool);
+
+ // stats monitor (shared by req data and continueB loop)
+ struct StatMon;
+ friend struct StatMon;
+ struct StatMon {
+ IndexStatImplReq m_req;
+ Uint32 m_requestType;
+ // continueB loop
+ Uint32 m_loopIndexId;
+ Uint32 m_loopDelay;
+ StatMon();
+ };
+ StatMon c_statMon;
+
// methods
/*
@@ -644,9 +720,26 @@ private:
* DbtuxStat.cpp
*/
void execREAD_PSEUDO_REQ(Signal* signal);
+ // one-round-trip tree-dive records in range
void statRecordsInRange(ScanOpPtr scanPtr, Uint32* out);
Uint32 getEntriesBeforeOrAfter(Frag& frag, TreePos pos, unsigned idir);
unsigned getPathToNode(NodeHandle node, Uint16* path);
+ // stats scan
+ int statScanInit(StatOpPtr, const Uint32* data, Uint32 len, Uint32* usedLen);
+ int statScanAddRow(StatOpPtr, TreeEnt ent);
+ void statScanReadKey(StatOpPtr, Uint32* out);
+ void statScanReadValue(StatOpPtr, Uint32* out);
+ void execINDEX_STAT_REP(Signal*); // from TRIX
+ // stats monitor request
+ void execINDEX_STAT_IMPL_REQ(Signal*);
+ void statMonStart(Signal*, StatMon&);
+ void statMonStop(Signal*, StatMon&);
+ void statMonConf(Signal*, StatMon&);
+ // stats monitor continueB loop
+ void statMonSendContinueB(Signal*);
+ void statMonExecContinueB(Signal*);
+ void statMonCheck(Signal*, StatMon&);
+ void statMonRep(Signal*, StatMon&);
/*
* DbtuxDebug.cpp
@@ -676,6 +769,8 @@ private:
friend class NdbOut& operator<<(NdbOut&, const Frag&);
friend class NdbOut& operator<<(NdbOut&, const FragOp&);
friend class NdbOut& operator<<(NdbOut&, const NodeHandle&);
+ friend class NdbOut& operator<<(NdbOut&, const StatOp&);
+ friend class NdbOut& operator<<(NdbOut&, const StatMon&);
FILE* debugFile;
NdbOut debugOut;
unsigned debugFlags;
@@ -684,7 +779,8 @@ private:
DebugMaint = 2, // log maintenance ops
DebugTree = 4, // log and check tree after each op
DebugScan = 8, // log scans
- DebugLock = 16 // log ACC locks
+ DebugLock = 16, // log ACC locks
+ DebugStat = 32 // log stats collection
};
STATIC_CONST( DataFillByte = 0xa2 );
STATIC_CONST( NodeFillByte = 0xa4 );
@@ -722,6 +818,14 @@ private:
struct TuxCtx c_ctx; // Global Tux context, for everything build MT-index build
+ // index stats
+ bool c_indexStatAutoUpdate;
+ Uint32 c_indexStatSaveSize;
+ Uint32 c_indexStatSaveScale;
+ Uint32 c_indexStatTriggerPct;
+ Uint32 c_indexStatTriggerScale;
+ Uint32 c_indexStatUpdateDelay;
+
// inlined utils
Uint32 getDescSize(const Index& index);
DescHead& getDescHead(const Index& index);
@@ -878,7 +982,6 @@ Dbtux::TreeHead::TreeHead() :
m_prefSize(0),
m_minOccup(0),
m_maxOccup(0),
- m_entryCount(0),
m_root()
{
}
@@ -956,7 +1059,8 @@ Dbtux::ScanOp::ScanOp() :
m_scanBound(),
m_scanPos(),
m_scanEnt(),
- m_nodeScan(RNIL)
+ m_nodeScan(RNIL),
+ m_statOpPtrI(RNIL)
{
}
@@ -974,6 +1078,8 @@ Dbtux::Index::Index() :
m_prefAttrs(0),
m_prefBytes(0),
m_keySpec(),
+ m_statFragPtrI(RNIL),
+ m_statLoadTime(0),
m_storeNullKey(false)
{
for (unsigned i = 0; i < MaxIndexFragments; i++) {
@@ -994,7 +1100,10 @@ Dbtux::Frag::Frag(ArrayPool<ScanOp>& sca
m_scanList(scanOpPool),
m_tupIndexFragPtrI(RNIL),
m_tupTableFragPtrI(RNIL),
- m_accTableFragPtrI(RNIL)
+ m_accTableFragPtrI(RNIL),
+ m_entryCount(0),
+ m_entryBytes(0),
+ m_entryOps(0)
{
}
@@ -1146,6 +1255,59 @@ Dbtux::NodeHandle::getEnt(unsigned pos)
return entList[pos];
}
+// stats
+
+inline
+Dbtux::StatOp::Value::Value()
+{
+ m_rir = 0;
+ Uint32 i;
+ for (i = 0; i < MaxKeyCount; i++)
+ m_unq[i] = 0;
+}
+
+inline
+Dbtux::StatOp::StatOp(const Index& index) :
+ m_scanOpPtrI(RNIL),
+ m_saveSize(0),
+ m_saveScale(0),
+ m_batchSize(0),
+ m_estBytes(0),
+ m_rowCount(0),
+ m_batchCurr(0),
+ m_haveSample(false),
+ m_sampleCount(0),
+ m_keyBytes(0),
+ m_keyChange(false),
+ m_usePrev(false),
+ m_keyCount(0),
+ m_valueCount(0),
+ m_keySpec(index.m_keySpec),
+ m_keyData1(m_keySpec, false, 2),
+ m_keyData2(m_keySpec, false, 2),
+ m_keyData(m_keySpec, false, 2),
+ m_valueData(m_valueSpec, false, 2),
+ m_value1(),
+ m_value2()
+{
+ m_valueSpec.set_buf(m_valueSpecBuf, MaxValueCount);
+ m_keyData1.set_buf(m_keyDataBuf1, sizeof(m_keyDataBuf1));
+ m_keyData2.set_buf(m_keyDataBuf2, sizeof(m_keyDataBuf2));
+ m_keyData.set_buf(m_keyDataBuf, sizeof(m_keyDataBuf));
+ m_valueData.set_buf(m_valueDataBuf, sizeof(m_valueDataBuf));
+}
+
+// Dbtux::StatMon
+
+inline
+Dbtux::StatMon::StatMon() :
+ m_requestType(0),
+ m_loopIndexId(0),
+ m_loopDelay(1000)
+{
+ memset(&m_req, 0, sizeof(m_req));
+}
+
// parameters for methods
#ifdef VM_TRACE
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxBuild.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxBuild.cpp 2011-05-17 12:19:20 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxBuild.cpp 2011-05-19 09:40:36 +0000
@@ -139,6 +139,9 @@ Dbtux::mt_buildIndexFragment(mt_BuildInd
ndbrequire(frag.m_freeLoc != NullTupLoc);
}
treeAdd(ctx, frag, treePos, ent);
+ frag.m_entryCount++;
+ frag.m_entryBytes += searchKey.get_data_len();
+ frag.m_entryOps++;
}
if (err < 0)
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp 2011-05-30 08:50:17 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp 2011-05-31 08:28:58 +0000
@@ -125,7 +125,7 @@ void Dbtux::execDBINFO_SCANREQ(Signal *s
/*
* 12001 log file 0-close 1-open 2-append 3-append to signal log
- * 12002 log flags 1-meta 2-maint 4-tree 8-scan
+ * 12002 log flags 1-meta 2-maint 4-tree 8-scan lock-16 stat-32
*/
void
Dbtux::execDUMP_STATE_ORD(Signal* signal)
@@ -425,6 +425,8 @@ operator<<(NdbOut& out, const Dbtux::Sca
out << " [savePointId " << dec << scan.m_savePointId << "]";
out << " [accLockOp " << hex << scan.m_accLockOp << "]";
out << " [accLockOps";
+ if (globalData.isNdbMtLqh)//TODO
+ return out;
{
DLFifoList<Dbtux::ScanLock>::Head head = scan.m_accLockOps;
LocalDLFifoList<Dbtux::ScanLock> list(tux->c_scanLockPool, head);
@@ -461,6 +463,8 @@ operator<<(NdbOut& out, const Dbtux::Ind
out << "[Index " << hex << &index;
out << " [tableId " << dec << index.m_tableId << "]";
out << " [numFrags " << dec << index.m_numFrags << "]";
+ if (globalData.isNdbMtLqh)//TODO
+ return out;
for (unsigned i = 0; i < index.m_numFrags; i++) {
out << " [frag " << dec << i << " ";
const Dbtux::Frag& frag = *tux->c_fragPool.getPtr(index.m_fragPtrI[i]);
@@ -472,6 +476,8 @@ operator<<(NdbOut& out, const Dbtux::Ind
out << " [numAttrs " << dec << index.m_numAttrs << "]";
out << " [prefAttrs " << dec << index.m_prefAttrs << "]";
out << " [prefBytes " << dec << index.m_prefBytes << "]";
+ out << " [statFragPtrI " << hex << index.m_statFragPtrI << "]";
+ out << " [statLoadTime " << dec << index.m_statLoadTime << "]";
out << "]";
return out;
}
@@ -483,6 +489,9 @@ operator<<(NdbOut& out, const Dbtux::Fra
out << " [tableId " << dec << frag.m_tableId << "]";
out << " [indexId " << dec << frag.m_indexId << "]";
out << " [fragId " << dec << frag.m_fragId << "]";
+ out << " [entryCount " << dec << frag.m_entryCount << "]";
+ out << " [entryBytes " << dec << frag.m_entryBytes << "]";
+ out << " [entryOps " << dec << frag.m_entryOps << "]";
out << " [tree " << frag.m_tree << "]";
out << "]";
return out;
@@ -525,5 +534,25 @@ operator<<(NdbOut& out, const Dbtux::Nod
out << "]";
return out;
}
+
+NdbOut&
+operator<<(NdbOut& out, const Dbtux::StatOp& stat)
+{
+ out << "[StatOp " << hex << &stat;
+ out << " [saveSize " << dec << stat.m_saveSize << "]";
+ out << " [saveScale " << dec << stat.m_saveScale << "]";
+ out << " [batchSize " << dec << stat.m_batchSize << "]";
+ out << "]";
+ return out;
+}
+
+NdbOut&
+operator<<(NdbOut& out, const Dbtux::StatMon& mon)
+{
+ out << "[StatMon";
+ out << " [loopIndexId " << dec << mon.m_loopIndexId << "]";
+ out << "]";
+ return out;
+}
#endif
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp 2011-05-30 08:50:17 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp 2011-05-31 08:28:58 +0000
@@ -31,7 +31,13 @@ Dbtux::Dbtux(Block_context& ctx, Uint32
debugFlags(0),
#endif
c_internalStartPhase(0),
- c_typeOfStart(NodeState::ST_ILLEGAL_TYPE)
+ c_typeOfStart(NodeState::ST_ILLEGAL_TYPE),
+ c_indexStatAutoUpdate(false),
+ c_indexStatSaveSize(0),
+ c_indexStatSaveScale(0),
+ c_indexStatTriggerPct(0),
+ c_indexStatTriggerScale(0),
+ c_indexStatUpdateDelay(0)
{
BLOCK_CONSTRUCTOR(Dbtux);
// verify size assumptions (also when release-compiled)
@@ -73,6 +79,8 @@ Dbtux::Dbtux(Block_context& ctx, Uint32
* DbtuxStat.cpp
*/
addRecSignal(GSN_READ_PSEUDO_REQ, &Dbtux::execREAD_PSEUDO_REQ);
+ addRecSignal(GSN_INDEX_STAT_REP, &Dbtux::execINDEX_STAT_REP);
+ addRecSignal(GSN_INDEX_STAT_IMPL_REQ, &Dbtux::execINDEX_STAT_IMPL_REQ);
/*
* DbtuxDebug.cpp
*/
@@ -102,6 +110,13 @@ Dbtux::execCONTINUEB(Signal* signal)
dropIndex(signal, indexPtr, data[2], data[3]);
}
break;
+ case TuxContinueB::StatMon:
+ {
+ Uint32 id = data[1];
+ ndbrequire(id == c_statMon.m_loopIndexId);
+ statMonExecContinueB(signal);
+ }
+ break;
default:
ndbrequire(false);
break;
@@ -143,8 +158,16 @@ Dbtux::execSTTOR(Signal* signal)
jam();
c_typeOfStart = signal->theData[7];
break;
+ return;
case 7:
c_internalStartPhase = 6;
+ /*
+ * config cannot yet be changed dynamically but we start the
+ * loop always anyway because the cost is minimal
+ */
+ c_statMon.m_loopIndexId = 0;
+ statMonSendContinueB(signal);
+ break;
default:
jam();
break;
@@ -190,6 +213,12 @@ Dbtux::execREAD_CONFIG_REQ(Signal* signa
Uint32 nAttribute;
Uint32 nScanOp;
Uint32 nScanBatch;
+ Uint32 nStatAutoUpdate;
+ Uint32 nStatSaveSize;
+ Uint32 nStatSaveScale;
+ Uint32 nStatTriggerPct;
+ Uint32 nStatTriggerScale;
+ Uint32 nStatUpdateDelay;
const ndb_mgm_configuration_iterator * p =
m_ctx.m_config.getOwnConfigIterator();
@@ -200,10 +229,23 @@ Dbtux::execREAD_CONFIG_REQ(Signal* signa
ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_ATTRIBUTE, &nAttribute));
ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_SCAN_OP, &nScanOp));
ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_BATCH_SIZE, &nScanBatch));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_AUTO_UPDATE,
+ &nStatAutoUpdate));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_SAVE_SIZE,
+ &nStatSaveSize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_SAVE_SCALE,
+ &nStatSaveScale));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_TRIGGER_PCT,
+ &nStatTriggerPct));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_TRIGGER_SCALE,
+ &nStatTriggerScale));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_INDEX_STAT_UPDATE_DELAY,
+ &nStatUpdateDelay));
const Uint32 nDescPage = (nIndex * DescHeadSize + nAttribute * KeyTypeSize + nAttribute * AttributeHeaderSize + DescPageSize - 1) / DescPageSize;
const Uint32 nScanBoundWords = nScanOp * ScanBoundSegmentSize * 4;
const Uint32 nScanLock = nScanOp * nScanBatch;
+ const Uint32 nStatOp = 8;
c_indexPool.setSize(nIndex);
c_fragPool.setSize(nFragment);
@@ -212,6 +254,14 @@ Dbtux::execREAD_CONFIG_REQ(Signal* signa
c_scanOpPool.setSize(nScanOp);
c_scanBoundPool.setSize(nScanBoundWords);
c_scanLockPool.setSize(nScanLock);
+ c_statOpPool.setSize(nStatOp);
+ c_indexStatAutoUpdate = nStatAutoUpdate;
+ c_indexStatSaveSize = nStatSaveSize;
+ c_indexStatSaveScale = nStatSaveScale;
+ c_indexStatTriggerPct = nStatTriggerPct;
+ c_indexStatTriggerScale = nStatTriggerScale;
+ c_indexStatUpdateDelay = nStatUpdateDelay;
+
/*
* Index id is physical array index. We seize and initialize all
* index records now.
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp 2011-05-04 11:58:38 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp 2011-05-19 09:40:36 +0000
@@ -128,6 +128,9 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
ndbrequire(frag.m_freeLoc != NullTupLoc);
}
treeAdd(c_ctx, frag, treePos, ent);
+ frag.m_entryCount++;
+ frag.m_entryBytes += searchKey.get_data_len();
+ frag.m_entryOps++;
break;
case TuxMaintReq::OpRemove:
jam();
@@ -147,6 +150,10 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
break;
}
treeRemove(frag, treePos);
+ ndbrequire(frag.m_entryCount != 0);
+ frag.m_entryCount--;
+ frag.m_entryBytes -= searchKey.get_data_len();
+ frag.m_entryOps++;
break;
default:
ndbrequire(false);
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.cpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.cpp 2011-05-25 06:42:30 +0000
@@ -15,6 +15,7 @@
#include "DbtuxProxy.hpp"
#include "Dbtux.hpp"
+#include "../dblqh/DblqhCommon.hpp"
DbtuxProxy::DbtuxProxy(Block_context& ctx) :
LocalProxy(DBTUX, ctx)
@@ -23,6 +24,14 @@ DbtuxProxy::DbtuxProxy(Block_context& ct
addRecSignal(GSN_ALTER_INDX_IMPL_REQ, &DbtuxProxy::execALTER_INDX_IMPL_REQ);
addRecSignal(GSN_ALTER_INDX_IMPL_CONF, &DbtuxProxy::execALTER_INDX_IMPL_CONF);
addRecSignal(GSN_ALTER_INDX_IMPL_REF, &DbtuxProxy::execALTER_INDX_IMPL_REF);
+
+ // GSN_INDEX_STAT_IMPL_REQ
+ addRecSignal(GSN_INDEX_STAT_IMPL_REQ, &DbtuxProxy::execINDEX_STAT_IMPL_REQ);
+ addRecSignal(GSN_INDEX_STAT_IMPL_CONF, &DbtuxProxy::execINDEX_STAT_IMPL_CONF);
+ addRecSignal(GSN_INDEX_STAT_IMPL_REF, &DbtuxProxy::execINDEX_STAT_IMPL_REF);
+
+ // GSN_INDEX_STAT_REP
+ addRecSignal(GSN_INDEX_STAT_REP, &DbtuxProxy::execINDEX_STAT_REP);
}
DbtuxProxy::~DbtuxProxy()
@@ -107,4 +116,176 @@ DbtuxProxy::sendALTER_INDX_IMPL_CONF(Sig
ssRelease<Ss_ALTER_INDX_IMPL_REQ>(ssId);
}
+// GSN_INDEX_STAT_IMPL_REQ
+
+void
+DbtuxProxy::execINDEX_STAT_IMPL_REQ(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplReq* req =
+ (const IndexStatImplReq*)signal->getDataPtr();
+ Ss_INDEX_STAT_IMPL_REQ& ss = ssSeize<Ss_INDEX_STAT_IMPL_REQ>();
+ ss.m_req = *req;
+ ndbrequire(signal->getLength() == IndexStatImplReq::SignalLength);
+ sendREQ(signal, ss);
+}
+
+void
+DbtuxProxy::sendINDEX_STAT_IMPL_REQ(Signal* signal, Uint32 ssId,
+ SectionHandle*)
+{
+ Ss_INDEX_STAT_IMPL_REQ& ss = ssFind<Ss_INDEX_STAT_IMPL_REQ>(ssId);
+
+ IndexStatImplReq* req = (IndexStatImplReq*)signal->getDataPtrSend();
+ *req = ss.m_req;
+ req->senderRef = reference();
+ req->senderData = ssId;
+
+ const Uint32 instance = workerInstance(ss.m_worker);
+ NdbLogPartInfo lpinfo(instance);
+
+ //XXX remove unused
+ switch (req->requestType) {
+ case IndexStatReq::RT_START_MON:
+ /*
+ * DICT sets fragId if assigned frag is on this node, or else ZNIL
+ * to turn off any possible old assignment. In MT-LQH we also have
+ * to check which worker owns the frag.
+ */
+ if (req->fragId != ZNIL
+ && !lpinfo.partNoOwner(req->indexId, req->fragId)) {
+ jam();
+ req->fragId = ZNIL;
+ }
+ break;
+ case IndexStatReq::RT_STOP_MON:
+ /*
+ * DICT sets fragId to ZNIL always. There is no (pointless) check
+ * to see if the frag was ever assigned.
+ */
+ ndbrequire(req->fragId == ZNIL);
+ break;
+ case IndexStatReq::RT_SCAN_FRAG:
+ ndbrequire(req->fragId != ZNIL);
+ if (!lpinfo.partNoOwner(req->indexId, req->fragId)) {
+ jam();
+ skipReq(ss);
+ return;
+ }
+ break;
+ case IndexStatReq::RT_CLEAN_NEW:
+ case IndexStatReq::RT_CLEAN_OLD:
+ case IndexStatReq::RT_CLEAN_ALL:
+ ndbrequire(req->fragId == ZNIL);
+ break;
+ case IndexStatReq::RT_DROP_HEAD:
+ /*
+ * Only one client can do the PK-delete of the head record. We use
+ * of course the worker which owns the assigned fragment.
+ */
+ ndbrequire(req->fragId != ZNIL);
+ if (!lpinfo.partNoOwner(req->indexId, req->fragId)) {
+ jam();
+ skipReq(ss);
+ return;
+ }
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+
+ sendSignal(workerRef(ss.m_worker), GSN_INDEX_STAT_IMPL_REQ,
+ signal, IndexStatImplReq::SignalLength, JBB);
+}
+
+void
+DbtuxProxy::execINDEX_STAT_IMPL_CONF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplConf* conf =
+ (const IndexStatImplConf*)signal->getDataPtr();
+ Uint32 ssId = conf->senderData;
+ Ss_INDEX_STAT_IMPL_REQ& ss = ssFind<Ss_INDEX_STAT_IMPL_REQ>(ssId);
+ recvCONF(signal, ss);
+}
+
+void
+DbtuxProxy::execINDEX_STAT_IMPL_REF(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplRef* ref = (const IndexStatImplRef*)signal->getDataPtr();
+ Uint32 ssId = ref->senderData;
+ Ss_INDEX_STAT_IMPL_REQ& ss = ssFind<Ss_INDEX_STAT_IMPL_REQ>(ssId);
+ recvREF(signal, ss, ref->errorCode);
+}
+
+void
+DbtuxProxy::sendINDEX_STAT_IMPL_CONF(Signal* signal, Uint32 ssId)
+{
+ Ss_INDEX_STAT_IMPL_REQ& ss = ssFind<Ss_INDEX_STAT_IMPL_REQ>(ssId);
+ BlockReference dictRef = ss.m_req.senderRef;
+
+ if (!lastReply(ss))
+ return;
+
+ if (ss.m_error == 0) {
+ jam();
+ IndexStatImplConf* conf = (IndexStatImplConf*)signal->getDataPtrSend();
+ conf->senderRef = reference();
+ conf->senderData = ss.m_req.senderData;
+ sendSignal(dictRef, GSN_INDEX_STAT_IMPL_CONF,
+ signal, IndexStatImplConf::SignalLength, JBB);
+ } else {
+ IndexStatImplRef* ref = (IndexStatImplRef*)signal->getDataPtrSend();
+ ref->senderRef = reference();
+ ref->senderData = ss.m_req.senderData;
+ ref->errorCode = ss.m_error;
+ sendSignal(dictRef, GSN_INDEX_STAT_IMPL_REF,
+ signal, IndexStatImplRef::SignalLength, JBB);
+ }
+
+ ssRelease<Ss_INDEX_STAT_IMPL_REQ>(ssId);
+}
+
+// GSN_INDEX_STAT_REP
+
+void
+DbtuxProxy::execINDEX_STAT_REP(Signal* signal)
+{
+ jamEntry();
+ const IndexStatRep* rep =
+ (const IndexStatRep*)signal->getDataPtr();
+ Ss_INDEX_STAT_REP& ss = ssSeize<Ss_INDEX_STAT_REP>();
+ ss.m_rep = *rep;
+ ndbrequire(signal->getLength() == IndexStatRep::SignalLength);
+ sendREQ(signal, ss);
+ ssRelease<Ss_INDEX_STAT_REP>(ss);
+}
+
+void
+DbtuxProxy::sendINDEX_STAT_REP(Signal* signal, Uint32 ssId,
+ SectionHandle*)
+{
+ Ss_INDEX_STAT_REP& ss = ssFind<Ss_INDEX_STAT_REP>(ssId);
+
+ IndexStatRep* rep = (IndexStatRep*)signal->getDataPtrSend();
+ *rep = ss.m_rep;
+ rep->senderData = reference();
+ rep->senderData = ssId;
+
+ const Uint32 instance = workerInstance(ss.m_worker);
+ NdbLogPartInfo lpinfo(instance);
+
+ ndbrequire(rep->fragId != ZNIL);
+ if (!lpinfo.partNoOwner(rep->indexId, rep->fragId)) {
+ jam();
+ skipReq(ss);
+ return;
+ }
+
+ sendSignal(workerRef(ss.m_worker), GSN_INDEX_STAT_REP,
+ signal, IndexStatRep::SignalLength, JBB);
+}
+
BLOCK_FUNCTIONS(DbtuxProxy)
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.hpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.hpp 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxProxy.hpp 2011-05-25 06:42:30 +0000
@@ -19,6 +19,7 @@
#include <LocalProxy.hpp>
#include <signaldata/AlterIndxImpl.hpp>
#include <signaldata/DropTab.hpp>
+#include <signaldata/IndexStatSignal.hpp>
class DbtuxProxy : public LocalProxy {
public:
@@ -47,6 +48,41 @@ protected:
void execALTER_INDX_IMPL_CONF(Signal*);
void execALTER_INDX_IMPL_REF(Signal*);
void sendALTER_INDX_IMPL_CONF(Signal*, Uint32 ssId);
+
+ // GSN_INDEX_STAT_IMPL_REQ
+ struct Ss_INDEX_STAT_IMPL_REQ : SsParallel {
+ IndexStatImplReq m_req;
+ Ss_INDEX_STAT_IMPL_REQ() {
+ m_sendREQ = (SsFUNCREQ)&DbtuxProxy::sendINDEX_STAT_IMPL_REQ;
+ m_sendCONF = (SsFUNCREP)&DbtuxProxy::sendINDEX_STAT_IMPL_CONF;
+ }
+ enum { poolSize = 1 };
+ static SsPool<Ss_INDEX_STAT_IMPL_REQ>& pool(LocalProxy* proxy) {
+ return ((DbtuxProxy*)proxy)->c_ss_INDEX_STAT_IMPL_REQ;
+ }
+ };
+ SsPool<Ss_INDEX_STAT_IMPL_REQ> c_ss_INDEX_STAT_IMPL_REQ;
+ void execINDEX_STAT_IMPL_REQ(Signal*);
+ void sendINDEX_STAT_IMPL_REQ(Signal*, Uint32 ssId, SectionHandle*);
+ void execINDEX_STAT_IMPL_CONF(Signal*);
+ void execINDEX_STAT_IMPL_REF(Signal*);
+ void sendINDEX_STAT_IMPL_CONF(Signal*, Uint32 ssId);
+
+ // GSN_INDEX_STAT_REP
+ struct Ss_INDEX_STAT_REP : SsParallel {
+ IndexStatRep m_rep;
+ Ss_INDEX_STAT_REP() {
+ m_sendREQ = (SsFUNCREQ)&DbtuxProxy::sendINDEX_STAT_REP;
+ m_sendCONF = 0;
+ }
+ enum { poolSize = 1 };
+ static SsPool<Ss_INDEX_STAT_REP>& pool(LocalProxy* proxy) {
+ return ((DbtuxProxy*)proxy)->c_ss_INDEX_STAT_REP;
+ }
+ };
+ SsPool<Ss_INDEX_STAT_REP> c_ss_INDEX_STAT_REP;
+ void execINDEX_STAT_REP(Signal*);
+ void sendINDEX_STAT_REP(Signal*, Uint32 ssId, SectionHandle*);
};
#endif
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp 2011-05-30 08:50:17 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp 2011-05-31 08:28:58 +0000
@@ -95,6 +95,30 @@ Dbtux::execACC_SCANREQ(Signal* signal)
* 0 0 0 - read latest (read lock)
* 0 1 1 - read exclusive (write lock)
*/
+ const bool isStatScan = AccScanReq::getStatScanFlag(req->requestInfo);
+ if (unlikely(isStatScan)) {
+ jam();
+ if (!scanPtr.p->m_readCommitted) {
+ jam();
+ errorCode = AccScanRef::TuxInvalidLockMode;
+ break;
+ }
+ StatOpPtr statPtr;
+ if (!c_statOpPool.seize(statPtr)) {
+ jam();
+ errorCode = AccScanRef::TuxNoFreeStatOp;
+ break;
+ }
+ scanPtr.p->m_statOpPtrI = statPtr.i;
+ new (statPtr.p) StatOp(*indexPtr.p);
+ statPtr.p->m_scanOpPtrI = scanPtr.i;
+ // rest of StatOp is initialized in execTUX_BOUND_INFO
+#ifdef VM_TRACE
+ if (debugFlags & DebugStat) {
+ debugOut << "Seize stat op" << endl;
+ }
+#endif
+ }
#ifdef VM_TRACE
if (debugFlags & DebugScan) {
debugOut << "Seize scan " << scanPtr.i << " " << *scanPtr.p << endl;
@@ -144,10 +168,34 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal
jamEntry();
// get records
TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend();
- ScanOp& scan = *c_scanOpPool.getPtr(req->tuxScanPtrI);
+ ScanOpPtr scanPtr;
+ scanPtr.i = req->tuxScanPtrI;
+ c_scanOpPool.getPtr(scanPtr);
+ ScanOp& scan = *scanPtr.p;
const Index& index = *c_indexPool.getPtr(scan.m_indexId);
- //UNUSED const DescHead& descHead = getDescHead(index);
- //UNUSED const KeyType* keyTypes = getKeyTypes(descHead);
+ const DescHead& descHead = getDescHead(index);
+ const KeyType* keyTypes = getKeyTypes(descHead);
+ // data passed in Signal
+ const Uint32* const boundData = &req->data[0];
+ Uint32 boundLen = req->boundAiLength;
+ Uint32 boundOffset = 0;
+ // initialize stats scan
+ if (unlikely(scan.m_statOpPtrI != RNIL)) {
+ // stats options before bounds
+ StatOpPtr statPtr;
+ statPtr.i = scan.m_statOpPtrI;
+ c_statOpPool.getPtr(statPtr);
+ Uint32 usedLen = 0;
+ if (statScanInit(statPtr, boundData, boundLen, &usedLen) == -1) {
+ jam();
+ ndbrequire(scan.m_errorCode != 0);
+ req->errorCode = scan.m_errorCode;
+ return;
+ }
+ ndbrequire(usedLen <= boundLen);
+ boundLen -= usedLen;
+ boundOffset += usedLen;
+ }
// extract lower and upper bound in separate passes
for (unsigned idir = 0; idir <= 1; idir++) {
jam();
@@ -159,9 +207,9 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal
BoundInfo boundInfo[MaxIndexAttributes];
// largest attrId seen plus one
Uint32 maxAttrId = 0;
- const Uint32* const data = &req->data[0];
+ const Uint32* const data = &boundData[boundOffset];
Uint32 offset = 0;
- while (offset + 2 <= req->boundAiLength) {
+ while (offset + 2 <= boundLen) {
jam();
const Uint32 type = data[offset];
const AttributeHeader* ah = (const AttributeHeader*)&data[offset + 1];
@@ -210,7 +258,7 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal
// jump to next
offset += 2 + dataSize;
}
- if (unlikely(offset != req->boundAiLength)) {
+ if (unlikely(offset != boundLen)) {
jam();
scan.m_errorCode = TuxBoundInfo::InvalidAttrInfo;
req->errorCode = scan.m_errorCode;
@@ -798,7 +846,20 @@ Dbtux::scanFind(ScanOpPtr scanPtr)
NodeHandle node(frag);
selectNode(node, pos.m_loc);
const TreeEnt ent = node.getEnt(pos.m_pos);
- if (scanVisible(scanPtr, ent)) {
+ if (unlikely(scan.m_statOpPtrI != RNIL)) {
+ StatOpPtr statPtr;
+ statPtr.i = scan.m_statOpPtrI;
+ c_statOpPool.getPtr(statPtr);
+ // report row to stats, returns true if a sample is available
+ int ret = statScanAddRow(statPtr, ent);
+ if (ret == 1) {
+ jam();
+ scan.m_state = ScanOp::Found;
+ // may not access non-pseudo cols but must return valid ent
+ scan.m_scanEnt = ent;
+ break;
+ }
+ } else if (scanVisible(scanPtr, ent)) {
jam();
scan.m_state = ScanOp::Found;
scan.m_scanEnt = ent;
@@ -1205,6 +1266,13 @@ Dbtux::releaseScanOp(ScanOpPtr& scanPtr)
LocalDataBuffer<ScanBoundSegmentSize> b(c_scanBoundPool, head);
b.release();
}
+ if (unlikely(scanPtr.p->m_statOpPtrI != RNIL)) {
+ jam();
+ StatOpPtr statPtr;
+ statPtr.i = scanPtr.p->m_statOpPtrI;
+ c_statOpPool.getPtr(statPtr);
+ c_statOpPool.release(statPtr);
+ }
// unlink from per-fragment list and release from pool
frag.m_scanList.release(scanPtr);
}
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp 2011-05-04 12:08:38 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp 2011-05-24 17:54:07 +0000
@@ -18,6 +18,22 @@
#define DBTUX_STAT_CPP
#include "Dbtux.hpp"
+#include <math.h>
+
+// debug note: uses new-style debug macro "D" unlike rest of DBTUX
+// there is no filtering feature (yet) like "DebugStat"
+
+#ifdef VM_TRACE
+inline NdbOut&
+NdbOut::operator<<(double x)
+{
+ NdbOut& out = *this;
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%.02f", x);
+ out << buf;
+ return out;
+}
+#endif
void
Dbtux::execREAD_PSEUDO_REQ(Signal* signal)
@@ -26,14 +42,38 @@ Dbtux::execREAD_PSEUDO_REQ(Signal* signa
ScanOpPtr scanPtr;
scanPtr.i = signal->theData[0];
c_scanOpPool.getPtr(scanPtr);
- if (signal->theData[1] == AttributeHeader::RECORDS_IN_RANGE) {
+ StatOpPtr statPtr;
+ statPtr.i = scanPtr.p->m_statOpPtrI;
+
+ Uint32 attrId = signal->theData[1];
+ Uint32* out = &signal->theData[0];
+
+ switch (attrId) {
+ case AttributeHeader::RECORDS_IN_RANGE:
jam();
- statRecordsInRange(scanPtr, &signal->theData[0]);
- } else {
- ndbassert(false);
+ ndbrequire(statPtr.i == RNIL);
+ statRecordsInRange(scanPtr, out);
+ break;
+ case AttributeHeader::INDEX_STAT_KEY:
+ jam();
+ ndbrequire(statPtr.i != RNIL);
+ c_statOpPool.getPtr(statPtr);
+ statScanReadKey(statPtr, out);
+ break;
+ case AttributeHeader::INDEX_STAT_VALUE:
+ jam();
+ ndbrequire(statPtr.i != RNIL);
+ c_statOpPool.getPtr(statPtr);
+ statScanReadValue(statPtr, out);
+ break;
+ default:
+ ndbrequire(false);
+ break;
}
}
+// RECORDS_IN_RANGE
+
/*
* Estimate entries in range. Scan is at first entry. Search for last
* entry i.e. start of descending scan. Use the 2 positions to estimate
@@ -64,7 +104,8 @@ Dbtux::statRecordsInRange(ScanOpPtr scan
// committed read (same timeslice) and range not empty
ndbrequire(pos2.m_loc != NullTupLoc);
}
- out[0] = frag.m_tree.m_entryCount;
+ // wl4124_todo change all to Uint64 if ever needed (unlikely)
+ out[0] = (Uint32)frag.m_entryCount;
out[2] = getEntriesBeforeOrAfter(frag, pos1, 0);
out[3] = getEntriesBeforeOrAfter(frag, pos2, 1);
if (pos1.m_loc == pos2.m_loc) {
@@ -97,7 +138,7 @@ Dbtux::getEntriesBeforeOrAfter(Frag& fra
ndbrequire(depth != 0 && depth <= MaxTreeDepth);
TreeHead& tree = frag.m_tree;
Uint32 cnt = 0;
- Uint32 tot = tree.m_entryCount;
+ Uint32 tot = (Uint32)frag.m_entryCount;
unsigned i = 0;
// contribution from levels above
while (i + 1 < depth) {
@@ -155,3 +196,491 @@ Dbtux::getPathToNode(NodeHandle node, Ui
path[j] = 0xFFFF; // catch bug
return depth;
}
+
+// stats scan
+
+// windows has no log2
+static double
+tux_log2(double x)
+{
+ return ::log(x) / ::log((double)2.0);
+}
+
+int
+Dbtux::statScanInit(StatOpPtr statPtr, const Uint32* data, Uint32 len,
+ Uint32* usedLen)
+{
+ StatOp& stat = *statPtr.p;
+ ScanOp& scan = *c_scanOpPool.getPtr(stat.m_scanOpPtrI);
+ Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
+ const Index& index = *c_indexPool.getPtr(scan.m_indexId);
+ D("statScanInit");
+
+ // options
+ stat.m_saveSize = c_indexStatSaveSize;
+ stat.m_saveScale = c_indexStatSaveScale;
+ Uint32 offset = 0;
+ while (offset + 1 <= len)
+ {
+ const Uint32 type = data[offset];
+ const Uint32 value = data[offset + 1];
+ switch (type) {
+ case TuxBoundInfo::StatSaveSize:
+ jam();
+ stat.m_saveSize = value;
+ break;
+ case TuxBoundInfo::StatSaveScale:
+ jam();
+ stat.m_saveScale = value;
+ break;
+ default:
+ jam();
+ scan.m_errorCode = TuxBoundInfo::InvalidBounds;
+ return -1;
+ }
+ offset += 2;
+ }
+ *usedLen = offset;
+
+ // average key bytes as stored in stats
+ Uint32 avgKeyBytes = 0;
+ if (frag.m_entryCount != 0)
+ {
+ avgKeyBytes = (Uint32)(frag.m_entryBytes / frag.m_entryCount);
+ if (avgKeyBytes > stat.m_keySpec.get_max_data_len(false))
+ avgKeyBytes = stat.m_keySpec.get_max_data_len(false);
+ }
+
+ // compute batch size - see wl4124.txt
+ {
+ double a = stat.m_saveSize;
+ double b = stat.m_saveScale;
+ double c = avgKeyBytes;
+ double d = index.m_numAttrs;
+ double e = c + (1 + d) * 4; // approx size of one sample
+ double f = (double)frag.m_entryCount;
+ double g = f * e; // max possible sample bytes
+ if (g < 1.0)
+ g = 1.0;
+ double h = 1 + 0.01 * b * tux_log2(g); // scale factor
+ double i = a * h; // sample bytes allowed
+ double j = i / e; // sample count
+ double k = f / j; // sampling frequency
+ if (k < 1.0)
+ k = 1.0;
+ double l = e * f / k; // estimated sample bytes
+
+ stat.m_batchSize = (Uint32)(k + 0.5);
+ stat.m_estBytes = (Uint32)(l + 0.5);
+ ndbrequire(stat.m_batchSize != 0);
+ D("computed batch size" << V(stat));
+ }
+
+ // key spec is already defined as ref to index key spec
+ stat.m_keyCount = index.m_numAttrs;
+ stat.m_valueCount = 1 + stat.m_keyCount;
+ stat.m_keyData1.reset();
+ stat.m_keyData2.reset();
+
+ // define value spec
+ stat.m_valueCount = 1 + stat.m_keyCount;
+ NdbPack::Spec& valueSpec = stat.m_valueSpec;
+ valueSpec.reset();
+ {
+ NdbPack::Type type(NDB_TYPE_UNSIGNED, 4, false, 0);
+ int ret = valueSpec.add(type, stat.m_valueCount);
+ ndbrequire(ret == 0);
+ }
+
+ return 0;
+}
+
+int
+Dbtux::statScanAddRow(StatOpPtr statPtr, TreeEnt ent)
+{
+ StatOp& stat = *statPtr.p;
+ ScanOp& scan = *c_scanOpPool.getPtr(stat.m_scanOpPtrI);
+ Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
+ D("statScanAddRow" << V(stat));
+
+ KeyData& keyData1 = stat.m_keyData1;
+ KeyData& keyData2 = stat.m_keyData2;
+ StatOp::Value& value1 = stat.m_value1;
+ StatOp::Value& value2 = stat.m_value2;
+
+ stat.m_rowCount++;
+ stat.m_batchCurr++;
+ const bool firstRow = (stat.m_rowCount == 1);
+ int ret;
+
+ // save previous value
+ if (!firstRow) {
+ ret = keyData1.copy(keyData2);
+ ndbrequire(ret == 0);
+ value1 = value2;
+ }
+
+ // read current entry key
+ readKeyAttrs(c_ctx, frag, ent, keyData2, stat.m_keyCount);
+
+ // calculate new values
+ value2.m_rir = stat.m_rowCount;
+ if (firstRow)
+ {
+ for (Uint32 i = 0; i < stat.m_keyCount; i++)
+ value2.m_unq[i] = 1;
+ stat.m_keyChange = false;
+ }
+ else
+ {
+ // how many initial attrs are equal
+ Uint32 num_eq;
+ int res = keyData1.cmp(keyData2, stat.m_keyCount, num_eq);
+ ndbrequire(res <= 0);
+ stat.m_keyChange = (res != 0);
+
+ if (stat.m_keyChange)
+ {
+ ndbrequire(num_eq < stat.m_keyCount);
+ value2.m_unq[num_eq]++;
+ // propagate down
+ for (Uint32 i = num_eq + 1; i < stat.m_keyCount; i++)
+ value2.m_unq[i]++;
+ }
+ }
+
+ // always report last index entry
+ bool lastEntry = false;
+ do
+ {
+ NodeHandle node(frag);
+ TreePos pos = scan.m_scanPos;
+ selectNode(node, pos.m_loc);
+ // more entries in this node
+ const unsigned occup = node.getOccup();
+ // funny cast to avoid signed vs unsigned warning
+ if (pos.m_dir == 3 && pos.m_pos + (unsigned)1 < occup)
+ {
+ jam();
+ break;
+ }
+ // can continue to right sub-tree
+ if (node.getLink(1) != NullTupLoc)
+ {
+ jam();
+ break;
+ }
+ // while child on right
+ while (node.getSide() == 1)
+ {
+ jam();
+ TupLoc loc = node.getLink(2);
+ selectNode(node, loc);
+ }
+ // did not reach root
+ if (node.getSide() != 2)
+ {
+ jam();
+ break;
+ }
+ lastEntry = true;
+ }
+ while (0);
+
+ stat.m_usePrev = true;
+ if (lastEntry)
+ {
+ jam();
+ stat.m_usePrev = false;
+ return 1;
+ }
+ if (stat.m_batchCurr >= stat.m_batchSize && stat.m_keyChange)
+ {
+ jam();
+ stat.m_batchCurr = 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+Dbtux::statScanReadKey(StatOpPtr statPtr, Uint32* out)
+{
+ StatOp& stat = *statPtr.p;
+ int ret;
+
+ KeyData& keyData = stat.m_keyData;
+ ret = keyData.copy(stat.m_usePrev ? stat.m_keyData1 : stat.m_keyData2);
+ ndbrequire(ret == 0);
+ D("statScanReadKey" << V(keyData));
+ keyData.convert(NdbPack::Endian::Little);
+ memcpy(out, keyData.get_full_buf(), keyData.get_full_len());
+}
+
+void
+Dbtux::statScanReadValue(StatOpPtr statPtr, Uint32* out)
+{
+ StatOp& stat = *statPtr.p;
+ int ret;
+ Uint32 len_out;
+
+ const StatOp::Value& value = stat.m_usePrev ? stat.m_value1 : stat.m_value2;
+
+ // verify sanity
+ ndbrequire(value.m_rir != 0);
+ for (Uint32 k = 0; k < stat.m_keyCount; k++)
+ {
+ ndbrequire(value.m_unq[k] != 0);
+ ndbrequire(value.m_rir >= value.m_unq[k]);
+ ndbrequire(k == 0 || value.m_unq[k] >= value.m_unq[k - 1]);
+ }
+
+ NdbPack::Data& valueData = stat.m_valueData;
+ valueData.reset();
+
+ ret = valueData.add(&value.m_rir, &len_out);
+ ndbrequire(ret == 0 && len_out == 4);
+ ret = valueData.add(&value.m_unq[0], stat.m_keyCount, &len_out);
+ ndbrequire(ret == 0 && len_out == stat.m_keyCount * 4);
+ ret = valueData.finalize();
+ ndbrequire(ret == 0);
+
+ D("statScanReadValue" << V(valueData));
+ valueData.convert(NdbPack::Endian::Little);
+ memcpy(out, valueData.get_full_buf(), valueData.get_full_len());
+}
+
+// at end of stats update, TRIX sends loadTime
+void
+Dbtux::execINDEX_STAT_REP(Signal* signal)
+{
+ jamEntry();
+ const IndexStatRep* rep = (const IndexStatRep*)signal->getDataPtr();
+
+ switch (rep->requestType) {
+ case IndexStatRep::RT_UPDATE_REQ:
+ ndbrequire(false);
+ break;
+ case IndexStatRep::RT_UPDATE_CONF:
+ {
+ Index& index = *c_indexPool.getPtr(rep->indexId);
+ FragPtr fragPtr;
+ findFrag(index, rep->fragId, fragPtr);
+ ndbrequire(fragPtr.i != RNIL);
+ // index.m_statFragPtrI need not be defined yet
+ D("loadTime" << V(index.m_statLoadTime) << " ->" << V(rep->loadTime));
+ index.m_statLoadTime = rep->loadTime;
+ }
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+// stats monitor
+
+void
+Dbtux::execINDEX_STAT_IMPL_REQ(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplReq* req = (const IndexStatImplReq*)signal->getDataPtr();
+
+ StatMon& mon = c_statMon;
+ mon.m_req = *req;
+ mon.m_requestType = req->requestType;
+
+ switch (mon.m_requestType) {
+ case IndexStatReq::RT_START_MON:
+ statMonStart(signal, mon);
+ break;
+ case IndexStatReq::RT_STOP_MON:
+ statMonStop(signal, mon);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+void
+Dbtux::statMonStart(Signal* signal, StatMon& mon)
+{
+ const IndexStatImplReq* req = &mon.m_req;
+ Index& index = *c_indexPool.getPtr(req->indexId);
+ D("statMonStart" << V(mon));
+
+ // RT_START_MON also sends ZNIL to all non-monitoring nodes
+ if (req->fragId == ZNIL)
+ {
+ jam();
+ index.m_statFragPtrI = RNIL;
+ D("non-monitoring node");
+ }
+ else
+ {
+ jam();
+ FragPtr fragPtr;
+ findFrag(index, req->fragId, fragPtr);
+ ndbrequire(fragPtr.i != RNIL);
+ index.m_statFragPtrI = fragPtr.i;
+ fragPtr.p->m_entryOps = 0;
+ D("monitoring node" << V(index));
+ }
+
+ statMonConf(signal, mon);
+}
+
+void
+Dbtux::statMonStop(Signal* signal, StatMon& mon)
+{
+ const IndexStatImplReq* req = &mon.m_req;
+ Index& index = *c_indexPool.getPtr(req->indexId);
+ D("statMonStop" << V(mon));
+
+ // RT_STOP_MON simply sends ZNIL to every node
+ ndbrequire(req->fragId == ZNIL);
+ index.m_statFragPtrI = RNIL;
+
+ statMonConf(signal, mon);
+}
+
+void
+Dbtux::statMonConf(Signal* signal, StatMon& mon)
+{
+ const IndexStatImplReq* req = &mon.m_req;
+ D("statMonConf" << V(mon));
+
+ IndexStatImplConf* conf = (IndexStatImplConf*)signal->getDataPtrSend();
+ conf->senderRef = reference();
+ conf->senderData = req->senderData;
+ sendSignal(req->senderRef, GSN_INDEX_STAT_IMPL_CONF,
+ signal, IndexStatImplConf::SignalLength, JBB);
+}
+
+// continueB loop
+
+void
+Dbtux::statMonSendContinueB(Signal* signal)
+{
+ StatMon& mon = c_statMon;
+ D("statMonSendContinueB" << V(mon));
+
+ signal->theData[0] = TuxContinueB::StatMon;
+ signal->theData[1] = mon.m_loopIndexId;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB,
+ signal, mon.m_loopDelay, 2);
+}
+
+void
+Dbtux::statMonExecContinueB(Signal* signal)
+{
+ StatMon& mon = c_statMon;
+ D("statMonExecContinueB" << V(mon));
+
+ if (!c_indexStatAutoUpdate ||
+ c_indexStatTriggerPct == 0 ||
+ getNodeState().startLevel != NodeState::SL_STARTED)
+ {
+ }
+ else
+ {
+ jam();
+ statMonCheck(signal, mon);
+ }
+ statMonSendContinueB(signal);
+}
+
+void
+Dbtux::statMonCheck(Signal* signal, StatMon& mon)
+{
+ const Uint32 now = (Uint32)time(0);
+ D("statMonCheck" << V(mon) << V(now));
+
+ const uint maxloop = 32;
+ for (uint loop = 0; loop < maxloop; loop++, mon.m_loopIndexId++)
+ {
+ jam();
+ mon.m_loopIndexId %= c_indexPool.getSize();
+
+ const Index& index = *c_indexPool.getPtr(mon.m_loopIndexId);
+ if (index.m_state == Index::NotDefined ||
+ index.m_state == Index::Dropping ||
+ index.m_statFragPtrI == RNIL)
+ {
+ jam();
+ continue;
+ }
+ const Frag& frag = *c_fragPool.getPtr(index.m_statFragPtrI);
+
+ bool update = false;
+ if (index.m_statLoadTime == 0)
+ {
+ jam();
+ update = true;
+ D("statMonCheck" << V(update) << V(index.m_statLoadTime));
+ }
+ else if (now < index.m_statLoadTime + c_indexStatUpdateDelay)
+ {
+ jam();
+ update = false;
+ D("statMonCheck" << V(update) << V(index.m_statLoadTime));
+ }
+ else
+ {
+ const Uint64 count = frag.m_entryCount;
+ const Uint64 ops = frag.m_entryOps;
+ if (count <= 1)
+ {
+ jam();
+ update = (ops >= 1);
+ D("statMonCheck" << V(update) << V(ops));
+ }
+ else
+ {
+ jam();
+ // compute scaled percentags - see wl4124.txt
+ double a = c_indexStatTriggerPct;
+ double b = c_indexStatTriggerScale;
+ double c = (double)count;
+ double d = 1 + 0.01 * b * tux_log2(c); // inverse scale factor
+ double e = a / d; // scaled trigger pct
+ double f = (double)ops;
+ double g = 100.0 * f / c;
+ update = (g >= e);
+ D("statMonCheck" << V(update) << V(f) << V(c));
+ }
+ }
+
+ if (update)
+ {
+ jam();
+ statMonRep(signal, mon);
+ // advance index afterwards
+ mon.m_loopIndexId++;
+ break;
+ }
+ }
+}
+
+void
+Dbtux::statMonRep(Signal* signal, StatMon& mon)
+{
+ const Index& index = *c_indexPool.getPtr(mon.m_loopIndexId);
+ const Frag& frag = *c_fragPool.getPtr(index.m_statFragPtrI);
+ D("statMonRep" << V(mon));
+
+ IndexStatRep* rep = (IndexStatRep*)signal->getDataPtrSend();
+ rep->senderRef = reference();
+ rep->senderData = mon.m_loopIndexId;
+ rep->requestType = IndexStatRep::RT_UPDATE_REQ;
+ rep->requestFlag = 0;
+ rep->indexId = mon.m_loopIndexId;
+ rep->indexVersion = 0; // not required
+ rep->tableId = index.m_tableId;
+ rep->fragId = frag.m_fragId;
+ rep->loadTime = index.m_statLoadTime;
+
+ sendSignal(DBDICT_REF, GSN_INDEX_STAT_REP,
+ signal, IndexStatRep::SignalLength, JBB);
+}
=== modified file 'storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp 2011-05-19 09:40:36 +0000
@@ -49,7 +49,6 @@ Dbtux::treeAdd(TuxCtx& ctx, Frag& frag,
tree.m_root = node.m_loc;
break;
} while (0);
- tree.m_entryCount++;
}
/*
@@ -212,8 +211,6 @@ Dbtux::treeRemove(Frag& frag, TreePos tr
treeRemoveLeaf(frag, node);
break;
} while (0);
- ndbrequire(tree.m_entryCount != 0);
- tree.m_entryCount--;
}
/*
=== modified file 'storage/ndb/src/kernel/blocks/suma/Suma.cpp'
--- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp 2011-05-30 08:50:17 +0000
+++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp 2011-05-31 08:28:58 +0000
@@ -174,7 +174,12 @@ Suma::execREAD_CONFIG_REQ(Signal* signal
c_subOpPool.setSize(256);
c_syncPool.setSize(2);
- c_dataBufferPool.setSize(noAttrs);
+
+ // Trix: max 5 concurrent index stats ops with max 9 words bounds
+ Uint32 noOfBoundWords = 5 * 9;
+
+ // XXX multiplies number of words by 15 ???
+ c_dataBufferPool.setSize(noAttrs + noOfBoundWords);
c_maxBufferedEpochs = maxBufferedEpochs;
@@ -2292,6 +2297,7 @@ Suma::execSUB_SYNC_REQ(Signal* signal)
syncPtr.p->m_error = 0;
syncPtr.p->m_requestInfo = req->requestInfo;
syncPtr.p->m_frag_cnt = req->fragCount;
+ syncPtr.p->m_frag_id = req->fragId;
syncPtr.p->m_tableId = subPtr.p->m_tableId;
{
@@ -2302,8 +2308,17 @@ Suma::execSUB_SYNC_REQ(Signal* signal)
handle.getSection(ptr, SubSyncReq::ATTRIBUTE_LIST);
LocalDataBuffer<15> attrBuf(c_dataBufferPool, syncPtr.p->m_attributeList);
append(attrBuf, ptr, getSectionSegmentPool());
- releaseSections(handle);
}
+ if (req->requestInfo & SubSyncReq::RangeScan)
+ {
+ jam();
+ ndbrequire(handle.m_cnt > 1)
+ SegmentedSectionPtr ptr;
+ handle.getSection(ptr, SubSyncReq::TUX_BOUND_INFO);
+ LocalDataBuffer<15> boundBuf(c_dataBufferPool, syncPtr.p->m_boundInfo);
+ append(boundBuf, ptr, getSectionSegmentPool());
+ }
+ releaseSections(handle);
}
/**
@@ -2432,8 +2447,30 @@ Suma::execDIH_SCAN_GET_NODES_CONF(Signal
fd.m_fragDesc.m_nodeId = conf->nodes[0];
fd.m_fragDesc.m_fragmentNo = fragNo;
fd.m_fragDesc.m_lqhInstanceKey = conf->instanceKey;
- signal->theData[2] = fd.m_dummy;
- fragBuf.append(&signal->theData[2], 1);
+ if (ptr.p->m_frag_id == ZNIL)
+ {
+ signal->theData[2] = fd.m_dummy;
+ fragBuf.append(&signal->theData[2], 1);
+ }
+ else if (ptr.p->m_frag_id == fragNo)
+ {
+ /*
+ * Given fragment must have a replica on this node.
+ */
+ const Uint32 ownNodeId = getOwnNodeId();
+ Uint32 i = 0;
+ for (i = 0; i < nodeCount; i++)
+ if (conf->nodes[i] == ownNodeId)
+ break;
+ if (i == nodeCount)
+ {
+ sendSubSyncRef(signal, 1428);
+ return;
+ }
+ fd.m_fragDesc.m_nodeId = ownNodeId;
+ signal->theData[2] = fd.m_dummy;
+ fragBuf.append(&signal->theData[2], 1);
+ }
}
const Uint32 nextFrag = fragNo + 1;
@@ -2740,6 +2777,21 @@ Suma::SyncRecord::nextScan(Signal* signa
ScanFragReq::setTupScanFlag(req->requestInfo, 1);
}
+ if (m_requestInfo & SubSyncReq::LM_CommittedRead)
+ {
+ ScanFragReq::setReadCommittedFlag(req->requestInfo, 1);
+ }
+
+ if (m_requestInfo & SubSyncReq::RangeScan)
+ {
+ ScanFragReq::setRangeScanFlag(req->requestInfo, 1);
+ }
+
+ if (m_requestInfo & SubSyncReq::StatScan)
+ {
+ ScanFragReq::setStatScanFlag(req->requestInfo, 1);
+ }
+
req->fragmentNoKeyLen = fd.m_fragDesc.m_fragmentNo;
req->schemaVersion = tabPtr.p->m_schemaVersion;
req->transId1 = 0;
@@ -2763,10 +2815,25 @@ Suma::SyncRecord::nextScan(Signal* signa
AttributeHeader::init(&attrInfo[pos++], * it.data, 0);
}
LinearSectionPtr ptr[3];
+ Uint32 noOfSections;
ptr[0].p = attrInfo;
ptr[0].sz = pos;
+ noOfSections = 1;
+ if (m_requestInfo & SubSyncReq::RangeScan)
+ {
+ jam();
+ Uint32 oldpos = pos; // after attrInfo
+ LocalDataBuffer<15> boundBuf(suma.c_dataBufferPool, m_boundInfo);
+ for (boundBuf.first(it); !it.curr.isNull(); boundBuf.next(it))
+ {
+ attrInfo[pos++] = *it.data;
+ }
+ ptr[1].p = &attrInfo[oldpos];
+ ptr[1].sz = pos - oldpos;
+ noOfSections = 2;
+ }
suma.sendSignal(lqhRef, GSN_SCAN_FRAGREQ, signal,
- ScanFragReq::SignalLength, JBB, ptr, 1);
+ ScanFragReq::SignalLength, JBB, ptr, noOfSections);
m_currentNoOfAttributes = attrBuf.getSize();
@@ -5305,6 +5372,9 @@ Suma::SyncRecord::release(){
LocalDataBuffer<15> attrBuf(suma.c_dataBufferPool, m_attributeList);
attrBuf.release();
+
+ LocalDataBuffer<15> boundBuf(suma.c_dataBufferPool, m_boundInfo);
+ boundBuf.release();
}
=== modified file 'storage/ndb/src/kernel/blocks/suma/Suma.hpp'
--- a/storage/ndb/src/kernel/blocks/suma/Suma.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/kernel/blocks/suma/Suma.hpp 2011-05-19 09:38:03 +0000
@@ -171,6 +171,7 @@ public:
Uint32 m_requestInfo;
Uint32 m_frag_cnt; // only scan this many fragments...
+ Uint32 m_frag_id; // only scan this specific fragment...
Uint32 m_tableId; // redundant...
/**
@@ -185,6 +186,7 @@ public:
Uint32 m_currentFragment; // Index in tabPtr.p->m_fragments
Uint32 m_currentNoOfAttributes; // No of attributes for current table
DataBuffer<15>::Head m_attributeList; // Attribute if other than default
+ DataBuffer<15>::Head m_boundInfo; // For range scan
void startScan(Signal*);
void nextScan(Signal*);
=== modified file 'storage/ndb/src/kernel/blocks/trix/Trix.cpp'
--- a/storage/ndb/src/kernel/blocks/trix/Trix.cpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/kernel/blocks/trix/Trix.cpp 2011-05-31 08:28:58 +0000
@@ -108,6 +108,14 @@ Trix::Trix(Block_context& ctx) :
addRecSignal(GSN_WAIT_GCP_REF, &Trix::execWAIT_GCP_REF);
addRecSignal(GSN_WAIT_GCP_CONF, &Trix::execWAIT_GCP_CONF);
+
+ // index stats
+ addRecSignal(GSN_INDEX_STAT_IMPL_REQ, &Trix::execINDEX_STAT_IMPL_REQ);
+ addRecSignal(GSN_GET_TABINFO_CONF, &Trix::execGET_TABINFO_CONF);
+ addRecSignal(GSN_GET_TABINFOREF, &Trix::execGET_TABINFO_REF);
+
+ // index stats sys tables
+ c_statGetMetaDone = false;
}
/**
@@ -134,6 +142,7 @@ Trix::execREAD_CONFIG_REQ(Signal* signal
// Allocate pool sizes
c_theAttrOrderBufferPool.setSize(100);
c_theSubscriptionRecPool.setSize(100);
+ c_statOpPool.setSize(5);
DLList<SubscriptionRecord> subscriptions(c_theSubscriptionRecPool);
SubscriptionRecPtr subptr;
@@ -469,12 +478,14 @@ Trix::execDUMP_STATE_ORD(Signal* signal)
if (signal->theData[0] == DumpStateOrd::SchemaResourceSnapshot)
{
RSS_AP_SNAPSHOT_SAVE(c_theSubscriptionRecPool);
+ RSS_AP_SNAPSHOT_SAVE(c_statOpPool);
return;
}
if (signal->theData[0] == DumpStateOrd::SchemaResourceCheckLeak)
{
RSS_AP_SNAPSHOT_CHECK(c_theSubscriptionRecPool);
+ RSS_AP_SNAPSHOT_CHECK(c_statOpPool);
return;
}
@@ -597,6 +608,7 @@ void Trix:: execBUILD_INDX_IMPL_REQ(Sign
subRec->prepareId = RNIL;
subRec->requestType = INDEX_BUILD;
subRec->fragCount = 0;
+ subRec->fragId = ZNIL;
subRec->m_rows_processed = 0;
subRec->m_flags = SubscriptionRecord::RF_WAIT_GCP; // Todo make configurable
subRec->m_gci = 0;
@@ -655,6 +667,11 @@ void Trix::execUTIL_PREPARE_CONF(Signal*
printf("Trix::execUTIL_PREPARE_CONF: Failed to find subscription data %u\n", subRecPtr.i);
return;
}
+ if (subRec->requestType == STAT_UTIL)
+ {
+ statUtilPrepareConf(signal, subRec->m_statPtrI);
+ return;
+ }
subRecPtr.p = subRec;
subRec->prepareId = utilPrepareConf->prepareId;
setupSubscription(signal, subRecPtr);
@@ -672,6 +689,11 @@ void Trix::execUTIL_PREPARE_REF(Signal*
printf("Trix::execUTIL_PREPARE_REF: Failed to find subscription data %u\n", subRecPtr.i);
return;
}
+ if (subRec->requestType == STAT_UTIL)
+ {
+ statUtilPrepareRef(signal, subRec->m_statPtrI);
+ return;
+ }
subRecPtr.p = subRec;
subRec->errorCode = (BuildIndxRef::ErrorCode)utilPrepareRef->errorCode;
@@ -696,6 +718,11 @@ void Trix::execUTIL_EXECUTE_CONF(Signal*
printf("rix::execUTIL_EXECUTE_CONF: Failed to find subscription data %u\n", subRecPtr.i);
return;
}
+ if (subRec->requestType == STAT_UTIL)
+ {
+ statUtilExecuteConf(signal, subRec->m_statPtrI);
+ return;
+ }
subRecPtr.p = subRec;
subRec->expectedConf--;
@@ -730,6 +757,11 @@ void Trix::execUTIL_EXECUTE_REF(Signal*
printf("Trix::execUTIL_EXECUTE_REF: Failed to find subscription data %u\n", subRecPtr.i);
return;
}
+ if (subRec->requestType == STAT_UTIL)
+ {
+ statUtilExecuteRef(signal, subRec->m_statPtrI);
+ return;
+ }
subRecPtr.p = subRec;
ndbrequire(utilExecuteRef->errorCode == UtilExecuteRef::TCError);
if(utilExecuteRef->TCErrorCode == CONSTRAINT_VIOLATION)
@@ -890,6 +922,21 @@ void Trix::execSUB_TABLE_DATA(Signal* si
case REORG_DELETE:
executeReorgTransaction(signal, subRecPtr, subTableData->takeOver);
break;
+ case STAT_UTIL:
+ ndbrequire(false);
+ break;
+ case STAT_CLEAN:
+ {
+ StatOp& stat = statOpGetPtr(subRecPtr.p->m_statPtrI);
+ statCleanExecute(signal, stat);
+ }
+ break;
+ case STAT_SCAN:
+ {
+ StatOp& stat = statOpGetPtr(subRecPtr.p->m_statPtrI);
+ statScanExecute(signal, stat);
+ }
+ break;
}
subRecPtr.p->m_rows_processed++;
@@ -939,8 +986,10 @@ void Trix::startTableScan(Signal* signal
}
// Merge index and key column segments
struct LinearSectionPtr orderPtr[3];
+ Uint32 noOfSections;
orderPtr[0].p = attributeList;
orderPtr[0].sz = subRec->attributeOrder.getSize();
+ noOfSections = 1;
SubSyncReq * subSyncReq = (SubSyncReq *)signal->getDataPtrSend();
subSyncReq->senderRef = reference();
@@ -950,6 +999,7 @@ void Trix::startTableScan(Signal* signal
subSyncReq->part = SubscriptionData::TableData;
subSyncReq->requestInfo = 0;
subSyncReq->fragCount = subRec->fragCount;
+ subSyncReq->fragId = subRec->fragId;
if (subRec->m_flags & SubscriptionRecord::RF_NO_DISK)
{
@@ -974,6 +1024,27 @@ void Trix::startTableScan(Signal* signal
subSyncReq->requestInfo |= SubSyncReq::LM_Exclusive;
subSyncReq->requestInfo |= SubSyncReq::Reorg;
}
+ else if (subRec->requestType == STAT_CLEAN)
+ {
+ jam();
+ StatOp& stat = statOpGetPtr(subRecPtr.p->m_statPtrI);
+ StatOp::Clean clean = stat.m_clean;
+ orderPtr[1].p = clean.m_bound;
+ orderPtr[1].sz = clean.m_boundSize;
+ noOfSections = 2;
+ subSyncReq->requestInfo |= SubSyncReq::LM_CommittedRead;
+ subSyncReq->requestInfo |= SubSyncReq::RangeScan;
+ }
+ else if (subRec->requestType == STAT_SCAN)
+ {
+ jam();
+ orderPtr[1].p = 0;
+ orderPtr[1].sz = 0;
+ noOfSections = 2;
+ subSyncReq->requestInfo |= SubSyncReq::LM_CommittedRead;
+ subSyncReq->requestInfo |= SubSyncReq::RangeScan;
+ subSyncReq->requestInfo |= SubSyncReq::StatScan;
+ }
subRecPtr.p->expectedConf = 1;
DBUG_PRINT("info",("i: %u subscriptionId: %u, subscriptionKey: %u",
@@ -981,7 +1052,7 @@ void Trix::startTableScan(Signal* signal
subSyncReq->subscriptionKey));
sendSignal(SUMA_REF, GSN_SUB_SYNC_REQ,
- signal, SubSyncReq::SignalLength, JBB, orderPtr, 1);
+ signal, SubSyncReq::SignalLength, JBB, orderPtr, noOfSections);
}
void Trix::prepareInsertTransactions(Signal* signal,
@@ -1325,6 +1396,24 @@ Trix::execUTIL_RELEASE_CONF(Signal* sign
BuildIndxRef::SignalLength , JBB);
}
break;
+ case STAT_UTIL:
+ ndbrequire(subRecPtr.p->errorCode == BuildIndxRef::NoError);
+ statUtilReleaseConf(signal, subRecPtr.p->m_statPtrI);
+ return;
+ case STAT_CLEAN:
+ {
+ subRecPtr.p->prepareId = RNIL;
+ StatOp& stat = statOpGetPtr(subRecPtr.p->m_statPtrI);
+ statCleanRelease(signal, stat);
+ }
+ return;
+ case STAT_SCAN:
+ {
+ subRecPtr.p->prepareId = RNIL;
+ StatOp& stat = statOpGetPtr(subRecPtr.p->m_statPtrI);
+ statScanRelease(signal, stat);
+ }
+ return;
}
// Release subscription record
@@ -1394,6 +1483,7 @@ Trix::execCOPY_DATA_IMPL_REQ(Signal* sig
subRec->pendingSubSyncContinueConf = false;
subRec->prepareId = req->transId;
subRec->fragCount = req->srcFragments;
+ subRec->fragId = ZNIL;
subRec->m_rows_processed = 0;
subRec->m_flags = SubscriptionRecord::RF_WAIT_GCP; // Todo make configurable
subRec->m_gci = 0;
@@ -1478,6 +1568,1606 @@ Trix::execCOPY_DATA_IMPL_REQ(Signal* sig
}
}
+// index stats
+
+Trix::StatOp&
+Trix::statOpGetPtr(Uint32 statPtrI)
+{
+ ndbrequire(statPtrI != RNIL);
+ return *c_statOpPool.getPtr(statPtrI);
+}
+
+bool
+Trix::statOpSeize(Uint32& statPtrI)
+{
+ StatOpPtr statPtr;
+ if (ERROR_INSERTED(18001) ||
+ !c_statOpPool.seize(statPtr))
+ {
+ jam();
+ D("statOpSeize: seize statOp failed");
+ return false;
+ }
+#ifdef VM_TRACE
+ memset(statPtr.p, 0xf3, sizeof(*statPtr.p));
+#endif
+ new (statPtr.p) StatOp;
+ statPtrI = statPtr.i;
+ StatOp& stat = statOpGetPtr(statPtrI);
+ stat.m_ownPtrI = statPtrI;
+
+ SubscriptionRecPtr subRecPtr;
+ if (ERROR_INSERTED(18002) ||
+ !c_theSubscriptions.seize(subRecPtr))
+ {
+ jam();
+ c_statOpPool.release(statPtr);
+ D("statOpSeize: seize subRec failed");
+ return false;
+ }
+ SubscriptionRecord* subRec = subRecPtr.p;
+ subRec->m_statPtrI = stat.m_ownPtrI;
+ stat.m_subRecPtrI = subRecPtr.i;
+
+ D("statOpSeize" << V(statPtrI) << V(subRecPtr.i));
+ return true;
+}
+
+void
+Trix::statOpRelease(StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ D("statOpRelease" << V(stat));
+
+ if (stat.m_subRecPtrI != RNIL)
+ {
+ jam();
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ ndbrequire(subRec->prepareId == RNIL);
+ subRec->attributeOrder.release();
+ c_theSubscriptions.release(stat.m_subRecPtrI);
+ stat.m_subRecPtrI = RNIL;
+ }
+ ndbrequire(util.m_prepareId == RNIL);
+ c_statOpPool.release(stat.m_ownPtrI);
+}
+
+void
+Trix::execINDEX_STAT_IMPL_REQ(Signal* signal)
+{
+ jamEntry();
+ const IndexStatImplReq* req = (const IndexStatImplReq*)signal->getDataPtr();
+
+ Uint32 statPtrI = RNIL;
+ if (!statOpSeize(statPtrI))
+ {
+ jam();
+ statOpRef(signal, req, IndexStatRef::NoFreeStatOp, __LINE__);
+ return;
+ }
+ StatOp& stat = statOpGetPtr(statPtrI);
+ stat.m_req = *req;
+ stat.m_requestType = req->requestType;
+
+ // set request name for cluster log message
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_CLEAN_NEW:
+ jam();
+ stat.m_requestName = "clean new";
+ break;
+ case IndexStatReq::RT_CLEAN_OLD:
+ jam();
+ stat.m_requestName = "clean old";
+ break;
+ case IndexStatReq::RT_CLEAN_ALL:
+ jam();
+ stat.m_requestName = "clean all";
+ break;
+ case IndexStatReq::RT_SCAN_FRAG:
+ jam();
+ stat.m_requestName = "scan frag";
+ break;
+ case IndexStatReq::RT_DROP_HEAD:
+ jam();
+ stat.m_requestName = "drop head";
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ subRec->prepareId = RNIL;
+ subRec->errorCode = BuildIndxRef::NoError;
+
+ // sys tables are not recreated so do this only once
+ if (!c_statGetMetaDone)
+ {
+ jam();
+ statMetaGetHead(signal, stat);
+ return;
+ }
+ statGetMetaDone(signal, stat);
+}
+
+// sys tables metadata
+
+const Trix::SysColumn
+Trix::g_statMetaHead_column[] = {
+ { 0, "INDEX_ID",
+ true
+ },
+ { 1, "INDEX_VERSION",
+ true
+ },
+ { 2, "TABLE_ID",
+ false
+ },
+ { 3, "FRAG_COUNT",
+ false
+ },
+ { 4, "VALUE_FORMAT",
+ false
+ },
+ { 5, "SAMPLE_VERSION",
+ false
+ },
+ { 6, "LOAD_TIME",
+ false
+ },
+ { 7, "SAMPLE_COUNT",
+ false
+ },
+ { 8, "KEY_BYTES",
+ false
+ }
+};
+
+const Trix::SysColumn
+Trix::g_statMetaSample_column[] = {
+ { 0, "INDEX_ID",
+ true
+ },
+ { 1, "INDEX_VERSION",
+ true
+ },
+ { 2, "SAMPLE_VERSION",
+ true
+ },
+ { 3, "STAT_KEY",
+ true
+ },
+ { 4, "STAT_VALUE",
+ false
+ }
+};
+
+const Trix::SysTable
+Trix::g_statMetaHead = {
+ NDB_INDEX_STAT_DB "/" NDB_INDEX_STAT_SCHEMA "/" NDB_INDEX_STAT_HEAD_TABLE,
+ ~(Uint32)0,
+ sizeof(g_statMetaHead_column)/sizeof(g_statMetaHead_column[0]),
+ g_statMetaHead_column
+};
+
+const Trix::SysTable
+Trix::g_statMetaSample = {
+ NDB_INDEX_STAT_DB "/" NDB_INDEX_STAT_SCHEMA "/" NDB_INDEX_STAT_SAMPLE_TABLE,
+ ~(Uint32)0,
+ sizeof(g_statMetaSample_column)/sizeof(g_statMetaSample_column[0]),
+ g_statMetaSample_column
+};
+
+const Trix::SysIndex
+Trix::g_statMetaSampleX1 = {
+ NDB_INDEX_STAT_DB "/" NDB_INDEX_STAT_SCHEMA "/%u/" NDB_INDEX_STAT_SAMPLE_INDEX1,
+ ~(Uint32)0,
+ ~(Uint32)0
+};
+
+void
+Trix::statMetaGetHead(Signal* signal, StatOp& stat)
+{
+ D("statMetaGetHead" << V(stat));
+ StatOp::Meta& meta = stat.m_meta;
+ meta.m_cb.m_callbackFunction = safe_cast(&Trix::statMetaGetHeadCB);
+ meta.m_cb.m_callbackData = stat.m_ownPtrI;
+ const char* name = g_statMetaHead.name;
+ sendGetTabInfoReq(signal, stat, name);
+}
+
+void
+Trix::statMetaGetHeadCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statMetaGetHeadCB" << V(stat) << V(ret));
+ StatOp::Meta& meta = stat.m_meta;
+ if (ret != 0)
+ {
+ jam();
+ statOpError(signal, stat, ret, __LINE__);
+ return;
+ }
+ g_statMetaHead.tableId = meta.m_conf.tableId;
+ statMetaGetSample(signal, stat);
+}
+
+void
+Trix::statMetaGetSample(Signal* signal, StatOp& stat)
+{
+ D("statMetaGetSample" << V(stat));
+ StatOp::Meta& meta = stat.m_meta;
+ meta.m_cb.m_callbackFunction = safe_cast(&Trix::statMetaGetSampleCB);
+ meta.m_cb.m_callbackData = stat.m_ownPtrI;
+ const char* name = g_statMetaSample.name;
+ sendGetTabInfoReq(signal, stat, name);
+}
+
+void
+Trix::statMetaGetSampleCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statMetaGetSampleCB" << V(stat) << V(ret));
+ StatOp::Meta& meta = stat.m_meta;
+ if (ret != 0)
+ {
+ jam();
+ statOpError(signal, stat, ret, __LINE__);
+ return;
+ }
+ g_statMetaSample.tableId = meta.m_conf.tableId;
+ statMetaGetSampleX1(signal, stat);
+}
+
+void
+Trix::statMetaGetSampleX1(Signal* signal, StatOp& stat)
+{
+ D("statMetaGetSampleX1" << V(stat));
+ StatOp::Meta& meta = stat.m_meta;
+ meta.m_cb.m_callbackFunction = safe_cast(&Trix::statMetaGetSampleX1CB);
+ meta.m_cb.m_callbackData = stat.m_ownPtrI;
+ const char* name_fmt = g_statMetaSampleX1.name;
+ char name[MAX_TAB_NAME_SIZE];
+ BaseString::snprintf(name, sizeof(name), name_fmt, g_statMetaSample.tableId);
+ sendGetTabInfoReq(signal, stat, name);
+}
+
+void
+Trix::statMetaGetSampleX1CB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statMetaGetSampleX1CB" << V(stat) << V(ret));
+ StatOp::Meta& meta = stat.m_meta;
+ if (ret != 0)
+ {
+ jam();
+ statOpError(signal, stat, ret, __LINE__);
+ return;
+ }
+ g_statMetaSampleX1.tableId = g_statMetaSample.tableId;
+ g_statMetaSampleX1.indexId = meta.m_conf.tableId;
+ statGetMetaDone(signal, stat);
+}
+
+void
+Trix::sendGetTabInfoReq(Signal* signal, StatOp& stat, const char* name)
+{
+ D("sendGetTabInfoReq" << V(stat) << V(name));
+ GetTabInfoReq* req = (GetTabInfoReq*)signal->getDataPtrSend();
+
+ Uint32 name_len = (Uint32)strlen(name) + 1;
+ Uint32 name_len_words = (name_len + 3 ) / 4;
+ Uint32 name_buf[32];
+ ndbrequire(name_len_words <= 32);
+ memset(name_buf, 0, sizeof(name_buf));
+ memcpy(name_buf, name, name_len);
+
+ req->senderData = stat.m_ownPtrI;
+ req->senderRef = reference();
+ req->requestType = GetTabInfoReq::RequestByName |
+ GetTabInfoReq::LongSignalConf;
+ req->tableNameLen = name_len;
+ req->schemaTransId = 0;
+ LinearSectionPtr ptr[3];
+ ptr[0].p = name_buf;
+ ptr[0].sz = name_len_words;
+ sendSignal(DBDICT_REF, GSN_GET_TABINFOREQ,
+ signal, GetTabInfoReq::SignalLength, JBB, ptr, 1);
+}
+
+void
+Trix::execGET_TABINFO_CONF(Signal* signal)
+{
+ jamEntry();
+ if (!assembleFragments(signal)) {
+ jam();
+ return;
+ }
+ const GetTabInfoConf* conf = (const GetTabInfoConf*)signal->getDataPtr();
+ StatOp& stat = statOpGetPtr(conf->senderData);
+ D("execGET_TABINFO_CONF" << V(stat));
+ StatOp::Meta& meta = stat.m_meta;
+ meta.m_conf = *conf;
+
+ // do not need DICTTABINFO
+ SectionHandle handle(this, signal);
+ releaseSections(handle);
+
+ execute(signal, meta.m_cb, 0);
+}
+
+void
+Trix::execGET_TABINFO_REF(Signal* signal)
+{
+ jamEntry();
+ const GetTabInfoRef* ref = (const GetTabInfoRef*)signal->getDataPtr();
+ StatOp& stat = statOpGetPtr(ref->senderData);
+ D("execGET_TABINFO_REF" << V(stat));
+ StatOp::Meta& meta = stat.m_meta;
+
+ ndbrequire(ref->errorCode != 0);
+ execute(signal, meta.m_cb, ref->errorCode);
+}
+
+// continue after metadata retrieval
+
+void
+Trix::statGetMetaDone(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statGetMetaDone" << V(stat));
+
+ // c_statGetMetaDone = true;
+
+ subRec->requestType = STAT_UTIL;
+ // fill in constant part
+ ndbrequire(req->fragCount != 0);
+ data.m_indexId = req->indexId;
+ data.m_indexVersion = req->indexVersion;
+ data.m_fragCount = req->fragCount;
+ statHeadRead(signal, stat);
+}
+
+// head table ops
+
+void
+Trix::statHeadRead(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statHeadRead" << V(stat));
+
+ util.m_not_found = false;
+ util.m_cb.m_callbackFunction = safe_cast(&Trix::statHeadReadCB);
+ util.m_cb.m_callbackData = stat.m_ownPtrI;
+ send.m_sysTable = &g_statMetaHead;
+ send.m_operationType = UtilPrepareReq::Read;
+ statUtilPrepare(signal, stat);
+}
+
+void
+Trix::statHeadReadCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ StatOp::Data& data = stat.m_data;
+ StatOp::Util& util = stat.m_util;
+ D("statHeadReadCB" << V(stat) << V(ret));
+
+ ndbrequire(ret == 0);
+ data.m_head_found = !util.m_not_found;
+ statReadHeadDone(signal, stat);
+}
+
+void
+Trix::statHeadInsert(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statHeadInsert" << V(stat));
+
+ util.m_cb.m_callbackFunction = safe_cast(&Trix::statHeadInsertCB);
+ util.m_cb.m_callbackData = stat.m_ownPtrI;
+ send.m_sysTable = &g_statMetaHead;
+ send.m_operationType = UtilPrepareReq::Insert;
+ statUtilPrepare(signal, stat);
+}
+
+void
+Trix::statHeadInsertCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statHeadInsertCB" << V(stat) << V(ret));
+
+ ndbrequire(ret == 0);
+ statInsertHeadDone(signal, stat);
+}
+
+void
+Trix::statHeadUpdate(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statHeadUpdate" << V(stat));
+
+ util.m_cb.m_callbackFunction = safe_cast(&Trix::statHeadUpdateCB);
+ util.m_cb.m_callbackData = stat.m_ownPtrI;
+ send.m_sysTable = &g_statMetaHead;
+ send.m_operationType = UtilPrepareReq::Update;
+ statUtilPrepare(signal, stat);
+}
+
+void
+Trix::statHeadUpdateCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statHeadUpdateCB" << V(stat) << V(ret));
+
+ ndbrequire(ret == 0);
+ statUpdateHeadDone(signal, stat);
+}
+
+void
+Trix::statHeadDelete(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statHeadDelete" << V(stat));
+
+ util.m_cb.m_callbackFunction = safe_cast(&Trix::statHeadDeleteCB);
+ util.m_cb.m_callbackData = stat.m_ownPtrI;
+ send.m_sysTable = &g_statMetaHead;
+ send.m_operationType = UtilPrepareReq::Delete;
+ statUtilPrepare(signal, stat);
+}
+
+void
+Trix::statHeadDeleteCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statHeadDeleteCB" << V(stat) << V(ret));
+
+ ndbrequire(ret == 0);
+ statDeleteHeadDone(signal, stat);
+}
+
+// util (PK ops, only HEAD for now)
+
+void
+Trix::statUtilPrepare(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ D("statUtilPrepare" << V(stat));
+
+ util.m_prepareId = RNIL;
+ statSendPrepare(signal, stat);
+}
+
+void
+Trix::statUtilPrepareConf(Signal* signal, Uint32 statPtrI)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statUtilPrepareConf" << V(stat));
+
+ const UtilPrepareConf* utilConf =
+ (const UtilPrepareConf*)signal->getDataPtr();
+ util.m_prepareId = utilConf->prepareId;
+
+ const Uint32 ot = send.m_operationType;
+ if (ERROR_INSERTED(18011) && ot == UtilPrepareReq::Read ||
+ ERROR_INSERTED(18012) && ot != UtilPrepareReq::Read)
+ {
+ jam();
+ CLEAR_ERROR_INSERT_VALUE;
+ UtilExecuteRef* utilRef =
+ (UtilExecuteRef*)signal->getDataPtrSend();
+ utilRef->senderData = stat.m_ownPtrI;
+ utilRef->errorCode = UtilExecuteRef::AllocationError;
+ utilRef->TCErrorCode = 0;
+ sendSignal(reference(), GSN_UTIL_EXECUTE_REF,
+ signal, UtilExecuteRef::SignalLength, JBB);
+ return;
+ }
+
+ statUtilExecute(signal, stat);
+}
+
+void
+Trix::statUtilPrepareRef(Signal* signal, Uint32 statPtrI)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statUtilPrepareRef" << V(stat));
+
+ const UtilPrepareRef* utilRef =
+ (const UtilPrepareRef*)signal->getDataPtr();
+ Uint32 errorCode = utilRef->errorCode;
+ ndbrequire(errorCode != 0);
+
+ switch (errorCode) {
+ case UtilPrepareRef::PREPARE_SEIZE_ERROR:
+ case UtilPrepareRef::PREPARE_PAGES_SEIZE_ERROR:
+ case UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR:
+ errorCode = IndexStatRef::BusyUtilPrepare;
+ break;
+ case UtilPrepareRef::DICT_TAB_INFO_ERROR:
+ errorCode = IndexStatRef::InvalidSysTable;
+ break;
+ case UtilPrepareRef::MISSING_PROPERTIES_SECTION:
+ default:
+ ndbrequire(false);
+ break;
+ }
+ statOpError(signal, stat, errorCode, __LINE__);
+}
+
+void
+Trix::statUtilExecute(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statUtilExecute" << V(stat));
+
+ send.m_prepareId = util.m_prepareId;
+ statSendExecute(signal, stat);
+}
+
+void
+Trix::statUtilExecuteConf(Signal* signal, Uint32 statPtrI)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ StatOp::Attr& attr = stat.m_attr;
+ StatOp::Send& send = stat.m_send;
+ D("statUtilExecuteConf" << V(stat));
+
+ if (send.m_operationType == UtilPrepareReq::Read)
+ {
+ jam();
+ SectionHandle handle(this, signal);
+ Uint32 rattr[20];
+ Uint32 rdata[2048];
+ attr.m_attr = rattr;
+ attr.m_attrMax = 20;
+ attr.m_attrSize = 0;
+ attr.m_data = rdata;
+ attr.m_dataMax = 2048;
+ attr.m_dataSize = 0;
+ {
+ SegmentedSectionPtr ssPtr;
+ handle.getSection(ssPtr, 0);
+ ::copy(rattr, ssPtr);
+ }
+ {
+ SegmentedSectionPtr ssPtr;
+ handle.getSection(ssPtr, 1);
+ ::copy(rdata, ssPtr);
+ }
+ releaseSections(handle);
+
+ const SysTable& sysTable = *send.m_sysTable;
+ for (Uint32 i = 0; i < sysTable.columnCount; i++)
+ {
+ jam();
+ statDataIn(stat, i);
+ }
+ }
+
+ statUtilRelease(signal, stat);
+}
+
+void
+Trix::statUtilExecuteRef(Signal* signal, Uint32 statPtrI)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statUtilExecuteRef" << V(stat));
+
+ const UtilExecuteRef* utilRef =
+ (const UtilExecuteRef*)signal->getDataPtr();
+ Uint32 errorCode = utilRef->errorCode;
+ ndbrequire(errorCode != 0);
+
+ switch (errorCode) {
+ case UtilExecuteRef::TCError:
+ errorCode = utilRef->TCErrorCode;
+ ndbrequire(errorCode != 0);
+ if (send.m_operationType == UtilPrepareReq::Read &&
+ errorCode == ZNOT_FOUND)
+ {
+ jam();
+ util.m_not_found = true;
+ errorCode = 0;
+ }
+ break;
+ case UtilExecuteRef::AllocationError:
+ errorCode = IndexStatRef::BusyUtilExecute;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+
+ if (errorCode != 0)
+ {
+ jam();
+ statOpError(signal, stat, errorCode, __LINE__);
+ return;
+ }
+ statUtilRelease(signal, stat);
+}
+
+void
+Trix::statUtilRelease(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ StatOp::Send& send = stat.m_send;
+ D("statUtilRelease" << V(stat));
+
+ send.m_prepareId = util.m_prepareId;
+ statSendRelease(signal, stat);
+}
+
+void
+Trix::statUtilReleaseConf(Signal* signal, Uint32 statPtrI)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ StatOp::Util& util = stat.m_util;
+ D("statUtilReleaseConf" << V(stat));
+
+ util.m_prepareId = RNIL;
+ execute(signal, util.m_cb, 0);
+}
+
+// continue after head table ops
+
+void
+Trix::statReadHeadDone(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ D("statReadHeadDone" << V(stat));
+
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_CLEAN_NEW:
+ jam();
+ case IndexStatReq::RT_CLEAN_OLD:
+ jam();
+ case IndexStatReq::RT_CLEAN_ALL:
+ jam();
+ statCleanBegin(signal, stat);
+ break;
+
+ case IndexStatReq::RT_SCAN_FRAG:
+ jam();
+ statScanBegin(signal, stat);
+ break;
+
+ case IndexStatReq::RT_DROP_HEAD:
+ jam();
+ statDropBegin(signal, stat);
+ break;
+
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+void
+Trix::statInsertHeadDone(Signal* signal, StatOp& stat)
+{
+ D("statInsertHeadDone" << V(stat));
+
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_SCAN_FRAG:
+ jam();
+ statScanEnd(signal, stat);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+void
+Trix::statUpdateHeadDone(Signal* signal, StatOp& stat)
+{
+ D("statUpdateHeadDone" << V(stat));
+
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_SCAN_FRAG:
+ jam();
+ statScanEnd(signal, stat);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+void
+Trix::statDeleteHeadDone(Signal* signal, StatOp& stat)
+{
+ D("statDeleteHeadDone" << V(stat));
+
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_DROP_HEAD:
+ jam();
+ statDropEnd(signal, stat);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+}
+
+// clean
+
+void
+Trix::statCleanBegin(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+ D("statCleanBegin" << V(stat));
+
+ if (data.m_head_found == true)
+ {
+ jam();
+ if (data.m_tableId != req->tableId &&
+ stat.m_requestType != IndexStatReq::RT_CLEAN_ALL)
+ {
+ jam();
+ // must run ndb_index_stat --drop
+ statOpError(signal, stat, IndexStatRef::InvalidSysTableData, __LINE__);
+ return;
+ }
+ }
+ else
+ {
+ if (stat.m_requestType != IndexStatReq::RT_CLEAN_ALL)
+ {
+ jam();
+ // happens normally on first stats scan
+ stat.m_requestType = IndexStatReq::RT_CLEAN_ALL;
+ }
+ }
+ statCleanPrepare(signal, stat);
+}
+
+void
+Trix::statCleanPrepare(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+ StatOp::Clean& clean = stat.m_clean;
+ StatOp::Send& send = stat.m_send;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statCleanPrepare" << V(stat));
+
+ // count of deleted samples is just for info
+ clean.m_cleanCount = 0;
+
+ const Uint32 ao_list[] = {
+ 0, // INDEX_ID
+ 1, // INDEX_VERSION
+ 2, // SAMPLE_VERSION
+ 3 // STAT_KEY
+ };
+ const Uint32 ao_size = sizeof(ao_list)/sizeof(ao_list[0]);
+
+ ndbrequire(req->fragId == ZNIL);
+ subRec->m_flags = 0;
+ subRec->requestType = STAT_CLEAN;
+ subRec->schemaTransId = req->transId;
+ subRec->userReference = 0; // not used
+ subRec->connectionPtr = RNIL;
+ subRec->subscriptionId = rand();
+ subRec->subscriptionKey = rand();
+ subRec->prepareId = RNIL;
+ subRec->indexType = 0; // not used
+ subRec->sourceTableId = g_statMetaSampleX1.indexId;
+ subRec->targetTableId = RNIL;
+ subRec->noOfIndexColumns = ao_size;
+ subRec->noOfKeyColumns = 0;
+ subRec->parallelism = 16;
+ subRec->fragCount = 0;
+ subRec->fragId = ZNIL;
+ subRec->syncPtr = RNIL;
+ subRec->errorCode = BuildIndxRef::NoError;
+ subRec->subscriptionCreated = false;
+ subRec->pendingSubSyncContinueConf = false;
+ subRec->expectedConf = 0;
+ subRec->m_rows_processed = 0;
+ subRec->m_gci = 0;
+
+ AttrOrderBuffer& ao_buf = subRec->attributeOrder;
+ ndbrequire(ao_buf.isEmpty());
+ ao_buf.append(ao_list, ao_size);
+
+ // create TUX bounds
+ clean.m_bound[0] = TuxBoundInfo::BoundEQ;
+ clean.m_bound[1] = AttributeHeader(0, 4).m_value;
+ clean.m_bound[2] = data.m_indexId;
+ clean.m_bound[3] = TuxBoundInfo::BoundEQ;
+ clean.m_bound[4] = AttributeHeader(1, 4).m_value;
+ clean.m_bound[5] = data.m_indexVersion;
+ switch (stat.m_requestType) {
+ case IndexStatReq::RT_CLEAN_NEW:
+ D("statCleanPrepare delete sample versions > " << data.m_sampleVersion);
+ clean.m_bound[6] = TuxBoundInfo::BoundLT;
+ clean.m_bound[7] = AttributeHeader(2, 4).m_value;
+ clean.m_bound[8] = data.m_sampleVersion;
+ clean.m_boundCount = 3;
+ break;
+ case IndexStatReq::RT_CLEAN_OLD:
+ D("statCleanPrepare delete sample versions < " << data.m_sampleVersion);
+ clean.m_bound[6] = TuxBoundInfo::BoundGT;
+ clean.m_bound[7] = AttributeHeader(2, 4).m_value;
+ clean.m_bound[8] = data.m_sampleVersion;
+ clean.m_boundCount = 3;
+ break;
+ case IndexStatReq::RT_CLEAN_ALL:
+ D("statCleanPrepare delete all sample versions");
+ clean.m_boundCount = 2;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+ clean.m_boundSize = 3 * clean.m_boundCount;
+
+ // TRIX traps the CONF
+ send.m_sysTable = &g_statMetaSample;
+ send.m_operationType = UtilPrepareReq::Delete;
+ statSendPrepare(signal, stat);
+}
+
+void
+Trix::statCleanExecute(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ StatOp::Send& send = stat.m_send;
+ StatOp::Clean& clean = stat.m_clean;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statCleanExecute" << V(stat));
+
+ SectionHandle handle(this, signal);
+ ndbrequire(handle.m_cnt == 2);
+
+ // ATTR_INFO
+ AttributeHeader ah[4];
+ SegmentedSectionPtr ptr0;
+ handle.getSection(ptr0, SubTableData::ATTR_INFO);
+ ndbrequire(ptr0.sz == 4);
+ ::copy((Uint32*)ah, ptr0);
+ ndbrequire(ah[0].getAttributeId() == 0 && ah[0].getDataSize() == 1);
+ ndbrequire(ah[1].getAttributeId() == 1 && ah[1].getDataSize() == 1);
+ ndbrequire(ah[2].getAttributeId() == 2 && ah[2].getDataSize() == 1);
+ // read via TUP rounds bytes to words
+ const Uint32 kz = ah[3].getDataSize();
+ ndbrequire(ah[3].getAttributeId() == 3 && kz != 0);
+
+ // AFTER_VALUES
+ const Uint32 avmax = 3 + MAX_INDEX_STAT_KEY_SIZE;
+ Uint32 av[avmax];
+ SegmentedSectionPtr ptr1;
+ handle.getSection(ptr1, SubTableData::AFTER_VALUES);
+ ndbrequire(ptr1.sz <= avmax);
+ ::copy(av, ptr1);
+ ndbrequire(data.m_indexId == av[0]);
+ ndbrequire(data.m_indexVersion == av[1]);
+ data.m_sampleVersion = av[2];
+ data.m_statKey = &av[3];
+ const char* kp = (const char*)data.m_statKey;
+ const Uint32 kb = kp[0] + (kp[1] << 8);
+ // key is not empty
+ ndbrequire(kb != 0);
+ ndbrequire(kz == ((2 + kb) + 3) / 4);
+
+ clean.m_cleanCount++;
+ releaseSections(handle);
+
+ const Uint32 rt = stat.m_requestType;
+ if (ERROR_INSERTED(18021) && rt == IndexStatReq::RT_CLEAN_NEW ||
+ ERROR_INSERTED(18022) && rt == IndexStatReq::RT_CLEAN_OLD ||
+ ERROR_INSERTED(18023) && rt == IndexStatReq::RT_CLEAN_ALL)
+ {
+ jam();
+ CLEAR_ERROR_INSERT_VALUE;
+ UtilExecuteRef* utilRef =
+ (UtilExecuteRef*)signal->getDataPtrSend();
+ utilRef->senderData = stat.m_ownPtrI;
+ utilRef->errorCode = UtilExecuteRef::TCError;
+ utilRef->TCErrorCode = 626;
+ sendSignal(reference(), GSN_UTIL_EXECUTE_REF,
+ signal, UtilExecuteRef::SignalLength, JBB);
+ subRec->expectedConf++;
+ return;
+ }
+
+ // TRIX traps the CONF
+ send.m_sysTable = &g_statMetaSample;
+ send.m_operationType = UtilPrepareReq::Delete;
+ send.m_prepareId = subRec->prepareId;
+ subRec->expectedConf++;
+ statSendExecute(signal, stat);
+}
+
+void
+Trix::statCleanRelease(Signal* signal, StatOp& stat)
+{
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statCleanRelease" << V(stat) << V(subRec->errorCode));
+
+ if (subRec->errorCode != 0)
+ {
+ jam();
+ statOpError(signal, stat, subRec->errorCode, __LINE__);
+ return;
+ }
+ statCleanEnd(signal, stat);
+}
+
+void
+Trix::statCleanEnd(Signal* signal, StatOp& stat)
+{
+ D("statCleanEnd" << V(stat));
+ statOpSuccess(signal, stat);
+}
+
+// scan
+
+void
+Trix::statScanBegin(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+ D("statScanBegin" << V(stat));
+
+ if (data.m_head_found == true &&
+ data.m_tableId != req->tableId)
+ {
+ jam();
+ statOpError(signal, stat, IndexStatRef::InvalidSysTableData, __LINE__);
+ return;
+ }
+ data.m_tableId = req->tableId;
+ statScanPrepare(signal, stat);
+}
+
+void
+Trix::statScanPrepare(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+ StatOp::Scan& scan = stat.m_scan;
+ StatOp::Send& send = stat.m_send;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statScanPrepare" << V(stat));
+
+ // update sample version prior to scan
+ if (data.m_head_found == false)
+ data.m_sampleVersion = 0;
+ data.m_sampleVersion += 1;
+
+ // zero totals
+ scan.m_sampleCount = 0;
+ scan.m_keyBytes = 0;
+
+ const Uint32 ao_list[] = {
+ AttributeHeader::INDEX_STAT_KEY,
+ AttributeHeader::INDEX_STAT_VALUE
+ };
+ const Uint32 ao_size = sizeof(ao_list)/sizeof(ao_list[0]);
+
+ ndbrequire(req->fragId != ZNIL);
+ subRec->m_flags = 0;
+ subRec->requestType = STAT_SCAN;
+ subRec->schemaTransId = req->transId;
+ subRec->userReference = 0; // not used
+ subRec->connectionPtr = RNIL;
+ subRec->subscriptionId = rand();
+ subRec->subscriptionKey = rand();
+ subRec->prepareId = RNIL;
+ subRec->indexType = 0; // not used
+ subRec->sourceTableId = data.m_indexId;
+ subRec->targetTableId = RNIL;
+ subRec->noOfIndexColumns = ao_size;
+ subRec->noOfKeyColumns = 0;
+ subRec->parallelism = 16;
+ subRec->fragCount = 0; // XXX Suma currently checks all frags
+ subRec->fragId = req->fragId;
+ subRec->syncPtr = RNIL;
+ subRec->errorCode = BuildIndxRef::NoError;
+ subRec->subscriptionCreated = false;
+ subRec->pendingSubSyncContinueConf = false;
+ subRec->expectedConf = 0;
+ subRec->m_rows_processed = 0;
+ subRec->m_gci = 0;
+
+ AttrOrderBuffer& ao_buf = subRec->attributeOrder;
+ ndbrequire(ao_buf.isEmpty());
+ ao_buf.append(ao_list, ao_size);
+
+ // TRIX traps the CONF
+ send.m_sysTable = &g_statMetaSample;
+ send.m_operationType = UtilPrepareReq::Insert;
+ statSendPrepare(signal, stat);
+}
+
+void
+Trix::statScanExecute(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ StatOp::Scan& scan = stat.m_scan;
+ StatOp::Send& send = stat.m_send;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statScanExecute" << V(stat));
+
+ SectionHandle handle(this, signal);
+ ndbrequire(handle.m_cnt == 2);
+
+ // ATTR_INFO
+ AttributeHeader ah[2];
+ SegmentedSectionPtr ptr0;
+ handle.getSection(ptr0, SubTableData::ATTR_INFO);
+ ndbrequire(ptr0.sz == 2);
+ ::copy((Uint32*)ah, ptr0);
+ ndbrequire(ah[0].getAttributeId() == AttributeHeader::INDEX_STAT_KEY);
+ ndbrequire(ah[1].getAttributeId() == AttributeHeader::INDEX_STAT_VALUE);
+ // read via TUP rounds bytes to words
+ const Uint32 kz = ah[0].getDataSize();
+ const Uint32 vz = ah[1].getDataSize();
+ ndbrequire(kz != 0 && vz != 0);
+
+ // AFTER_VALUES
+ const Uint32 avmax = MAX_INDEX_STAT_KEY_SIZE + MAX_INDEX_STAT_VALUE_SIZE;
+ Uint32 av[avmax];
+ SegmentedSectionPtr ptr1;
+ handle.getSection(ptr1, SubTableData::AFTER_VALUES);
+ ndbrequire(ptr1.sz <= avmax);
+ ::copy(av, ptr1);
+ data.m_statKey = &av[0];
+ data.m_statValue = &av[kz];
+ const char* kp = (const char*)data.m_statKey;
+ const char* vp = (const char*)data.m_statValue;
+ const Uint32 kb = kp[0] + (kp[1] << 8);
+ const Uint32 vb = vp[0] + (vp[1] << 8);
+ // key and value are not empty
+ ndbrequire(kb != 0 && vb != 0);
+ ndbrequire(kz == ((2 + kb) + 3) / 4);
+ ndbrequire(vz == ((2 + vb) + 3) / 4);
+
+ scan.m_sampleCount++;
+ scan.m_keyBytes += kb;
+ releaseSections(handle);
+
+ if (ERROR_INSERTED(18024))
+ {
+ jam();
+ CLEAR_ERROR_INSERT_VALUE;
+ UtilExecuteRef* utilRef =
+ (UtilExecuteRef*)signal->getDataPtrSend();
+ utilRef->senderData = stat.m_ownPtrI;
+ utilRef->errorCode = UtilExecuteRef::TCError;
+ utilRef->TCErrorCode = 630;
+ sendSignal(reference(), GSN_UTIL_EXECUTE_REF,
+ signal, UtilExecuteRef::SignalLength, JBB);
+ subRec->expectedConf++;
+ return;
+ }
+
+ // TRIX traps the CONF
+ send.m_sysTable = &g_statMetaSample;
+ send.m_operationType = UtilPrepareReq::Insert;
+ send.m_prepareId = subRec->prepareId;
+ subRec->expectedConf++;
+ statSendExecute(signal, stat);
+}
+
+void
+Trix::statScanRelease(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ StatOp::Scan& scan = stat.m_scan;
+ SubscriptionRecord* subRec = c_theSubscriptions.getPtr(stat.m_subRecPtrI);
+ D("statScanRelease" << V(stat) << V(subRec->errorCode));
+
+ if (subRec->errorCode != 0)
+ {
+ jam();
+ statOpError(signal, stat, subRec->errorCode, __LINE__);
+ return;
+ }
+ subRec->requestType = STAT_UTIL;
+
+ const Uint32 now = (Uint32)time(0);
+ data.m_loadTime = now;
+ data.m_sampleCount = scan.m_sampleCount;
+ data.m_keyBytes = scan.m_keyBytes;
+ data.m_valueFormat = MAX_INDEX_STAT_VALUE_FORMAT;
+
+ if (data.m_head_found == false)
+ {
+ jam();
+ statHeadInsert(signal, stat);
+ }
+ else
+ {
+ jam();
+ statHeadUpdate(signal, stat);
+ }
+}
+
+void
+Trix::statScanEnd(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ const IndexStatImplReq* req = &stat.m_req;
+ D("statScanEnd" << V(stat));
+
+ /*
+ * TRIX reports stats load time to TUX for proper stats monitoring.
+ * Passing this via DBDICT RT_START_MON is not feasible. For MT-LQH
+ * we prefer DbtuxProxy to avoid introducing MT-LQH into TRIX.
+ */
+
+#if trix_index_stat_rep_to_tux_instance
+ Uint32 instanceKey = getInstanceKey(req->indexId, req->fragId);
+ BlockReference tuxRef = numberToRef(DBTUX, instanceKey, getOwnNodeId());
+#else
+ BlockReference tuxRef = DBTUX_REF;
+#endif
+
+ IndexStatRep* rep = (IndexStatRep*)signal->getDataPtrSend();
+ rep->senderRef = reference();
+ rep->senderData = 0;
+ rep->requestType = IndexStatRep::RT_UPDATE_CONF;
+ rep->requestFlag = 0;
+ rep->indexId = req->indexId;
+ rep->indexVersion = req->indexVersion;
+ rep->tableId = req->tableId;
+ rep->fragId = req->fragId;
+ rep->loadTime = data.m_loadTime;
+ sendSignal(tuxRef, GSN_INDEX_STAT_REP,
+ signal, IndexStatRep::SignalLength, JBB);
+
+ statOpSuccess(signal, stat);
+}
+
+// drop
+
+void
+Trix::statDropBegin(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ D("statDropBegin" << V(stat));
+
+ if (data.m_head_found == true)
+ {
+ jam();
+ statHeadDelete(signal, stat);
+ return;
+ }
+ statDropEnd(signal, stat);
+}
+
+void
+Trix::statDropEnd(Signal* signal, StatOp& stat)
+{
+ D("statDropEnd");
+ statOpSuccess(signal, stat);
+}
+
+// send
+
+void
+Trix::statSendPrepare(Signal* signal, StatOp& stat)
+{
+ StatOp::Send& send = stat.m_send;
+ const IndexStatImplReq* req = &stat.m_req;
+ const SysTable& sysTable = *send.m_sysTable;
+ D("statSendPrepare" << V(stat));
+
+ UtilPrepareReq* utilReq =
+ (UtilPrepareReq*)signal->getDataPtrSend();
+ utilReq->senderData = stat.m_ownPtrI;
+ utilReq->senderRef = reference();
+ utilReq->schemaTransId = req->transId;
+
+ Uint32 wbuf[256];
+ LinearWriter w(&wbuf[0], sizeof(wbuf) >> 2);
+
+ w.first();
+ w.add(UtilPrepareReq::NoOfOperations, 1);
+ w.add(UtilPrepareReq::OperationType, send.m_operationType);
+ w.add(UtilPrepareReq::TableId, sysTable.tableId);
+
+ Uint32 i;
+ for (i = 0; i < sysTable.columnCount; i++) {
+ const SysColumn& c = sysTable.columnList[i];
+ switch (send.m_operationType) {
+ case UtilPrepareReq::Read:
+ case UtilPrepareReq::Insert:
+ case UtilPrepareReq::Update:
+ jam();
+ w.add(UtilPrepareReq::AttributeId, i);
+ break;
+ case UtilPrepareReq::Delete:
+ jam();
+ if (c.keyFlag)
+ w.add(UtilPrepareReq::AttributeId, i);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+ }
+
+ LinearSectionPtr ptr[3];
+ ptr[0].p = &wbuf[0];
+ ptr[0].sz = w.getWordsUsed();
+ sendSignal(DBUTIL_REF, GSN_UTIL_PREPARE_REQ,
+ signal, UtilPrepareReq::SignalLength, JBB, ptr, 1);
+}
+
+void
+Trix::statSendExecute(Signal* signal, StatOp& stat)
+{
+ D("statSendExecute" << V(stat));
+ StatOp::Send& send = stat.m_send;
+ StatOp::Attr& attr = stat.m_attr;
+ const SysTable& sysTable = *send.m_sysTable;
+
+ UtilExecuteReq* utilReq =
+ (UtilExecuteReq*)signal->getDataPtrSend();
+ utilReq->senderData = stat.m_ownPtrI;
+ utilReq->senderRef = reference();
+ utilReq->prepareId = send.m_prepareId;
+ utilReq->scanTakeOver = 0;
+
+ Uint32 wattr[20];
+ Uint32 wdata[2048];
+ attr.m_attr = wattr;
+ attr.m_attrMax = 20;
+ attr.m_attrSize = 0;
+ attr.m_data = wdata;
+ attr.m_dataMax = 2048;
+ attr.m_dataSize = 0;
+
+ for (Uint32 i = 0; i < sysTable.columnCount; i++) {
+ const SysColumn& c = sysTable.columnList[i];
+ switch (send.m_operationType) {
+ case UtilPrepareReq::Read:
+ case UtilPrepareReq::Insert:
+ case UtilPrepareReq::Update:
+ jam();
+ statDataOut(stat, i);
+ break;
+ case UtilPrepareReq::Delete:
+ jam();
+ if (c.keyFlag)
+ statDataOut(stat, i);
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+ }
+
+ LinearSectionPtr ptr[3];
+ ptr[0].p = attr.m_attr;
+ ptr[0].sz = attr.m_attrSize;
+ ptr[1].p = attr.m_data;
+ ptr[1].sz = attr.m_dataSize;
+ sendSignal(DBUTIL_REF, GSN_UTIL_EXECUTE_REQ,
+ signal, UtilExecuteReq::SignalLength, JBB, ptr, 2);
+}
+
+void
+Trix::statSendRelease(Signal* signal, StatOp& stat)
+{
+ D("statSendRelease" << V(stat));
+ StatOp::Send& send = stat.m_send;
+ ndbrequire(send.m_prepareId != RNIL);
+
+ UtilReleaseReq* utilReq =
+ (UtilReleaseReq*)signal->getDataPtrSend();
+ utilReq->senderData = stat.m_ownPtrI;
+ utilReq->prepareId = send.m_prepareId;
+ sendSignal(DBUTIL_REF, GSN_UTIL_RELEASE_REQ,
+ signal, UtilReleaseReq::SignalLength, JBB);
+}
+
+// data
+
+void
+Trix::statDataPtr(StatOp& stat, Uint32 i, Uint32*& dptr, Uint32& bytes)
+{
+ StatOp::Data& data = stat.m_data;
+ StatOp::Send& send = stat.m_send;
+
+ const SysTable& sysTable = *send.m_sysTable;
+ ndbrequire(i < sysTable.columnCount);
+ const SysColumn& c = sysTable.columnList[i];
+
+ if (&sysTable == &g_statMetaHead)
+ {
+ switch (i) {
+ case 0:
+ dptr = &data.m_indexId;
+ bytes = 4;
+ break;
+ case 1:
+ dptr = &data.m_indexVersion;
+ bytes = 4;
+ break;
+ case 2:
+ dptr = &data.m_tableId;
+ bytes = 4;
+ break;
+ case 3:
+ dptr = &data.m_fragCount;
+ bytes = 4;
+ break;
+ case 4:
+ dptr = &data.m_valueFormat;
+ bytes = 4;
+ break;
+ case 5:
+ dptr = &data.m_sampleVersion;
+ bytes = 4;
+ break;
+ case 6:
+ dptr = &data.m_loadTime;
+ bytes = 4;
+ break;
+ case 7:
+ dptr = &data.m_sampleCount;
+ bytes = 4;
+ break;
+ case 8:
+ dptr = &data.m_keyBytes;
+ bytes = 4;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+ return;
+ }
+
+ if (&sysTable == &g_statMetaSample)
+ {
+ switch (i) {
+ case 0:
+ dptr = &data.m_indexId;
+ bytes = 4;
+ break;
+ case 1:
+ dptr = &data.m_indexVersion;
+ bytes = 4;
+ break;
+ case 2:
+ dptr = &data.m_sampleVersion;
+ bytes = 4;
+ break;
+ case 3:
+ {
+ dptr = data.m_statKey;
+ const uchar* p = (uchar*)dptr;
+ ndbrequire(p != 0);
+ bytes = 2 + p[0] + (p[1] << 8);
+ }
+ break;
+ case 4:
+ {
+ dptr = data.m_statValue;
+ const uchar* p = (uchar*)dptr;
+ ndbrequire(p != 0);
+ bytes = 2 + p[0] + (p[1] << 8);
+ }
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }
+ return;
+ }
+
+ ndbrequire(false);
+}
+
+void
+Trix::statDataOut(StatOp& stat, Uint32 i)
+{
+ StatOp::Attr& attr = stat.m_attr;
+ Uint32* dptr = 0;
+ Uint32 bytes = 0;
+ statDataPtr(stat, i, dptr, bytes);
+
+ ndbrequire(attr.m_attrSize + 1 <= attr.m_attrMax);
+ AttributeHeader::init(&attr.m_attr[attr.m_attrSize], i, bytes);
+ attr.m_attrSize++;
+
+ Uint32 words = (bytes + 3) / 4;
+ ndbrequire(attr.m_dataSize + words <= attr.m_dataMax);
+ Uint8* dst = (Uint8*)&attr.m_data[attr.m_dataSize];
+ memcpy(dst, dptr, bytes);
+ while (bytes < words * 4)
+ dst[bytes++] = 0;
+ attr.m_dataSize += words;
+ D("statDataOut" << V(i) << V(bytes) << hex << V(dptr[0]));
+}
+
+void
+Trix::statDataIn(StatOp& stat, Uint32 i)
+{
+ StatOp::Attr& attr = stat.m_attr;
+ Uint32* dptr = 0;
+ Uint32 bytes = 0;
+ statDataPtr(stat, i, dptr, bytes);
+
+ ndbrequire(attr.m_attrSize + 1 <= attr.m_attrMax);
+ const AttributeHeader& ah = attr.m_attr[attr.m_attrSize];
+ attr.m_attrSize++;
+
+ ndbrequire(ah.getByteSize() == bytes);
+ Uint32 words = (bytes + 3) / 4;
+ ndbrequire(attr.m_dataSize + words <= attr.m_dataMax);
+ const char* src = (const char*)&attr.m_data[attr.m_dataSize];
+ memcpy(dptr, src, bytes);
+ attr.m_dataSize += words;
+ D("statDataIn" << V(i) << V(bytes) << hex << V(dptr[0]));
+}
+
+// abort ongoing
+
+void
+Trix::statAbortUtil(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ D("statAbortUtil" << V(stat));
+
+ ndbrequire(util.m_prepareId != RNIL);
+ util.m_cb.m_callbackFunction = safe_cast(&Trix::statAbortUtilCB);
+ util.m_cb.m_callbackData = stat.m_ownPtrI;
+ statUtilRelease(signal, stat);
+}
+
+void
+Trix::statAbortUtilCB(Signal* signal, Uint32 statPtrI, Uint32 ret)
+{
+ StatOp& stat = statOpGetPtr(statPtrI);
+ D("statAbortUtilCB" << V(stat) << V(ret));
+
+ ndbrequire(ret == 0);
+ statOpAbort(signal, stat);
+}
+
+// conf and ref
+
+void
+Trix::statOpSuccess(Signal* signal, StatOp& stat)
+{
+ StatOp::Data& data = stat.m_data;
+ D("statOpSuccess" << V(stat));
+
+ if (stat.m_requestType == IndexStatReq::RT_SCAN_FRAG)
+ statOpEvent(stat, "I", "created %u samples", data.m_sampleCount);
+
+ statOpConf(signal, stat);
+ statOpRelease(stat);
+}
+
+void
+Trix::statOpConf(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ D("statOpConf" << V(stat));
+
+ IndexStatImplConf* conf = (IndexStatImplConf*)signal->getDataPtrSend();
+ conf->senderRef = reference();
+ conf->senderData = req->senderData;
+ sendSignal(req->senderRef, GSN_INDEX_STAT_IMPL_CONF,
+ signal, IndexStatImplConf::SignalLength, JBB);
+}
+
+void
+Trix::statOpError(Signal* signal, StatOp& stat,
+ Uint32 errorCode, Uint32 errorLine)
+{
+ D("statOpError" << V(stat) << V(errorCode) << V(errorLine));
+
+ statOpEvent(stat, "W", "error %u line %u", errorCode, errorLine);
+
+ ndbrequire(stat.m_errorCode == 0);
+ stat.m_errorCode = errorCode;
+ stat.m_errorLine = errorLine;
+ statOpAbort(signal, stat);
+}
+
+void
+Trix::statOpAbort(Signal* signal, StatOp& stat)
+{
+ StatOp::Util& util = stat.m_util;
+ D("statOpAbort" << V(stat));
+
+ if (util.m_prepareId != RNIL)
+ {
+ jam();
+ // returns here when done
+ statAbortUtil(signal, stat);
+ return;
+ }
+ statOpRef(signal, stat);
+ statOpRelease(stat);
+}
+
+void
+Trix::statOpRef(Signal* signal, StatOp& stat)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ D("statOpRef" << V(stat));
+
+ statOpRef(signal, req, stat.m_errorCode, stat.m_errorLine);
+}
+
+void
+Trix::statOpRef(Signal* signal, const IndexStatImplReq* req,
+ Uint32 errorCode, Uint32 errorLine)
+{
+ D("statOpRef" << V(errorCode) << V(errorLine));
+
+ IndexStatImplRef* ref = (IndexStatImplRef*)signal->getDataPtrSend();
+ ref->senderRef = reference();
+ ref->senderData = req->senderData;
+ ref->errorCode = errorCode;
+ ref->errorLine = errorLine;
+ sendSignal(req->senderRef, GSN_INDEX_STAT_IMPL_REF,
+ signal, IndexStatImplRef::SignalLength, JBB);
+}
+
+void
+Trix::statOpEvent(StatOp& stat, const char* level, const char* msg, ...)
+{
+ const IndexStatImplReq* req = &stat.m_req;
+ StatOp::Data& data = stat.m_data;
+
+ char tmp1[100];
+ va_list ap;
+ va_start(ap, msg);
+ BaseString::vsnprintf(tmp1, sizeof(tmp1), msg, ap);
+ va_end(ap);
+
+ char tmp2[100];
+ BaseString::snprintf(tmp2, sizeof(tmp2),
+ "index %u stats version %u: %s: %s",
+ data.m_indexId, data.m_sampleVersion,
+ stat.m_requestName, tmp1);
+
+ D("statOpEvent" << V(level) << V(tmp2));
+
+ if (level[0] == 'I')
+ infoEvent("%s", tmp2);
+ if (level[0] == 'W')
+ warningEvent("%s", tmp2);
+}
+
+// debug
+
+class NdbOut&
+operator<<(NdbOut& out, const Trix::StatOp& stat)
+{
+ out << "[";
+ out << " i:" << stat.m_ownPtrI;
+ out << " head_found:" << stat.m_data.m_head_found;
+ out << " ]";
+ return out;
+}
+
BLOCK_FUNCTIONS(Trix)
=== modified file 'storage/ndb/src/kernel/blocks/trix/Trix.hpp'
--- a/storage/ndb/src/kernel/blocks/trix/Trix.hpp 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/kernel/blocks/trix/Trix.hpp 2011-05-30 08:24:14 +0000
@@ -25,6 +25,10 @@
#include <signaldata/DictTabInfo.hpp>
#include <signaldata/CreateTrig.hpp>
#include <signaldata/BuildIndx.hpp>
+#include <signaldata/IndexStatSignal.hpp>
+#include <signaldata/GetTabInfo.hpp>
+#include <signaldata/TuxBound.hpp>
+#define ZNOT_FOUND 626
// Error codes
#define INTERNAL_ERROR_ILLEGAL_CALL 4344
@@ -46,6 +50,9 @@ public:
REORG_COPY = 0
,REORG_DELETE = 1
,INDEX_BUILD = 2
+ ,STAT_UTIL = 3 // PK op of HEAD table directly via DBUTIL
+ ,STAT_CLEAN = 4
+ ,STAT_SCAN = 5
//ALTER_TABLE
};
typedef DataBuffer<11> AttrOrderBuffer;
@@ -126,6 +133,7 @@ private:
Uint32 noOfKeyColumns;
Uint32 parallelism;
Uint32 fragCount;
+ Uint32 fragId;
Uint32 syncPtr;
BuildIndxRef::ErrorCode errorCode;
bool subscriptionCreated;
@@ -133,6 +141,7 @@ private:
Uint32 expectedConf; // Count in n UTIL_EXECUTE_CONF + 1 SUB_SYNC_CONF
Uint64 m_rows_processed;
Uint64 m_gci;
+ Uint32 m_statPtrI;
union {
Uint32 nextPool;
Uint32 nextList;
@@ -153,6 +162,127 @@ private:
*/
DLList<SubscriptionRecord> c_theSubscriptions;
+ /*
+ * Ordered index stats. Implements sub-ops of DBDICT index stat
+ * schema op. Each sub-op is a simple REQ which seizes and releases
+ * a stat op here before returning CONF or REF. A stat op always has
+ * an associated SubscriptionRecord. It is used for SUMA index scans
+ * and as proxy for PK ops to DBUTIL.
+ */
+
+ bool c_statGetMetaDone;
+ struct SysColumn {
+ Uint32 pos;
+ const char* name;
+ bool keyFlag;
+ };
+ struct SysTable {
+ const char* name;
+ mutable Uint32 tableId;
+ const Uint32 columnCount;
+ const SysColumn* columnList;
+ };
+ struct SysIndex {
+ const char* name;
+ mutable Uint32 tableId;
+ mutable Uint32 indexId;
+ };
+ static const SysColumn g_statMetaHead_column[];
+ static const SysColumn g_statMetaSample_column[];
+ static const SysTable g_statMetaHead;
+ static const SysTable g_statMetaSample;
+ static const SysIndex g_statMetaSampleX1;
+
+ struct StatOp {
+ struct Meta {
+ GetTabInfoConf m_conf;
+ Callback m_cb;
+ };
+ struct Data {
+ Int32 m_head_found;
+ Uint32 m_indexId;
+ Uint32 m_indexVersion;
+ Uint32 m_tableId;
+ Uint32 m_fragCount;
+ Uint32 m_valueFormat;
+ Uint32 m_sampleVersion;
+ Uint32 m_loadTime;
+ Uint32 m_sampleCount;
+ Uint32 m_keyBytes;
+ Uint32* m_statKey;
+ Uint32* m_statValue;
+ Data() {
+ m_head_found = -1;
+ m_sampleVersion = 0;
+ }
+ };
+ struct Attr {
+ Uint32* m_attr;
+ Uint32 m_attrMax;
+ Uint32 m_attrSize;
+ Uint32* m_data;
+ Uint32 m_dataMax;
+ Uint32 m_dataSize;
+ Attr() {}
+ };
+ struct Util {
+ Uint32 m_prepareId;
+ bool m_not_found;
+ Callback m_cb;
+ Util() {
+ m_prepareId = RNIL;
+ m_not_found = false; // read + ZNOT_FOUND
+ };
+ };
+ struct Clean {
+ Uint32 m_cleanCount;
+ // bounds on index_id, index_version, sample_version
+ Uint32 m_bound[3 * 3];
+ Uint32 m_boundCount;
+ Uint32 m_boundSize;
+ Clean() {}
+ };
+ struct Scan {
+ Uint32 m_sampleCount;
+ Uint32 m_keyBytes;
+ Scan() {}
+ };
+ struct Drop {
+ };
+ struct Send {
+ const SysTable* m_sysTable;
+ Uint32 m_operationType; // UtilPrepareReq::OperationTypeValue
+ Uint32 m_prepareId;
+ Send() {}
+ };
+ IndexStatImplReq m_req;
+ Uint32 m_requestType;
+ const char* m_requestName;
+ Uint32 m_subRecPtrI;
+ Meta m_meta;
+ Data m_data;
+ Attr m_attr;
+ Util m_util;
+ Clean m_clean;
+ Scan m_scan;
+ Drop m_drop;
+ Send m_send;
+ Uint32 m_errorCode;
+ Uint32 m_errorLine;
+ union {
+ Uint32 m_ownPtrI;
+ Uint32 nextPool;
+ };
+ StatOp() {
+ m_subRecPtrI = RNIL;
+ m_errorCode = 0;
+ m_errorLine = 0;
+ };
+ };
+ typedef Ptr<StatOp> StatOpPtr;
+ ArrayPool<StatOp> c_statOpPool;
+ RSS_AP_SNAPSHOT(c_statOpPool);
+
// System start
void execREAD_CONFIG_REQ(Signal* signal);
void execSTTOR(Signal* signal);
@@ -208,6 +338,83 @@ private:
SubscriptionRecPtr subRecPtr,
BuildIndxRef::ErrorCode);
void checkParallelism(Signal* signal, SubscriptionRecord* subRec);
+
+ // index stats
+ StatOp& statOpGetPtr(Uint32 statPtrI);
+ bool statOpSeize(Uint32& statPtrI);
+ void statOpRelease(StatOp&);
+ void execINDEX_STAT_IMPL_REQ(Signal*);
+ // sys tables metadata
+ void statMetaGetHead(Signal*, StatOp&);
+ void statMetaGetHeadCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void statMetaGetSample(Signal*, StatOp&);
+ void statMetaGetSampleCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void statMetaGetSampleX1(Signal*, StatOp&);
+ void statMetaGetSampleX1CB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void sendGetTabInfoReq(Signal*, StatOp&, const char* name);
+ void execGET_TABINFO_CONF(Signal*);
+ void execGET_TABINFO_REF(Signal*);
+ // continue
+ void statGetMetaDone(Signal*, StatOp&);
+ // head table ops
+ void statHeadRead(Signal*, StatOp&);
+ void statHeadReadCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void statHeadInsert(Signal*, StatOp&);
+ void statHeadInsertCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void statHeadUpdate(Signal*, StatOp&);
+ void statHeadUpdateCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ void statHeadDelete(Signal*, StatOp&);
+ void statHeadDeleteCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ // util
+ void statUtilPrepare(Signal*, StatOp&);
+ void statUtilPrepareConf(Signal*, Uint32 statPtrI);
+ void statUtilPrepareRef(Signal*, Uint32 statPtrI);
+ void statUtilExecute(Signal*, StatOp&);
+ void statUtilExecuteConf(Signal*, Uint32 statPtrI);
+ void statUtilExecuteRef(Signal*, Uint32 statPtrI);
+ void statUtilRelease(Signal*, StatOp&);
+ void statUtilReleaseConf(Signal*, Uint32 statPtrI);
+ // continue
+ void statReadHeadDone(Signal*, StatOp&);
+ void statInsertHeadDone(Signal*, StatOp&);
+ void statUpdateHeadDone(Signal*, StatOp&);
+ void statDeleteHeadDone(Signal*, StatOp&);
+ // clean
+ void statCleanBegin(Signal*, StatOp&);
+ void statCleanPrepare(Signal*, StatOp&);
+ void statCleanExecute(Signal*, StatOp&);
+ void statCleanRelease(Signal*, StatOp&);
+ void statCleanEnd(Signal*, StatOp&);
+ // scan
+ void statScanBegin(Signal*, StatOp&);
+ void statScanPrepare(Signal*, StatOp&);
+ void statScanExecute(Signal*, StatOp&);
+ void statScanRelease(Signal*, StatOp&);
+ void statScanEnd(Signal*, StatOp&);
+ // drop
+ void statDropBegin(Signal*, StatOp&);
+ void statDropEnd(Signal*, StatOp&);
+ // send
+ void statSendPrepare(Signal*, StatOp&);
+ void statSendExecute(Signal*, StatOp&);
+ void statSendRelease(Signal*, StatOp&);
+ // data
+ void statDataPtr(StatOp&, Uint32 i, Uint32*& dptr, Uint32& bytes);
+ void statDataOut(StatOp&, Uint32 i);
+ void statDataIn(StatOp&, Uint32 i);
+ // abort ongoing
+ void statAbortUtil(Signal*, StatOp&);
+ void statAbortUtilCB(Signal*, Uint32 statPtrI, Uint32 ret);
+ // conf and ref
+ void statOpSuccess(Signal*, StatOp&);
+ void statOpConf(Signal*, StatOp&);
+ void statOpError(Signal*, StatOp&, Uint32 errorCode, Uint32 errorLine);
+ void statOpAbort(Signal*, StatOp&);
+ void statOpRef(Signal*, StatOp&);
+ void statOpRef(Signal*, const IndexStatImplReq*, Uint32 errorCode, Uint32 errorLine);
+ void statOpEvent(StatOp&, const char* level, const char* msg, ...);
+ // debug
+ friend class NdbOut& operator<<(NdbOut&, const StatOp& stat);
};
#endif
=== modified file 'storage/ndb/src/mgmsrv/ConfigInfo.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigInfo.cpp 2011-04-19 13:47:33 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp 2011-05-19 09:16:32 +0000
@@ -1985,6 +1985,114 @@ const ConfigInfo::ParamInfo ConfigInfo::
STR_VALUE(MAX_INT_RNIL) /* Max */
},
+ /* ordered index stats */
+
+ {
+ CFG_DB_INDEX_STAT_AUTO_CREATE,
+ "IndexStatAutoCreate",
+ DB_TOKEN,
+ "Make create index also create initial index stats",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "1"
+ },
+
+ {
+ CFG_DB_INDEX_STAT_AUTO_UPDATE,
+ "IndexStatAutoUpdate",
+ DB_TOKEN,
+ "Monitor each index for changes and trigger automatic stats updates."
+ " See IndexStatTrigger options",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "1"
+ },
+
+ {
+ CFG_DB_INDEX_STAT_SAVE_SIZE,
+ "IndexStatSaveSize",
+ DB_TOKEN,
+ "Maximum bytes allowed for the saved stats of one index."
+ " At least 1 sample is produced regardless of size limit."
+ " The size is scaled up by a factor from IndexStatSaveScale."
+ " The value affects size of stats saved in NDB system tables"
+ " and in mysqld memory cache",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "32768",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
+ {
+ CFG_DB_INDEX_STAT_SAVE_SCALE,
+ "IndexStatSaveScale",
+ DB_TOKEN,
+ "Factor to scale up IndexStatSaveSize for a large index."
+ " Given in units of 0.01."
+ " Multiplied by a logarithmic index size."
+ " Value 0 disables scaling",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "100",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
+ {
+ CFG_DB_INDEX_STAT_TRIGGER_PCT,
+ "IndexStatTriggerPct",
+ DB_TOKEN,
+ "Percent change (in DML ops) to schedule index stats update."
+ " The value is scaled down by a factor from IndexStatTriggerScale."
+ " Value 0 disables the trigger",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "100",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
+ {
+ CFG_DB_INDEX_STAT_TRIGGER_SCALE,
+ "IndexStatTriggerScale",
+ DB_TOKEN,
+ "Factor to scale down IndexStatTriggerPct for a large index."
+ " Given in units of 0.01."
+ " Multiplied by a logarithmic index size."
+ " Value 0 disables scaling",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "100",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
+ {
+ CFG_DB_INDEX_STAT_UPDATE_DELAY,
+ "IndexStatUpdateDelay",
+ DB_TOKEN,
+ "Minimum delay in seconds between automatic index stats updates"
+ " for a given index."
+ " Value 0 means no delay",
+ ConfigInfo::CI_USED,
+ 0,
+ ConfigInfo::CI_INT,
+ "60",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
/***************************************************************************
* API
***************************************************************************/
=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c 2011-05-25 13:19:02 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c 2011-05-31 08:28:58 +0000
@@ -449,6 +449,13 @@ ErrorBundle ErrorCodes[] = {
{ 908, DMEC, IS, "Invalid ordered index tree node size" },
{ 909, DMEC, IE, "No free index scan op" },
{ 910, HA_ERR_NO_SUCH_TABLE, SE, "Index is being dropped" },
+ { 913, DMEC, AE, "Invalid index for index state update" },
+ { 914, DMEC, IE, "Invalid index stats request" },
+ { 915, DMEC, TR, "No free index stats op" },
+ { 916, DMEC, IE, "Invalid index stats sys tables" },
+ { 917, DMEC, IE, "Invalid index stats sys tables data" },
+ { 918, DMEC, TR, "Cannot prepare index stats update" },
+ { 919, DMEC, TR, "Cannot execute index stats update" },
{ 1224, HA_WRONG_CREATE_OPTION, SE, "Too many fragments" },
{ 1225, DMEC, SE, "Table not defined in local query handler" },
{ 1226, DMEC, SE, "Table is being dropped" },
@@ -529,6 +536,16 @@ ErrorBundle ErrorCodes[] = {
{ 1702, DMEC, AE, "Node already connected" },
{ 1703, DMEC, IT, "Node failure handling not completed" },
{ 1704, DMEC, AE, "Node type mismatch" },
+
+ /*
+ * Index stats error codes
+ */
+ { 4714, DMEC, AE, "Index stats sys tables " NDB_INDEX_STAT_PREFIX " are invalid" },
+ { 4715, DMEC, AE, "Index stats for specified index do not exist" },
+ { 4716, DMEC, AE, "Index stats methods usage error" },
+ { 4717, DMEC, AE, "Index stats cannot allocate memory" },
+ { 4718, DMEC, IE, "Index stats memory cache is corrupted" },
+ { 4719, DMEC, IE, "Index stats internal error" },
/**
* Still uncategorized
@@ -554,6 +571,7 @@ ErrorBundle ErrorCodes[] = {
{ 1425, DMEC, SE, "Subscription being defined...while trying to stop subscriber" },
{ 1426, DMEC, SE, "No such subscriber" },
{ 1427, DMEC, NR, "Api node died, when SUB_START_REQ reached node "},
+ { 1428, DMEC, IE, "No replica to scan on this node (internal index stats error)" },
{ 4004, DMEC, AE, "Attribute name or id not found in the table" },
=== modified file 'storage/ndb/tools/restore/Restore.cpp'
--- a/storage/ndb/tools/restore/Restore.cpp 2011-04-04 09:41:30 +0000
+++ b/storage/ndb/tools/restore/Restore.cpp 2011-05-31 08:28:58 +0000
@@ -523,6 +523,10 @@ RestoreMetaData::markSysTables()
strcmp(tableName, "NDB$EVENTS_0") == 0 ||
strcmp(tableName, "sys/def/SYSTAB_0") == 0 ||
strcmp(tableName, "sys/def/NDB$EVENTS_0") == 0 ||
+ // index stats tables and indexes
+ strncmp(tableName, NDB_INDEX_STAT_PREFIX,
+ sizeof(NDB_INDEX_STAT_PREFIX)-1) == 0 ||
+ strstr(tableName, "/" NDB_INDEX_STAT_PREFIX) != 0 ||
/*
The following is for old MySQL versions,
before we changed the database name of the tables from
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0 branch (jonas:4427 to 4428) | Jonas Oreland | 31 May |