From cae0b6f9a86ac54968858b669fb9658b6d5b08f5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 19 Jan 2006 14:01:32 +0100 Subject: [PATCH 01/15] ndb - wl#2972 rbr blobs ndb api support storage/ndb/include/ndbapi/NdbBlob.hpp: rbr blobs ndb api support storage/ndb/include/ndbapi/NdbDictionary.hpp: rbr blobs ndb api support storage/ndb/include/ndbapi/NdbEventOperation.hpp: rbr blobs ndb api support storage/ndb/ndbapi-examples/ndbapi_event/Makefile: rbr blobs ndb api support storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbBlob.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbDictionary.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbEventOperation.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: rbr blobs ndb api support storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp: rbr blobs ndb api support storage/ndb/test/ndbapi/test_event_merge.cpp: rbr blobs ndb api support --- storage/ndb/include/ndbapi/NdbBlob.hpp | 38 +- storage/ndb/include/ndbapi/NdbDictionary.hpp | 20 +- .../ndb/include/ndbapi/NdbEventOperation.hpp | 8 + .../ndb/ndbapi-examples/ndbapi_event/Makefile | 6 +- .../ndbapi_event/ndbapi_event.cpp | 169 +++++-- storage/ndb/src/ndbapi/NdbBlob.cpp | 267 ++++++++-- storage/ndb/src/ndbapi/NdbDictionary.cpp | 5 + storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp | 90 +++- storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp | 5 +- storage/ndb/src/ndbapi/NdbEventOperation.cpp | 12 + .../ndb/src/ndbapi/NdbEventOperationImpl.cpp | 478 ++++++++++++++++-- .../ndb/src/ndbapi/NdbEventOperationImpl.hpp | 39 +- storage/ndb/test/ndbapi/test_event_merge.cpp | 144 +++--- 13 files changed, 1057 insertions(+), 224 deletions(-) diff --git a/storage/ndb/include/ndbapi/NdbBlob.hpp b/storage/ndb/include/ndbapi/NdbBlob.hpp index cb0caafe34f..5d6022862b8 100644 --- a/storage/ndb/include/ndbapi/NdbBlob.hpp +++ b/storage/ndb/include/ndbapi/NdbBlob.hpp @@ -28,6 +28,7 @@ class NdbOperation; class NdbRecAttr; class NdbTableImpl; class NdbColumnImpl; +class NdbEventOperationImpl; /** * @class NdbBlob @@ -71,6 +72,10 @@ class NdbColumnImpl; * writes. It avoids execute penalty if nothing is pending. It is not * needed after execute (obviously) or after next scan result. * + * NdbBlob also supports reading post or pre blob data from events. The + * handle can be read after next event on main table has been retrieved. + * The data is available immediately. See NdbEventOperation. + * * NdbBlob methods return -1 on error and 0 on success, and use output * parameters when necessary. * @@ -145,6 +150,12 @@ public: * then the callback is invoked. */ int setActiveHook(ActiveHook* activeHook, void* arg); + /** + * Check if blob value is defined (NULL or not). Used as first call + * on event based blob. The argument is set to -1 for not defined. + * Unlike getNull() this does not cause error on the handle. + */ + int getDefined(int& isNull); /** * Check if blob is null. */ @@ -191,6 +202,11 @@ public: * Get blob parts table name. Useful only to test programs. */ static int getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName); + /** + * Get blob event name. The blob event is created if the main event + * monitors the blob column. The name includes main event name. + */ + static int getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName); /** * Return error object. The error may be blob specific (below) or may * be copied from a failed implicit operation. @@ -217,17 +233,29 @@ private: friend class NdbScanOperation; friend class NdbDictionaryImpl; friend class NdbResultSet; // atNextResult + friend class NdbEventBuffer; + friend class NdbEventOperationImpl; #endif // state State theState; void setState(State newState); + // quick and dirty support for events (consider subclassing) + int theEventBlobVersion; // -1=normal blob 0=post event 1=pre event // define blob table static void getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c); static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c); + static void getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c); + static void getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c); // ndb api stuff Ndb* theNdb; NdbTransaction* theNdbCon; NdbOperation* theNdbOp; + NdbEventOperationImpl* theEventOp; + NdbEventOperationImpl* theBlobEventOp; + NdbRecAttr* theBlobEventPkRecAttr; + NdbRecAttr* theBlobEventDistRecAttr; + NdbRecAttr* theBlobEventPartRecAttr; + NdbRecAttr* theBlobEventDataRecAttr; const NdbTableImpl* theTable; const NdbTableImpl* theAccessTable; const NdbTableImpl* theBlobTable; @@ -263,6 +291,8 @@ private: Buf theHeadInlineBuf; Buf theHeadInlineCopyBuf; // for writeTuple Buf thePartBuf; + Buf theBlobEventDataBuf; + Uint32 thePartNumber; // for event Head* theHead; char* theInlineData; NdbRecAttr* theHeadInlineRecAttr; @@ -306,6 +336,8 @@ private: int readDataPrivate(char* buf, Uint32& bytes); int writeDataPrivate(const char* buf, Uint32 bytes); int readParts(char* buf, Uint32 part, Uint32 count); + int readTableParts(char* buf, Uint32 part, Uint32 count); + int readEventParts(char* buf, Uint32 part, Uint32 count); int insertParts(const char* buf, Uint32 part, Uint32 count); int updateParts(const char* buf, Uint32 part, Uint32 count); int deleteParts(Uint32 part, Uint32 count); @@ -317,19 +349,23 @@ private: int invokeActiveHook(); // blob handle maintenance int atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn); + int atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version); + int prepareColumn(); int preExecute(NdbTransaction::ExecType anExecType, bool& batch); int postExecute(NdbTransaction::ExecType anExecType); int preCommit(); int atNextResult(); + int atNextEvent(); // errors void setErrorCode(int anErrorCode, bool invalidFlag = true); void setErrorCode(NdbOperation* anOp, bool invalidFlag = true); void setErrorCode(NdbTransaction* aCon, bool invalidFlag = true); + void setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag = true); #ifdef VM_TRACE int getOperationType() const; friend class NdbOut& operator<<(NdbOut&, const NdbBlob&); #endif - + // list stuff void next(NdbBlob* obj) { theNext= obj;} NdbBlob* next() { return theNext;} friend struct Ndb_free_list_t; diff --git a/storage/ndb/include/ndbapi/NdbDictionary.hpp b/storage/ndb/include/ndbapi/NdbDictionary.hpp index 6f8ead63a81..dd3d06f419e 100644 --- a/storage/ndb/include/ndbapi/NdbDictionary.hpp +++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp @@ -1124,7 +1124,7 @@ public: _TE_NODE_FAILURE=10, _TE_SUBSCRIBE=11, _TE_UNSUBSCRIBE=12, - _TE_NUL=13 // internal (INS o DEL within same GCI) + _TE_NUL=13 // internal (e.g. INS o DEL within same GCI) }; #endif /** @@ -1261,6 +1261,24 @@ public: */ int getNoOfEventColumns() const; + /** + * The merge events flag is false by default. Setting it true + * implies that events are merged in following ways: + * + * - for given NdbEventOperation associated with this event, + * events on same PK within same GCI are merged into single event + * + * - a blob table event is created for each blob attribute + * and blob events are handled as part of main table events + * + * - blob post/pre data from the blob part events can be read + * via NdbBlob methods as a single value + * + * NOTE: Currently this flag is not inherited by NdbEventOperation + * and must be set on NdbEventOperation explicitly. + */ + void mergeEvents(bool flag); + /** * Get object status */ diff --git a/storage/ndb/include/ndbapi/NdbEventOperation.hpp b/storage/ndb/include/ndbapi/NdbEventOperation.hpp index 5992fc2b036..4a9dd6cd295 100644 --- a/storage/ndb/include/ndbapi/NdbEventOperation.hpp +++ b/storage/ndb/include/ndbapi/NdbEventOperation.hpp @@ -150,6 +150,14 @@ public: */ NdbRecAttr *getPreValue(const char *anAttrName, char *aValue = 0); + /** + * These methods replace getValue/getPreValue for blobs. Each + * method creates a blob handle NdbBlob. The handle supports only + * read operations. See NdbBlob. + */ + NdbBlob* getBlobHandle(const char *anAttrName); + NdbBlob* getPreBlobHandle(const char *anAttrName); + int isOverrun() const; /** diff --git a/storage/ndb/ndbapi-examples/ndbapi_event/Makefile b/storage/ndb/ndbapi-examples/ndbapi_event/Makefile index 54c4c903a56..a3ca6fd61e3 100644 --- a/storage/ndb/ndbapi-examples/ndbapi_event/Makefile +++ b/storage/ndb/ndbapi-examples/ndbapi_event/Makefile @@ -4,7 +4,7 @@ OBJS = ndbapi_event.o CXX = g++ -g CFLAGS = -c -Wall -fno-rtti -fno-exceptions CXXFLAGS = -DEBUG = +DEBUG =# -DVM_TRACE LFLAGS = -Wall TOP_SRCDIR = ../../../.. INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include @@ -16,8 +16,8 @@ SYS_LIB = $(TARGET): $(OBJS) $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET) -$(TARGET).o: $(SRCS) - $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi -I$(TOP_SRCDIR)/include $(SRCS) +$(TARGET).o: $(SRCS) Makefile + $(CXX) $(CFLAGS) $(DEBUG) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi -I$(TOP_SRCDIR)/include $(SRCS) clean: rm -f *.o $(TARGET) diff --git a/storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp b/storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp index 98b34e51e27..328d43caf28 100644 --- a/storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp +++ b/storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp @@ -54,26 +54,32 @@ #include #include #include +#ifdef VM_TRACE +#include +#endif +#ifndef assert +#include +#endif /** - * - * Assume that there is a table t0 which is being updated by + * Assume that there is a table which is being updated by * another process (e.g. flexBench -l 0 -stdtables). - * We want to monitor what happens with columns c0,c1,c2,c3. + * We want to monitor what happens with column values. * - * or together with the mysql client; + * Or using the mysql client: * * shell> mysql -u root * mysql> create database TEST_DB; * mysql> use TEST_DB; - * mysql> create table t0 (c0 int, c1 int, c2 char(4), c3 char(4), + * mysql> create table t0 + * (c0 int, c1 int, c2 char(4), c3 char(4), c4 text, * primary key(c0, c2)) engine ndb charset latin1; * * In another window start ndbapi_event, wait until properly started - * - insert into t0 values (1, 2, 'a', 'b'); - insert into t0 values (3, 4, 'c', 'd'); + + insert into t0 values (1, 2, 'a', 'b', null); + insert into t0 values (3, 4, 'c', 'd', null); update t0 set c3 = 'e' where c0 = 1 and c2 = 'a'; -- use pk update t0 set c3 = 'f'; -- use scan update t0 set c3 = 'F'; -- use scan update to 'same' @@ -81,7 +87,18 @@ update t0 set c2 = 'G' where c0 = 1; -- update pk part to 'same' update t0 set c0 = 5, c2 = 'H' where c0 = 3; -- update full PK delete from t0; - * + + insert ...; update ...; -- see events w/ same pk merged (if -m option) + delete ...; insert ...; -- there are 5 combinations ID IU DI UD UU + update ...; update ...; + + -- text requires -m flag + set @a = repeat('a',256); -- inline size + set @b = repeat('b',2000); -- part size + set @c = repeat('c',2000*30); -- 30 parts + + -- update the text field using combinations of @a, @b, @c ... + * you should see the data popping up in the example window * */ @@ -95,12 +112,18 @@ int myCreateEvent(Ndb* myNdb, const char *eventName, const char *eventTableName, const char **eventColumnName, - const int noEventColumnName); + const int noEventColumnName, + bool merge_events); int main(int argc, char** argv) { ndb_init(); - bool merge_events = argc > 1 && strcmp(argv[1], "-m") == 0; + bool merge_events = argc > 1 && strchr(argv[1], 'm') != 0; +#ifdef VM_TRACE + bool dbug = argc > 1 && strchr(argv[1], 'd') != 0; + if (dbug) DBUG_PUSH("d:t:"); + if (dbug) putenv("API_SIGNAL_LOG=-"); +#endif Ndb_cluster_connection *cluster_connection= new Ndb_cluster_connection(); // Object representing the cluster @@ -134,12 +157,13 @@ int main(int argc, char** argv) const char *eventName= "CHNG_IN_t0"; const char *eventTableName= "t0"; - const int noEventColumnName= 4; + const int noEventColumnName= 5; const char *eventColumnName[noEventColumnName]= {"c0", "c1", "c2", - "c3" + "c3", + "c4" }; // Create events @@ -147,9 +171,14 @@ int main(int argc, char** argv) eventName, eventTableName, eventColumnName, - noEventColumnName); + noEventColumnName, + merge_events); - int j= 0; + // Normal values and blobs are unfortunately handled differently.. + typedef union { NdbRecAttr* ra; NdbBlob* bh; } RA_BH; + + int i, j, k, l; + j = 0; while (j < 99) { // Start "transaction" for handling events @@ -160,12 +189,17 @@ int main(int argc, char** argv) op->mergeEvents(merge_events); printf("get values\n"); - NdbRecAttr* recAttr[noEventColumnName]; - NdbRecAttr* recAttrPre[noEventColumnName]; + RA_BH recAttr[noEventColumnName]; + RA_BH recAttrPre[noEventColumnName]; // primary keys should always be a part of the result - for (int i = 0; i < noEventColumnName; i++) { - recAttr[i] = op->getValue(eventColumnName[i]); - recAttrPre[i] = op->getPreValue(eventColumnName[i]); + for (i = 0; i < noEventColumnName; i++) { + if (i < 4) { + recAttr[i].ra = op->getValue(eventColumnName[i]); + recAttrPre[i].ra = op->getPreValue(eventColumnName[i]); + } else if (merge_events) { + recAttr[i].bh = op->getBlobHandle(eventColumnName[i]); + recAttrPre[i].bh = op->getPreBlobHandle(eventColumnName[i]); + } } // set up the callbacks @@ -174,13 +208,16 @@ int main(int argc, char** argv) if (op->execute()) APIERROR(op->getNdbError()); - int i= 0; - while(i < 40) { + NdbEventOperation* the_op = op; + + i= 0; + while (i < 40) { // printf("now waiting for event...\n"); - int r= myNdb->pollEvents(1000); // wait for event or 1000 ms + int r = myNdb->pollEvents(1000); // wait for event or 1000 ms if (r > 0) { // printf("got data! %d\n", r); while ((op= myNdb->nextEvent())) { + assert(the_op == op); i++; switch (op->getEventType()) { case NdbDictionary::Event::TE_INSERT: @@ -195,40 +232,66 @@ int main(int argc, char** argv) default: abort(); // should not happen } - printf(" gci=%d\n", op->getGCI()); - printf("post: "); - for (int i = 0; i < noEventColumnName; i++) { - if (recAttr[i]->isNULL() >= 0) { // we have a value - if (recAttr[i]->isNULL() == 0) { // we have a non-null value - if (i < 2) - printf("%-5u", recAttr[i]->u_32_value()); - else - printf("%-5.4s", recAttr[i]->aRef()); - } else // we have a null value - printf("%-5s", "NULL"); - } else - printf("%-5s", "-"); + printf(" gci=%d\n", (int)op->getGCI()); + for (k = 0; k <= 1; k++) { + printf(k == 0 ? "post: " : "pre : "); + for (l = 0; l < noEventColumnName; l++) { + if (l < 4) { + NdbRecAttr* ra = k == 0 ? recAttr[l].ra : recAttrPre[l].ra; + if (ra->isNULL() >= 0) { // we have a value + if (ra->isNULL() == 0) { // we have a non-null value + if (l < 2) + printf("%-5u", ra->u_32_value()); + else + printf("%-5.4s", ra->aRef()); + } else + printf("%-5s", "NULL"); + } else + printf("%-5s", "-"); // no value + } else if (merge_events) { + int isNull; + NdbBlob* bh = k == 0 ? recAttr[l].bh : recAttrPre[l].bh; + bh->getDefined(isNull); + if (isNull >= 0) { // we have a value + if (! isNull) { // we have a non-null value + Uint64 length = 0; + bh->getLength(length); + // read into buffer + unsigned char* buf = new unsigned char [length]; + memset(buf, 'X', length); + Uint32 n = length; + bh->readData(buf, n); // n is in/out + assert(n == length); + // pretty-print + bool first = true; + Uint32 i = 0; + while (i < n) { + unsigned char c = buf[i++]; + Uint32 m = 1; + while (i < n && buf[i] == c) + i++, m++; + if (! first) + printf("+"); + printf("%u%c", m, c); + first = false; + } + printf("[%u]", n); + delete [] buf; + } else + printf("%-5s", "NULL"); + } else + printf("%-5s", "-"); // no value + } + } + printf("\n"); } - printf("\npre : "); - for (int i = 0; i < noEventColumnName; i++) { - if (recAttrPre[i]->isNULL() >= 0) { // we have a value - if (recAttrPre[i]->isNULL() == 0) { // we have a non-null value - if (i < 2) - printf("%-5u", recAttrPre[i]->u_32_value()); - else - printf("%-5.4s", recAttrPre[i]->aRef()); - } else // we have a null value - printf("%-5s", "NULL"); - } else - printf("%-5s", "-"); - } - printf("\n"); } } else ;//printf("timed out\n"); } // don't want to listen to events anymore - if (myNdb->dropEventOperation(op)) APIERROR(myNdb->getNdbError()); + if (myNdb->dropEventOperation(the_op)) APIERROR(myNdb->getNdbError()); + the_op = 0; j++; } @@ -250,7 +313,8 @@ int myCreateEvent(Ndb* myNdb, const char *eventName, const char *eventTableName, const char **eventColumnNames, - const int noEventColumnNames) + const int noEventColumnNames, + bool merge_events) { NdbDictionary::Dictionary *myDict= myNdb->getDictionary(); if (!myDict) APIERROR(myNdb->getNdbError()); @@ -265,6 +329,7 @@ int myCreateEvent(Ndb* myNdb, // myEvent.addTableEvent(NdbDictionary::Event::TE_DELETE); myEvent.addEventColumns(noEventColumnNames, eventColumnNames); + myEvent.mergeEvents(merge_events); // Add event to database if (myDict->createEvent(myEvent) == 0) diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 2f5325bd844..375d64c2eab 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -23,6 +23,7 @@ #include #include "NdbBlobImpl.hpp" #include +#include /* * Reading index table directly (as a table) is faster but there are @@ -147,6 +148,61 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnIm DBUG_VOID_RETURN; } +int +NdbBlob::getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char* columnName) +{ + NdbEventImpl* e = anNdb->theDictionary->m_impl.getEvent(eventName); + if (e == NULL) + return -1; + NdbColumnImpl* c = e->m_tableImpl->getColumn(columnName); + if (c == NULL) + return -1; + getBlobEventName(bename, e, c); + return 0; +} + +void +NdbBlob::getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c) +{ + // XXX events should have object id + snprintf(bename, MAX_TAB_NAME_SIZE, "NDB$BLOBEVENT_%s_%d", e->m_name.c_str(), (int)c->m_column_no); +} + +void +NdbBlob::getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c) +{ + DBUG_ENTER("NdbBlob::getBlobEvent"); + // blob table + assert(c->m_blobTable != NULL); + const NdbTableImpl& bt = *c->m_blobTable; + // blob event name + char bename[NdbBlobImpl::BlobTableNameSize]; + getBlobEventName(bename, e, c); + be.setName(bename); + be.setTable(bt); + // simple assigments + be.mi_type = e->mi_type; + be.m_dur = e->m_dur; + be.m_mergeEvents = e->m_mergeEvents; + // report unchanged data + // not really needed now since UPD is DEL o INS and we subscribe to all + be.setReport(NdbDictionary::Event::ER_ALL); + // columns PK - DIST - PART - DATA + { const NdbColumnImpl* bc = bt.getColumn((Uint32)0); + be.addColumn(*bc); + } + { const NdbColumnImpl* bc = bt.getColumn((Uint32)1); + be.addColumn(*bc); + } + { const NdbColumnImpl* bc = bt.getColumn((Uint32)2); + be.addColumn(*bc); + } + { const NdbColumnImpl* bc = bt.getColumn((Uint32)3); + be.addColumn(*bc); + } + DBUG_VOID_RETURN; +} + // initialization NdbBlob::NdbBlob(Ndb*) @@ -158,9 +214,16 @@ void NdbBlob::init() { theState = Idle; + theEventBlobVersion = -1; theNdb = NULL; theNdbCon = NULL; theNdbOp = NULL; + theEventOp = NULL; + theBlobEventOp = NULL; + theBlobEventPkRecAttr = NULL; + theBlobEventDistRecAttr = NULL; + theBlobEventPartRecAttr = NULL; + theBlobEventDataRecAttr = NULL; theTable = NULL; theAccessTable = NULL; theBlobTable = NULL; @@ -439,7 +502,7 @@ NdbBlob::getHeadFromRecAttr() DBUG_ENTER("NdbBlob::getHeadFromRecAttr"); assert(theHeadInlineRecAttr != NULL); theNullFlag = theHeadInlineRecAttr->isNULL(); - assert(theNullFlag != -1); + assert(theEventBlobVersion >= 0 || theNullFlag != -1); theLength = ! theNullFlag ? theHead->length : 0; DBUG_VOID_RETURN; } @@ -543,6 +606,18 @@ NdbBlob::setActiveHook(ActiveHook activeHook, void* arg) // misc operations +int +NdbBlob::getDefined(int& isNull) +{ + DBUG_ENTER("NdbBlob::getDefined"); + if (theState == Prepared && theSetFlag) { + isNull = (theSetBuf == NULL); + DBUG_RETURN(0); + } + isNull = theNullFlag; + DBUG_RETURN(0); +} + int NdbBlob::getNull(bool& isNull) { @@ -887,6 +962,18 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) { DBUG_ENTER("NdbBlob::readParts"); DBUG_PRINT("info", ("part=%u count=%u", part, count)); + int ret; + if (theEventBlobVersion == -1) + ret = readTableParts(buf, part, count); + else + ret = readEventParts(buf, part, count); + DBUG_RETURN(ret); +} + +int +NdbBlob::readTableParts(char* buf, Uint32 part, Uint32 count) +{ + DBUG_ENTER("NdbBlob::readTableParts"); Uint32 n = 0; while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); @@ -906,6 +993,18 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) DBUG_RETURN(0); } +int +NdbBlob::readEventParts(char* buf, Uint32 part, Uint32 count) +{ + DBUG_ENTER("NdbBlob::readEventParts"); + int ret = theEventOp->readBlobParts(buf, this, part, count); + if (ret != 0) { + setErrorCode(theEventOp); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + int NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count) { @@ -1094,48 +1193,12 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl theTable = anOp->m_currentTable; theAccessTable = anOp->m_accessTable; theColumn = aColumn; - NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined; - switch (theColumn->getType()) { - case NdbDictionary::Column::Blob: - partType = NdbDictionary::Column::Binary; - theFillChar = 0x0; - break; - case NdbDictionary::Column::Text: - partType = NdbDictionary::Column::Char; - theFillChar = 0x20; - break; - default: - setErrorCode(NdbBlobImpl::ErrUsage); + // prepare blob column and table + if (prepareColumn() == -1) DBUG_RETURN(-1); - } - // sizes - theInlineSize = theColumn->getInlineSize(); - thePartSize = theColumn->getPartSize(); - theStripeSize = theColumn->getStripeSize(); - // sanity check - assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head)); - assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize); - if (thePartSize > 0) { - const NdbDictionary::Table* bt = NULL; - const NdbDictionary::Column* bc = NULL; - if (theStripeSize == 0 || - (bt = theColumn->getBlobTable()) == NULL || - (bc = bt->getColumn("DATA")) == NULL || - bc->getType() != partType || - bc->getLength() != (int)thePartSize) { - setErrorCode(NdbBlobImpl::ErrTable); - DBUG_RETURN(-1); - } - theBlobTable = &NdbTableImpl::getImpl(*bt); - } - // buffers - theKeyBuf.alloc(theTable->m_keyLenInWords << 2); + // extra buffers theAccessKeyBuf.alloc(theAccessTable->m_keyLenInWords << 2); - theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize); theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize); - thePartBuf.alloc(thePartSize); - theHead = (Head*)theHeadInlineBuf.data; - theInlineData = theHeadInlineBuf.data + sizeof(Head); // handle different operation types bool supportedOp = false; if (isKeyOp()) { @@ -1189,6 +1252,99 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl DBUG_RETURN(0); } +int +NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version) +{ + DBUG_ENTER("NdbBlob::atPrepare [event]"); + DBUG_PRINT("info", ("this=%p op=%p", this, anOp)); + assert(theState == Idle); + assert(version == 0 || version == 1); + theEventBlobVersion = version; + // ndb api stuff + theNdb = anOp->m_ndb; + theEventOp = anOp; + theBlobEventOp = aBlobOp; + theTable = anOp->m_eventImpl->m_tableImpl; + theColumn = aColumn; + // prepare blob column and table + if (prepareColumn() == -1) + DBUG_RETURN(-1); + // extra buffers + theBlobEventDataBuf.alloc(thePartSize); + // prepare receive of head+inline + theHeadInlineRecAttr = theEventOp->getValue(aColumn, theHeadInlineBuf.data, version); + if (theHeadInlineRecAttr == NULL) { + setErrorCode(theEventOp); + DBUG_RETURN(-1); + } + // prepare receive of blob part + if ((theBlobEventPkRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0), + theKeyBuf.data, version)) == NULL || + (theBlobEventDistRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1), + (char*)0, version)) == NULL || + (theBlobEventPartRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)2), + (char*)&thePartNumber, version)) == NULL || + (theBlobEventDataRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)3), + theBlobEventDataBuf.data, version)) == NULL) { + setErrorCode(theBlobEventOp); + DBUG_RETURN(-1); + } + setState(Prepared); + DBUG_RETURN(0); +} + +int +NdbBlob::prepareColumn() +{ + DBUG_ENTER("prepareColumn"); + NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined; + switch (theColumn->getType()) { + case NdbDictionary::Column::Blob: + partType = NdbDictionary::Column::Binary; + theFillChar = 0x0; + break; + case NdbDictionary::Column::Text: + partType = NdbDictionary::Column::Char; + theFillChar = 0x20; + break; + default: + setErrorCode(NdbBlobImpl::ErrUsage); + DBUG_RETURN(-1); + } + // sizes + theInlineSize = theColumn->getInlineSize(); + thePartSize = theColumn->getPartSize(); + theStripeSize = theColumn->getStripeSize(); + // sanity check + assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head)); + assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize); + if (thePartSize > 0) { + const NdbDictionary::Table* bt = NULL; + const NdbDictionary::Column* bc = NULL; + if (theStripeSize == 0 || + (bt = theColumn->getBlobTable()) == NULL || + (bc = bt->getColumn("DATA")) == NULL || + bc->getType() != partType || + bc->getLength() != (int)thePartSize) { + setErrorCode(NdbBlobImpl::ErrTable); + DBUG_RETURN(-1); + } + // blob table + theBlobTable = &NdbTableImpl::getImpl(*bt); + } + // these buffers are always used + theKeyBuf.alloc(theTable->m_keyLenInWords << 2); + theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize); + theHead = (Head*)theHeadInlineBuf.data; + theInlineData = theHeadInlineBuf.data + sizeof(Head); + thePartBuf.alloc(thePartSize); + DBUG_RETURN(0); +} + /* * Before execute of prepared operation. May add new operations before * this one. May ask that this operation and all before it (a "batch") @@ -1537,6 +1693,26 @@ NdbBlob::atNextResult() DBUG_RETURN(0); } +/* + * After next event on main table. + */ +int +NdbBlob::atNextEvent() +{ + DBUG_ENTER("NdbBlob::atNextEvent"); + DBUG_PRINT("info", ("this=%p op=%p blob op=%p version=%d", this, theEventOp, theBlobEventOp, theEventBlobVersion)); + if (theState == Invalid) + DBUG_RETURN(-1); + assert(theEventBlobVersion >= 0); + getHeadFromRecAttr(); + if (theNullFlag == -1) // value not defined + DBUG_RETURN(0); + if (setPos(0) == -1) + DBUG_RETURN(-1); + setState(Active); + DBUG_RETURN(0); +} + // misc const NdbDictionary::Column* @@ -1589,6 +1765,17 @@ NdbBlob::setErrorCode(NdbTransaction* aCon, bool invalidFlag) setErrorCode(code, invalidFlag); } +void +NdbBlob::setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag) +{ + int code = 0; + if ((code = anOp->m_error.code) != 0) + ; + else + code = NdbBlobImpl::ErrUnknown; + setErrorCode(code, invalidFlag); +} + // info about all blobs in this operation NdbBlob* diff --git a/storage/ndb/src/ndbapi/NdbDictionary.cpp b/storage/ndb/src/ndbapi/NdbDictionary.cpp index fd11aed14e3..ac3bb235b8e 100644 --- a/storage/ndb/src/ndbapi/NdbDictionary.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp @@ -901,6 +901,11 @@ int NdbDictionary::Event::getNoOfEventColumns() const return m_impl.getNoOfEventColumns(); } +void NdbDictionary::Event::mergeEvents(bool flag) +{ + m_impl.m_mergeEvents = flag; +} + NdbDictionary::Object::Status NdbDictionary::Event::getObjectStatus() const { diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 5716288263d..355684d218d 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1072,6 +1072,7 @@ void NdbEventImpl::init() m_tableId= RNIL; mi_type= 0; m_dur= NdbDictionary::Event::ED_UNDEFINED; + m_mergeEvents = false; m_tableImpl= NULL; m_rep= NdbDictionary::Event::ER_UPDATED; } @@ -2036,7 +2037,7 @@ int NdbDictionaryImpl::addBlobTables(NdbTableImpl &t) { unsigned n= t.m_noOfBlobs; - DBUG_ENTER("NdbDictioanryImpl::addBlobTables"); + DBUG_ENTER("NdbDictionaryImpl::addBlobTables"); // optimized for blob column being the last one // and not looking for more than one if not neccessary for (unsigned i = t.m_columns.size(); i > 0 && n > 0;) { @@ -3151,7 +3152,37 @@ NdbDictionaryImpl::createEvent(NdbEventImpl & evnt) #endif // NdbDictInterface m_receiver; - DBUG_RETURN(m_receiver.createEvent(m_ndb, evnt, 0 /* getFlag unset */)); + if (m_receiver.createEvent(m_ndb, evnt, 0 /* getFlag unset */) != 0) + DBUG_RETURN(-1); + + // Create blob events + if (evnt.m_mergeEvents && createBlobEvents(evnt) != 0) { + int save_code = m_error.code; + (void)dropEvent(evnt.m_name.c_str()); + m_error.code = save_code; + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + +int +NdbDictionaryImpl::createBlobEvents(NdbEventImpl& evnt) +{ + DBUG_ENTER("NdbDictionaryImpl::createBlobEvents"); + NdbTableImpl& t = *evnt.m_tableImpl; + Uint32 n = t.m_noOfBlobs; + Uint32 i; + for (i = 0; i < evnt.m_columns.size() && n > 0; i++) { + NdbColumnImpl & c = *evnt.m_columns[i]; + if (! c.getBlobType() || c.getPartSize() == 0) + continue; + n--; + NdbEventImpl blob_evnt; + NdbBlob::getBlobEvent(blob_evnt, &evnt, &c); + if (createEvent(blob_evnt) != 0) + DBUG_RETURN(-1); + } + DBUG_RETURN(0); } int @@ -3400,6 +3431,7 @@ NdbDictionaryImpl::getEvent(const char * eventName) if ( attributeList_sz > table.getNoOfColumns() ) { + m_error.code = 241; DBUG_PRINT("error",("Invalid version, too many columns")); delete ev; DBUG_RETURN(NULL); @@ -3409,6 +3441,7 @@ NdbDictionaryImpl::getEvent(const char * eventName) for(unsigned id= 0; ev->m_columns.size() < attributeList_sz; id++) { if ( id >= table.getNoOfColumns()) { + m_error.code = 241; DBUG_PRINT("error",("Invalid version, column %d out of range", id)); delete ev; DBUG_RETURN(NULL); @@ -3566,13 +3599,54 @@ NdbDictInterface::execSUB_START_REF(NdbApiSignal * signal, int NdbDictionaryImpl::dropEvent(const char * eventName) { - NdbEventImpl *ev= new NdbEventImpl(); - ev->setName(eventName); - int ret= m_receiver.dropEvent(*ev); - delete ev; + DBUG_ENTER("NdbDictionaryImpl::dropEvent"); + DBUG_PRINT("info", ("name=%s", eventName)); - // printf("__________________RET %u\n", ret); - return ret; + NdbEventImpl *evnt = getEvent(eventName); // allocated + if (evnt == NULL) { + if (m_error.code != 723 && // no such table + m_error.code != 241) // invalid table + DBUG_RETURN(-1); + DBUG_PRINT("info", ("no table, drop by name alone")); + evnt = new NdbEventImpl(); + evnt->setName(eventName); + } + int ret = dropEvent(*evnt); + delete evnt; + DBUG_RETURN(ret); +} + +int +NdbDictionaryImpl::dropEvent(const NdbEventImpl& evnt) +{ + if (dropBlobEvents(evnt) != 0) + return -1; + if (m_receiver.dropEvent(evnt) != 0) + return -1; + return 0; +} + +int +NdbDictionaryImpl::dropBlobEvents(const NdbEventImpl& evnt) +{ + DBUG_ENTER("NdbDictionaryImpl::dropBlobEvents"); + if (evnt.m_tableImpl != 0) { + const NdbTableImpl& t = *evnt.m_tableImpl; + Uint32 n = t.m_noOfBlobs; + Uint32 i; + for (i = 0; i < evnt.m_columns.size() && n > 0; i++) { + const NdbColumnImpl& c = *evnt.m_columns[i]; + if (! c.getBlobType() || c.getPartSize() == 0) + continue; + n--; + char bename[MAX_TAB_NAME_SIZE]; + NdbBlob::getBlobEventName(bename, &evnt, &c); + (void)dropEvent(bename); + } + } else { + // could loop over MAX_ATTRIBUTES_IN_TABLE ... + } + DBUG_RETURN(0); } int diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp index f812860c164..22fa13a4c71 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -277,7 +277,6 @@ public: NdbDictionary::Event::EventDurability getDurability() const; void setReport(NdbDictionary::Event::EventReport r); NdbDictionary::Event::EventReport getReport() const; - void addEventColumn(const NdbColumnImpl &c); int getNoOfEventColumns() const; void print() { @@ -295,6 +294,7 @@ public: Uint32 mi_type; NdbDictionary::Event::EventDurability m_dur; NdbDictionary::Event::EventReport m_rep; + bool m_mergeEvents; NdbTableImpl *m_tableImpl; BaseString m_tableName; @@ -547,7 +547,10 @@ public: NdbTableImpl * table); int createEvent(NdbEventImpl &); + int createBlobEvents(NdbEventImpl &); int dropEvent(const char * eventName); + int dropEvent(const NdbEventImpl &); + int dropBlobEvents(const NdbEventImpl &); int executeSubscribeEvent(NdbEventOperationImpl &); int stopSubscribeEvent(NdbEventOperationImpl &); diff --git a/storage/ndb/src/ndbapi/NdbEventOperation.cpp b/storage/ndb/src/ndbapi/NdbEventOperation.cpp index e7cc4abbb2a..22e4794775f 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperation.cpp @@ -55,6 +55,18 @@ NdbEventOperation::getPreValue(const char *colName, char *aValue) return m_impl.getValue(colName, aValue, 1); } +NdbBlob * +NdbEventOperation::getBlobHandle(const char *colName) +{ + return m_impl.getBlobHandle(colName, 0); +} + +NdbBlob * +NdbEventOperation::getPreBlobHandle(const char *colName) +{ + return m_impl.getBlobHandle(colName, 1); +} + int NdbEventOperation::execute() { diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 1ab6d4b2a5f..706c921b210 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -38,6 +38,7 @@ #include "DictCache.hpp" #include #include +#include #include #include "NdbEventOperationImpl.hpp" @@ -48,6 +49,20 @@ static Gci_container g_empty_gci_container; static const Uint32 ACTIVE_GCI_DIRECTORY_SIZE = 4; static const Uint32 ACTIVE_GCI_MASK = ACTIVE_GCI_DIRECTORY_SIZE - 1; +#ifdef VM_TRACE +static void +print_std(const SubTableData * sdata, LinearSectionPtr ptr[3]) +{ + printf("addr=%p gci=%d op=%d\n", (void*)sdata, sdata->gci, sdata->operation); + for (int i = 0; i <= 2; i++) { + printf("sec=%d addr=%p sz=%d\n", i, (void*)ptr[i].p, ptr[i].sz); + for (int j = 0; j < ptr[i].sz; j++) + printf("%08x ", ptr[i].p[j]); + printf("\n"); + } +} +#endif + /* * Class NdbEventOperationImpl * @@ -60,7 +75,7 @@ static const Uint32 ACTIVE_GCI_MASK = ACTIVE_GCI_DIRECTORY_SIZE - 1; #define DBUG_RETURN_EVENT(A) DBUG_RETURN(A) #define DBUG_VOID_RETURN_EVENT DBUG_VOID_RETURN #define DBUG_PRINT_EVENT(A,B) DBUG_PRINT(A,B) -#define DBUG_DUMP_EVENT(A,B,C) DBUG_SUMP(A,B,C) +#define DBUG_DUMP_EVENT(A,B,C) DBUG_DUMP(A,B,C) #else #define DBUG_ENTER_EVENT(A) #define DBUG_RETURN_EVENT(A) return(A) @@ -92,6 +107,11 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N, theCurrentDataAttrs[0] = NULL; theFirstDataAttrs[1] = NULL; theCurrentDataAttrs[1] = NULL; + + theBlobList = NULL; + theBlobOpList = NULL; + theMainOp = NULL; + m_data_item= NULL; m_eventImpl = NULL; @@ -117,7 +137,11 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N, m_state= EO_CREATED; - m_mergeEvents = false; +#ifdef ndb_event_stores_merge_events_flag + m_mergeEvents = m_eventImpl->m_mergeEvents; +#else + m_mergeEvents = false; +#endif m_has_error= 0; @@ -254,10 +278,183 @@ NdbEventOperationImpl::getValue(const NdbColumnImpl *tAttrInfo, char *aValue, in DBUG_RETURN(tAttr); } +NdbBlob* +NdbEventOperationImpl::getBlobHandle(const char *colName, int n) +{ + DBUG_ENTER("NdbEventOperationImpl::getBlobHandle (colName)"); + + assert(m_mergeEvents); + + if (m_state != EO_CREATED) { + ndbout_c("NdbEventOperationImpl::getBlobHandle may only be called between " + "instantiation and execute()"); + DBUG_RETURN(NULL); + } + + NdbColumnImpl *tAttrInfo = m_eventImpl->m_tableImpl->getColumn(colName); + + if (tAttrInfo == NULL) { + ndbout_c("NdbEventOperationImpl::getBlobHandle attribute %s not found",colName); + DBUG_RETURN(NULL); + } + + NdbBlob* bh = getBlobHandle(tAttrInfo, n); + DBUG_RETURN(bh); +} + +NdbBlob* +NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) +{ + DBUG_ENTER("NdbEventOperationImpl::getBlobHandle"); + DBUG_PRINT("info", ("attr=%s post/pre=%d", tAttrInfo->m_name.c_str(), n)); + + // as in NdbOperation, create only one instance + NdbBlob* tBlob = theBlobList; + NdbBlob* tLastBlob = NULL; + while (tBlob != NULL) { + if (tBlob->theColumn == tAttrInfo && tBlob->theEventBlobVersion == n) + DBUG_RETURN(tBlob); + tLastBlob = tBlob; + tBlob = tBlob->theNext; + } + + // blob event name + char bename[MAX_TAB_NAME_SIZE]; + NdbBlob::getBlobEventName(bename, m_eventImpl, tAttrInfo); + + // find blob event op if any (it serves both post and pre handles) + assert(tAttrInfo->m_blobTable != NULL); + NdbEventOperationImpl* tBlobOp = theBlobOpList; + NdbEventOperationImpl* tLastBlopOp = NULL; + while (tBlobOp != NULL) { + if (strcmp(tBlobOp->m_eventImpl->m_name.c_str(), bename) == 0) { + assert(tBlobOp->m_eventImpl->m_tableImpl == tAttrInfo->m_blobTable); + break; + } + tLastBlopOp = tBlobOp; + tBlobOp = tBlobOp->theNextBlobOp; + } + + DBUG_PRINT("info", ("%s op %s", tBlobOp ? " reuse" : " create", bename)); + + // create blob event op if not found + if (tBlobOp == NULL) { + NdbEventOperation* tmp = m_ndb->createEventOperation(bename); + if (tmp == NULL) + DBUG_RETURN(NULL); + tBlobOp = &tmp->m_impl; + + // pointer to main table op + tBlobOp->theMainOp = this; + tBlobOp->m_mergeEvents = m_mergeEvents; + + // add to list end + if (tLastBlopOp == NULL) + theBlobOpList = tBlobOp; + else + tLastBlopOp->theNextBlobOp = tBlobOp; + tBlobOp->theNextBlobOp = NULL; + } + + tBlob = m_ndb->getNdbBlob(); + if (tBlob == NULL) + DBUG_RETURN(NULL); + + // calls getValue on inline and blob part + if (tBlob->atPrepare(this, tBlobOp, tAttrInfo, n) == -1) { + m_ndb->releaseNdbBlob(tBlob); + DBUG_RETURN(NULL); + } + + // add to list end + if (tLastBlob == NULL) + theBlobList = tBlob; + else + tLastBlob->theNext = tBlob; + tBlob->theNext = NULL; + DBUG_RETURN(tBlob); +} + +int +NdbEventOperationImpl::readBlobParts(char* buf, NdbBlob* blob, + Uint32 part, Uint32 count) +{ + DBUG_ENTER_EVENT("NdbEventOperationImpl::readBlobParts"); + DBUG_PRINT_EVENT("info", ("part=%u count=%u post/pre=%d", + part, count, blob->theEventBlobVersion)); + + NdbEventOperationImpl* blob_op = blob->theBlobEventOp; + + EventBufData* main_data = m_data_item; + DBUG_PRINT_EVENT("info", ("main_data=%p", main_data)); + assert(main_data != NULL); + + // search for blob parts list head + EventBufData* head; + assert(m_data_item != NULL); + head = m_data_item->m_next_blob; + while (head != NULL) + { + if (head->m_event_op == blob_op) + { + DBUG_PRINT_EVENT("info", ("found blob parts head %p", head)); + break; + } + head = head->m_next_blob; + } + + Uint32 nparts = 0; + EventBufData* data = head; + // XXX optimize using part no ordering + while (data != NULL) + { + /* + * Hack part no directly out of buffer since it is not returned + * in pre data (PK buglet). For part data use receive_event(). + * This means extra copy. + */ + blob_op->m_data_item = data; + int r = blob_op->receive_event(); + assert(r > 0); + Uint32 no = data->get_blob_part_no(); + Uint32 sz = blob->thePartSize; + const char* src = blob->theBlobEventDataBuf.data; + + DBUG_PRINT_EVENT("info", ("part_data=%p part no=%u part sz=%u", data, no, sz)); + + if (part <= no && no < part + count) + { + DBUG_PRINT_EVENT("info", ("part within read range")); + memcpy(buf + (no - part) * sz, src, sz); + nparts++; + } + else + { + DBUG_PRINT_EVENT("info", ("part outside read range")); + } + data = data->m_next; + } + assert(nparts == count); + + DBUG_RETURN_EVENT(0); +} + int NdbEventOperationImpl::execute() { DBUG_ENTER("NdbEventOperationImpl::execute"); + m_ndb->theEventBuffer->add_drop_lock(); + int r = execute_nolock(); + m_ndb->theEventBuffer->add_drop_unlock(); + DBUG_RETURN(r); +} + +int +NdbEventOperationImpl::execute_nolock() +{ + DBUG_ENTER("NdbEventOperationImpl::execute_nolock"); + DBUG_PRINT("info", ("this=%p type=%s", this, !theMainOp ? "main" : "blob")); + NdbDictionary::Dictionary *myDict = m_ndb->getDictionary(); if (!myDict) { m_error.code= m_ndb->getNdbError().code; @@ -266,18 +463,26 @@ NdbEventOperationImpl::execute() if (theFirstPkAttrs[0] == NULL && theFirstDataAttrs[0] == NULL) { // defaults to get all - } - m_ndb->theEventBuffer->add_drop_lock(); m_magic_number= NDB_EVENT_OP_MAGIC_NUMBER; m_state= EO_EXECUTING; mi_type= m_eventImpl->mi_type; m_ndb->theEventBuffer->add_op(); int r= NdbDictionaryImpl::getImpl(*myDict).executeSubscribeEvent(*this); if (r == 0) { - m_ndb->theEventBuffer->add_drop_unlock(); - DBUG_RETURN(0); + if (theMainOp == NULL) { + DBUG_PRINT("info", ("execute blob ops")); + NdbEventOperationImpl* blob_op = theBlobOpList; + while (blob_op != NULL) { + r = blob_op->execute_nolock(); + if (r != 0) + break; + blob_op = blob_op->theNextBlobOp; + } + } + if (r == 0) + DBUG_RETURN(0); } //Error m_state= EO_ERROR; @@ -285,7 +490,6 @@ NdbEventOperationImpl::execute() m_magic_number= 0; m_error.code= myDict->getNdbError().code; m_ndb->theEventBuffer->remove_op(); - m_ndb->theEventBuffer->add_drop_unlock(); DBUG_RETURN(r); } @@ -709,21 +913,6 @@ NdbEventBuffer::pollEvents(int aMillisecondNumber, Uint64 *latestGCI) return ret; } -#ifdef VM_TRACE -static void -print_std(const char* tag, const SubTableData * sdata, LinearSectionPtr ptr[3]) -{ - printf("%s\n", tag); - printf("addr=%p gci=%d op=%d\n", (void*)sdata, sdata->gci, sdata->operation); - for (int i = 0; i <= 2; i++) { - printf("sec=%d addr=%p sz=%d\n", i, (void*)ptr[i].p, ptr[i].sz); - for (int j = 0; j < ptr[i].sz; j++) - printf("%08x ", ptr[i].p[j]); - printf("\n"); - } -} -#endif - NdbEventOperation * NdbEventBuffer::nextEvent() { @@ -751,6 +940,7 @@ NdbEventBuffer::nextEvent() while ((data= m_available_data.m_head)) { NdbEventOperationImpl *op= data->m_event_op; + DBUG_PRINT_EVENT("info", ("available data=%p op=%p", data, op)); // set NdbEventOperation data op->m_data_item= data; @@ -767,7 +957,10 @@ NdbEventBuffer::nextEvent() // NUL event is not returned if (data->sdata->operation == NdbDictionary::Event::_TE_NUL) + { + DBUG_PRINT_EVENT("info", ("skip _TE_NUL")); continue; + } int r= op->receive_event(); if (r > 0) @@ -777,6 +970,12 @@ NdbEventBuffer::nextEvent() #ifdef VM_TRACE m_latest_command= m_latest_command_save; #endif + NdbBlob* tBlob = op->theBlobList; + while (tBlob != NULL) + { + (void)tBlob->atNextEvent(); + tBlob = tBlob->theNext; + } DBUG_RETURN_EVENT(op->m_facade); } // the next event belonged to an event op that is no @@ -1161,7 +1360,7 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, DBUG_ENTER_EVENT("NdbEventBuffer::insertDataL"); Uint64 gci= sdata->gci; - if ( likely((Uint32)op->mi_type & 1 << (Uint32)sdata->operation) ) + if ( likely((Uint32)op->mi_type & (1 << (Uint32)sdata->operation)) ) { Gci_container* bucket= find_bucket(&m_active_gci, gci); @@ -1179,9 +1378,9 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, DBUG_RETURN_EVENT(0); } - bool use_hash = - op->m_mergeEvents && + const bool is_data_event = sdata->operation < NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT; + const bool use_hash = op->m_mergeEvents && is_data_event; // find position in bucket hash table EventBufData* data = 0; @@ -1207,10 +1406,38 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, op->m_has_error = 3; DBUG_RETURN_EVENT(-1); } - // add it to list and hash table - bucket->m_data.append(data); + data->m_event_op = op; + if (op->theMainOp == NULL || ! is_data_event) + { + bucket->m_data.append(data); + } + else + { + // find or create main event for this blob event + EventBufData_hash::Pos main_hpos; + int ret = get_main_data(bucket, main_hpos, data); + if (ret == -1) + { + op->m_has_error = 4; + DBUG_RETURN_EVENT(-1); + } + EventBufData* main_data = main_hpos.data; + if (ret != 0) // main event was created + { + main_data->m_event_op = op->theMainOp; + bucket->m_data.append(main_data); + if (use_hash) + { + main_data->m_pkhash = main_hpos.pkhash; + bucket->m_data_hash.append(main_hpos, main_data); + } + } + // link blob event under main event + add_blob_data(main_data, data); + } if (use_hash) { + data->m_pkhash = hpos.pkhash; bucket->m_data_hash.append(hpos, data); } #ifdef VM_TRACE @@ -1226,18 +1453,12 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, DBUG_RETURN_EVENT(-1); } } - data->m_event_op = op; - if (use_hash) - { - data->m_pkhash = hpos.pkhash; - } DBUG_RETURN_EVENT(0); } #ifdef VM_TRACE - if ((Uint32)op->m_eventImpl->mi_type & 1 << (Uint32)sdata->operation) + if ((Uint32)op->m_eventImpl->mi_type & (1 << (Uint32)sdata->operation)) { - // XXX never reached DBUG_PRINT_EVENT("info",("Data arrived before ready eventId", op->m_eventId)); DBUG_RETURN_EVENT(0); } @@ -1300,6 +1521,8 @@ NdbEventBuffer::alloc_data() int NdbEventBuffer::alloc_mem(EventBufData* data, LinearSectionPtr ptr[3]) { + DBUG_ENTER("NdbEventBuffer::alloc_mem"); + DBUG_PRINT("info", ("ptr sz %u + %u + %u", ptr[0].sz, ptr[1].sz, ptr[2].sz)); const Uint32 min_alloc_size = 128; Uint32 sz4 = (sizeof(SubTableData) + 3) >> 2; @@ -1317,7 +1540,7 @@ NdbEventBuffer::alloc_mem(EventBufData* data, LinearSectionPtr ptr[3]) data->memory = (Uint32*)NdbMem_Allocate(alloc_size); if (data->memory == 0) - return -1; + DBUG_RETURN(-1); data->sz = alloc_size; m_total_alloc += data->sz; } @@ -1332,7 +1555,7 @@ NdbEventBuffer::alloc_mem(EventBufData* data, LinearSectionPtr ptr[3]) memptr += ptr[i].sz; } - return 0; + DBUG_RETURN(0); } int @@ -1404,13 +1627,10 @@ copy_attr(AttributeHeader ah, { Uint32 k; for (k = 0; k < n; k++) - p1[j1++] = p2[j2++]; - } - else - { - j1 += n; - j2 += n; + p1[j1 + k] = p2[j2 + k]; } + j1 += n; + j2 += n; } int @@ -1443,8 +1663,8 @@ NdbEventBuffer::merge_data(const SubTableData * const sdata, data->sz = 0; // compose ptr1 o ptr2 = ptr - LinearSectionPtr (&ptr1) [3] = olddata.ptr; - LinearSectionPtr (&ptr) [3] = data->ptr; + LinearSectionPtr (&ptr1)[3] = olddata.ptr; + LinearSectionPtr (&ptr)[3] = data->ptr; // loop twice where first loop only sets sizes int loop; @@ -1458,7 +1678,7 @@ NdbEventBuffer::merge_data(const SubTableData * const sdata, data->sdata->operation = tp->t3; } - ptr[0].sz = ptr[1].sz = ptr[3].sz = 0; + ptr[0].sz = ptr[1].sz = ptr[2].sz = 0; // copy pk from new version { @@ -1572,6 +1792,113 @@ NdbEventBuffer::merge_data(const SubTableData * const sdata, DBUG_RETURN_EVENT(0); } + +/* + * Given blob part event, find main table event on inline part. It + * should exist (force in TUP) but may arrive later. If so, create + * NUL event on main table. The real event replaces it later. + */ + +// write attribute headers for concatened PK +static void +split_concatenated_pk(const NdbTableImpl* t, Uint32* ah_buffer, + const Uint32* pk_buffer, Uint32 pk_sz) +{ + Uint32 sz = 0; // words parsed so far + Uint32 n; // pk attr count + Uint32 i; + for (i = n = 0; i < t->m_columns.size() && n < t->m_noOfKeys; i++) + { + const NdbColumnImpl* c = t->getColumn(i); + assert(c != NULL); + if (! c->m_pk) + continue; + + assert(sz < pk_sz); + Uint32 bytesize = c->m_attrSize * c->m_arraySize; + Uint32 lb, len; + bool ok = NdbSqlUtil::get_var_length(c->m_type, &pk_buffer[sz], bytesize, + lb, len); + assert(ok); + + AttributeHeader ah(i, lb + len); + ah_buffer[n++] = ah.m_value; + sz += ah.getDataSize(); + } + assert(n == t->m_noOfKeys && sz == pk_sz); +} + +int +NdbEventBuffer::get_main_data(Gci_container* bucket, + EventBufData_hash::Pos& hpos, + EventBufData* blob_data) +{ + DBUG_ENTER_EVENT("NdbEventBuffer::get_main_data"); + + NdbEventOperationImpl* main_op = blob_data->m_event_op->theMainOp; + assert(main_op != NULL); + const NdbTableImpl* mainTable = main_op->m_eventImpl->m_tableImpl; + + // create LinearSectionPtr for main table key + LinearSectionPtr ptr[3]; + Uint32 ah_buffer[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY]; + ptr[0].sz = mainTable->m_noOfKeys; + ptr[0].p = ah_buffer; + ptr[1].sz = AttributeHeader(blob_data->ptr[0].p[0]).getDataSize(); + ptr[1].p = blob_data->ptr[1].p; + ptr[2].sz = 0; + ptr[2].p = 0; + split_concatenated_pk(mainTable, ptr[0].p, ptr[1].p, ptr[1].sz); + + DBUG_DUMP_EVENT("ah", (char*)ptr[0].p, ptr[0].sz << 2); + DBUG_DUMP_EVENT("pk", (char*)ptr[1].p, ptr[1].sz << 2); + + // search for main event buffer + bucket->m_data_hash.search(hpos, main_op, ptr); + if (hpos.data != NULL) + DBUG_RETURN_EVENT(0); + + // not found, create a place-holder + EventBufData* main_data = alloc_data(); + if (main_data == NULL) + DBUG_RETURN_EVENT(-1); + SubTableData sdata = *blob_data->sdata; + sdata.tableId = main_op->m_eventImpl->m_tableImpl->m_id; + sdata.operation = NdbDictionary::Event::_TE_NUL; + if (copy_data(&sdata, ptr, main_data) != 0) + DBUG_RETURN_EVENT(-1); + hpos.data = main_data; + + DBUG_RETURN_EVENT(1); +} + +void +NdbEventBuffer::add_blob_data(EventBufData* main_data, + EventBufData* blob_data) +{ + DBUG_ENTER_EVENT("NdbEventBuffer::add_blob_data"); + DBUG_PRINT_EVENT("info", ("main_data=%p blob_data=%p", main_data, blob_data)); + EventBufData* head; + head = main_data->m_next_blob; + while (head != NULL) + { + if (head->m_event_op == blob_data->m_event_op) + break; + head = head->m_next_blob; + } + if (head == NULL) + { + head = blob_data; + head->m_next_blob = main_data->m_next_blob; + main_data->m_next_blob = head; + } + else + { + blob_data->m_next = head->m_next; + head->m_next = blob_data; + } + DBUG_VOID_RETURN_EVENT; +} NdbEventOperationImpl * NdbEventBuffer::move_data() @@ -1613,6 +1940,31 @@ NdbEventBuffer::free_list(EventBufData_list &list) #endif m_free_data_sz+= list.m_sz; + // free blobs XXX unacceptable performance, fix later + { + EventBufData* data = list.m_head; + while (1) { + while (data->m_next_blob != NULL) { + EventBufData* blob_head = data->m_next_blob; + data->m_next_blob = blob_head->m_next_blob; + blob_head->m_next_blob = NULL; + while (blob_head != NULL) { + EventBufData* blob_part = blob_head; + blob_head = blob_head->m_next; + blob_part->m_next = m_free_data; + m_free_data = blob_part; +#ifdef VM_TRACE + m_free_data_count++; +#endif + m_free_data_sz += blob_part->sz; + } + } + if (data == list.m_tail) + break; + data = data->m_next; + } + } + // list returned to m_free_data new (&list) EventBufData_list; } @@ -1648,6 +2000,14 @@ NdbEventBuffer::dropEventOperation(NdbEventOperation* tOp) if (m_dropped_ev_op) m_dropped_ev_op->m_prev= op; m_dropped_ev_op= op; + + // drop blob ops + while (op->theBlobOpList != NULL) + { + NdbEventOperationImpl* tBlobOp = op->theBlobOpList; + op->theBlobOpList = op->theBlobOpList->theNextBlobOp; + (void)m_ndb->dropEventOperation(tBlobOp); + } // ToDo, take care of these to be deleted at the // appropriate time, after we are sure that there @@ -1717,6 +2077,10 @@ send_report: Uint32 EventBufData_hash::getpkhash(NdbEventOperationImpl* op, LinearSectionPtr ptr[3]) { + DBUG_ENTER_EVENT("EventBufData_hash::getpkhash"); + DBUG_DUMP_EVENT("ah", (char*)ptr[0].p, ptr[0].sz << 2); + DBUG_DUMP_EVENT("pk", (char*)ptr[1].p, ptr[1].sz << 2); + const NdbTableImpl* tab = op->m_eventImpl->m_tableImpl; // in all cases ptr[0] = pk ah.. ptr[1] = pk ad.. @@ -1747,13 +2111,19 @@ EventBufData_hash::getpkhash(NdbEventOperationImpl* op, LinearSectionPtr ptr[3]) (*cs->coll->hash_sort)(cs, dptr + lb, len, &nr1, &nr2); dptr += ((bytesize + 3) / 4) * 4; } - return nr1; + DBUG_PRINT_EVENT("info", ("hash result=%08x", nr1)); + DBUG_RETURN_EVENT(nr1); } -// this is seldom invoked bool EventBufData_hash::getpkequal(NdbEventOperationImpl* op, LinearSectionPtr ptr1[3], LinearSectionPtr ptr2[3]) { + DBUG_ENTER_EVENT("EventBufData_hash::getpkequal"); + DBUG_DUMP_EVENT("ah1", (char*)ptr1[0].p, ptr1[0].sz << 2); + DBUG_DUMP_EVENT("pk1", (char*)ptr1[1].p, ptr1[1].sz << 2); + DBUG_DUMP_EVENT("ah2", (char*)ptr2[0].p, ptr2[0].sz << 2); + DBUG_DUMP_EVENT("pk2", (char*)ptr2[1].p, ptr2[1].sz << 2); + const NdbTableImpl* tab = op->m_eventImpl->m_tableImpl; Uint32 nkey = tab->m_noOfKeys; @@ -1763,6 +2133,8 @@ EventBufData_hash::getpkequal(NdbEventOperationImpl* op, LinearSectionPtr ptr1[3 const uchar* dptr1 = (uchar*)ptr1[1].p; const uchar* dptr2 = (uchar*)ptr2[1].p; + bool equal = true; + while (nkey-- != 0) { AttributeHeader ah1(*hptr1++); @@ -1787,16 +2159,22 @@ EventBufData_hash::getpkequal(NdbEventOperationImpl* op, LinearSectionPtr ptr1[3 CHARSET_INFO* cs = col->m_cs ? col->m_cs : &my_charset_bin; int res = (cs->coll->strnncollsp)(cs, dptr1 + lb1, len1, dptr2 + lb2, len2, false); if (res != 0) - return false; + { + equal = false; + break; + } dptr1 += ((bytesize1 + 3) / 4) * 4; dptr2 += ((bytesize2 + 3) / 4) * 4; } - return true; + + DBUG_PRINT_EVENT("info", ("equal=%s", equal ? "true" : "false")); + DBUG_RETURN_EVENT(equal); } void EventBufData_hash::search(Pos& hpos, NdbEventOperationImpl* op, LinearSectionPtr ptr[3]) { + DBUG_ENTER_EVENT("EventBufData_hash::search"); Uint32 pkhash = getpkhash(op, ptr); Uint32 index = (op->m_oid ^ pkhash) % GCI_EVENT_HASH_SIZE; EventBufData* data = m_hash[index]; @@ -1811,6 +2189,8 @@ EventBufData_hash::search(Pos& hpos, NdbEventOperationImpl* op, LinearSectionPtr hpos.index = index; hpos.data = data; hpos.pkhash = pkhash; + DBUG_PRINT_EVENT("info", ("search result=%p", data)); + DBUG_VOID_RETURN_EVENT; } template class Vector; diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp index 2a1d1643a12..c91fd966b18 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #define NDB_EVENT_OP_MAGIC_NUMBER 0xA9F301B4 @@ -35,9 +36,28 @@ struct EventBufData LinearSectionPtr ptr[3]; unsigned sz; NdbEventOperationImpl *m_event_op; - EventBufData *m_next; // Next wrt to global order + + /* + * Blobs are stored in blob list (m_next_blob) where each entry + * is list of parts (m_next) in part number order. + * + * TODO order by part no and link for fast read and free_list + */ + + EventBufData *m_next; // Next wrt to global order or Next blob part + EventBufData *m_next_blob; // First part in next blob + EventBufData *m_next_hash; // Next in per-GCI hash Uint32 m_pkhash; // PK hash (without op) for fast compare + + // Get blob part number from blob data + Uint32 get_blob_part_no() { + assert(ptr[0].sz > 2); + Uint32 pos = AttributeHeader(ptr[0].p[0]).getDataSize() + + AttributeHeader(ptr[0].p[1]).getDataSize(); + Uint32 no = ptr[1].p[pos]; + return no; + } }; class EventBufData_list @@ -70,7 +90,6 @@ EventBufData_list::~EventBufData_list() { } - inline int EventBufData_list::is_empty() { @@ -173,9 +192,13 @@ public: NdbEventOperation::State getState(); int execute(); + int execute_nolock(); int stop(); NdbRecAttr *getValue(const char *colName, char *aValue, int n); NdbRecAttr *getValue(const NdbColumnImpl *, char *aValue, int n); + NdbBlob *getBlobHandle(const char *colName, int n); + NdbBlob *getBlobHandle(const NdbColumnImpl *, int n); + int readBlobParts(char* buf, NdbBlob* blob, Uint32 part, Uint32 count); int receive_event(); Uint64 getGCI(); Uint64 getLatestGCI(); @@ -199,6 +222,13 @@ public: NdbRecAttr *theFirstDataAttrs[2]; NdbRecAttr *theCurrentDataAttrs[2]; + NdbBlob* theBlobList; + union { + NdbEventOperationImpl* theBlobOpList; + NdbEventOperationImpl* theNextBlobOp; + }; + NdbEventOperationImpl* theMainOp; // blob op pointer to main op + NdbEventOperation::State m_state; /* note connection to mi_type */ Uint32 mi_type; /* should be == 0 if m_state != EO_EXECUTING * else same as in EventImpl @@ -275,6 +305,11 @@ public: int merge_data(const SubTableData * const sdata, LinearSectionPtr ptr[3], EventBufData* data); + int get_main_data(Gci_container* bucket, + EventBufData_hash::Pos& hpos, + EventBufData* blob_data); + void add_blob_data(EventBufData* main_data, + EventBufData* blob_data); void free_list(EventBufData_list &list); diff --git a/storage/ndb/test/ndbapi/test_event_merge.cpp b/storage/ndb/test/ndbapi/test_event_merge.cpp index 882679ffcb7..554d168b73c 100644 --- a/storage/ndb/test/ndbapi/test_event_merge.cpp +++ b/storage/ndb/test/ndbapi/test_event_merge.cpp @@ -21,14 +21,7 @@ #include #include -#if NDB_VERSION_D < MAKE_VERSION(5, 1, 0) -#define version50 -#else -#undef version50 -#endif - -// until rbr in 5.1 -#undef version51rbr +// version >= 5.1 required #if !defined(min) || !defined(max) #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -57,11 +50,11 @@ * There are other -no-* options, each added to isolate a specific bug. * * There are 5 ways (ignoring NUL operand) to compose 2 ops: - * 5.0 bugs 5.1 bugs + * * INS o DEL = NUL - * INS o UPD = INS type=INS - * DEL o INS = UPD type=INS type=INS - * UPD o DEL = DEL no event + * INS o UPD = INS + * DEL o INS = UPD + * UPD o DEL = DEL * UPD o UPD = UPD */ @@ -73,17 +66,19 @@ struct Opts { uint maxpk; my_bool no_blobs; my_bool no_implicit_nulls; + my_bool no_missing_update; my_bool no_multiops; my_bool no_nulls; my_bool one_blob; const char* opstring; uint seed; my_bool separate_events; + uint tweak; // whatever's useful my_bool use_table; }; static Opts g_opts; -static const uint g_maxpk = 100; +static const uint g_maxpk = 1000; static const uint g_maxopstringpart = 100; static const char* g_opstringpart[g_maxopstringpart]; static uint g_opstringparts = 0; @@ -712,6 +707,20 @@ checkop(const Op* op, Uint32& pk1) if (! c.nullable) { chkrc(ind0 <= 0 && ind1 <= 0); } + if (c.isblob()) { + // blob values must be from allowed chars + int j; + for (j = 0; j < 2; j++) { + const Data& d = op->data[j]; + if (d.ind[i] == 0) { + const Data::Txt& t = *d.ptr[i].txt; + int k; + for (k = 0; k < t.len; k++) { + chkrc(strchr(g_charval, t.val[k]) != 0); + } + } + } + } } return 0; } @@ -849,9 +858,8 @@ createevent() const Col& c = g_col[i]; evt.addEventColumn(c.name); } -#ifdef version51rbr + evt.setReport(NdbDictionary::Event::ER_UPDATED); evt.mergeEvents(! g_opts.separate_events); -#endif if (g_dic->getEvent(evt.getName()) != 0) chkdb(g_dic->dropEvent(evt.getName()) == 0); chkdb(g_dic->createEvent(evt) == 0); @@ -875,14 +883,8 @@ static int createeventop() { ll1("createeventop"); -#ifdef version50 - uint bsz = 10 * g_opts.maxops; - chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName(), bsz)) != 0); -#else chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName())) != 0); - // available in gci merge changeset g_evt_op->mergeEvents(! g_opts.separate_events); // not yet inherited -#endif uint i; for (i = 0; i < ncol(); i++) { const Col& c = g_col[i]; @@ -891,10 +893,8 @@ createeventop() chkdb((g_ev_ra[0][i] = g_evt_op->getValue(c.name, (char*)d[0].ptr[i].v)) != 0); chkdb((g_ev_ra[1][i] = g_evt_op->getPreValue(c.name, (char*)d[1].ptr[i].v)) != 0); } else { -#ifdef version51rbr chkdb((g_ev_bh[0][i] = g_evt_op->getBlobHandle(c.name)) != 0); chkdb((g_ev_bh[1][i] = g_evt_op->getPreBlobHandle(c.name)) != 0); -#endif } } return 0; @@ -909,10 +909,10 @@ dropeventop() return 0; } +// wait for event to be installed and for GCIs to pass static int -waitgci() // wait for event to be installed and for at least 1 GCI to pass +waitgci(uint ngci) { - const uint ngci = 3; ll1("waitgci " << ngci); Uint32 gci[2]; uint i = 0; @@ -976,7 +976,6 @@ scantab() if (! c.isblob()) { ind = ra[i]->isNULL(); } else { -#ifdef version51rbr int ret; ret = bh[i]->getDefined(ind); assert(ret == 0); @@ -992,8 +991,10 @@ scantab() Uint32 len = t.len; ret = bh[i]->readData(t.val, len); assert(ret == 0 && len == t.len); + // to see the data, have to execute... + chkdb(g_con->execute(NoCommit) == 0); + assert(memchr(t.val, 'X', t.len) == 0); } -#endif } assert(ind >= 0); d0.ind[i] = ind; @@ -1042,7 +1043,7 @@ makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t) } else if (t == Op::INS && ! g_opts.no_implicit_nulls && c.nullable && urandom(10, 100)) { d.noop |= (1 << i); d.ind[i] = 1; // implicit NULL value is known - } else if (t == Op::UPD && urandom(10, 100)) { + } else if (t == Op::UPD && ! g_opts.no_missing_update && urandom(10, 100)) { d.noop |= (1 << i); d.ind[i] = -1; // fixed up in caller } else if (! g_opts.no_nulls && c.nullable && urandom(10, 100)) { @@ -1060,6 +1061,8 @@ makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t) { char* p = d.ptr[i].ch; uint u = urandom(g_charlen); + if (u == 0) + u = urandom(g_charlen); // 2x bias for non-empty uint j; for (j = 0; j < g_charlen; j++) { uint v = urandom(strlen(g_charval)); @@ -1070,10 +1073,19 @@ makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t) case NdbDictionary::Column::Text: { Data::Txt& t = *d.ptr[i].txt; + delete [] t.val; + t.val = 0; + if (g_opts.tweak & 1) { + uint u = 256 + 2000; + uint v = (g_opts.tweak & 2) ? 0 : urandom(strlen(g_charval)); + t.val = new char [u]; + t.len = u; + memset(t.val, g_charval[v], u); + break; + } uint u = urandom(g_maxblobsize); u = urandom(u); // 4x bias for smaller blobs u = urandom(u); - delete [] t.val; t.val = new char [u]; t.len = u; uint j = 0; @@ -1134,9 +1146,15 @@ makeops() { ll1("makeops"); Uint32 pk1 = 0; - while (g_usedops < g_opts.maxops && pk1 < g_opts.maxpk) { - if (g_opts.opstring == 0) + while (1) { + if (g_opts.opstring == 0) { + if (g_usedops >= g_opts.maxops) // use up ops + break; pk1 = urandom(g_opts.maxpk); + } else { + if (pk1 >= g_opts.maxpk) // use up pks + break; + } ll2("makeops: pk1=" << pk1); // total op on the pk so far // optype either NUL=initial/deleted or INS=created @@ -1465,7 +1483,7 @@ matchevent(Op* ev) } if (tmpok) { ok = gci_op->match = true; - ll2("===: match"); + ll2("match"); } } pos++; @@ -1555,7 +1573,6 @@ geteventdata() NdbRecAttr* ra = g_ev_ra[j][i]; ind = ra->isNULL(); } else { -#ifdef version51rbr NdbBlob* bh = g_ev_bh[j][i]; ret = bh->getDefined(ind); assert(ret == 0); @@ -1572,7 +1589,6 @@ geteventdata() ret = bh->readData(t.val, len); assert(ret == 0 && len == t.len); } -#endif } d[j].ind[i] = ind; } @@ -1585,38 +1601,22 @@ runevents() ll1("runevents"); uint mspoll = 1000; uint npoll = 6; // strangely long delay + ll1("poll " << npoll); while (npoll != 0) { npoll--; int ret; - ll1("poll"); ret = g_ndb->pollEvents(mspoll); if (ret <= 0) continue; while (1) { g_rec_ev->init(Op::EV); -#ifdef version50 - int overrun = g_opts.maxops; - chkdb((ret = g_evt_op->next(&overrun)) >= 0); - chkrc(overrun == 0); - if (ret == 0) - break; -#else NdbEventOperation* tmp_op = g_ndb->nextEvent(); if (tmp_op == 0) break; reqrc(g_evt_op == tmp_op); -#endif chkrc(seteventtype(g_rec_ev, g_evt_op->getEventType()) == 0); geteventdata(); g_rec_ev->gci = g_evt_op->getGCI(); -#ifdef version50 - // fix to match 5.1 - if (g_rec_ev->type == Op::UPD) { - Uint32 pk1 = g_rec_ev->data[0].pk1; - makedata(getcol("pk1"), g_rec_ev->data[1], pk1, Op::UPD); - makedata(getcol("pk2"), g_rec_ev->data[1], pk1, Op::UPD); - } -#endif // get indicators and blob value ll2("runevents: EVT: " << *g_rec_ev); // check basic sanity @@ -1667,7 +1667,7 @@ runtest() chkrc(createtable() == 0); chkrc(createevent() == 0); for (g_loop = 0; g_opts.loop == 0 || g_loop < g_opts.loop; g_loop++) { - ll0("loop " << g_loop); + ll0("=== loop " << g_loop << " ==="); setseed(g_loop); resetmem(); chkrc(scantab() == 0); // alternative: save tot_op for loop > 0 @@ -1675,7 +1675,7 @@ runtest() g_rec_ev = getop(Op::EV); chkrc(createeventop() == 0); chkdb(g_evt_op->execute() == 0); - chkrc(waitgci() == 0); + chkrc(waitgci(3) == 0); chkrc(runops() == 0); if (! g_opts.separate_events) chkrc(mergeops() == 0); @@ -1685,6 +1685,8 @@ runtest() chkrc(matchevents() == 0); chkrc(matchops() == 0); chkrc(dropeventop() == 0); + // time erases everything.. + chkrc(waitgci(1) == 0); } chkrc(dropevent() == 0); chkrc(droptable() == 0); @@ -1703,41 +1705,48 @@ my_long_options[] = { "loglevel", 1002, "Logging level in this program (default 0)", (gptr*)&g_opts.loglevel, (gptr*)&g_opts.loglevel, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "loop", 1003, "Number of test loops (default 2, 0=forever)", + { "loop", 1003, "Number of test loops (default 3, 0=forever)", (gptr*)&g_opts.loop, (gptr*)&g_opts.loop, 0, - GET_INT, REQUIRED_ARG, 2, 0, 0, 0, 0, 0 }, + GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0 }, { "maxops", 1004, "Approx number of PK operations (default 1000)", (gptr*)&g_opts.maxops, (gptr*)&g_opts.maxops, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 }, { "maxpk", 1005, "Number of different PK values (default 10)", (gptr*)&g_opts.maxpk, (gptr*)&g_opts.maxpk, 0, - GET_UINT, REQUIRED_ARG, 10, 1, g_maxpk, 0, 0, 0 }, + GET_UINT, REQUIRED_ARG, 10, 0, 0, 0, 0, 0 }, { "no-blobs", 1006, "Omit blob attributes (5.0: true)", (gptr*)&g_opts.no_blobs, (gptr*)&g_opts.no_blobs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "no-implicit-nulls", 1007, "Insert must include NULL values explicitly", + { "no-implicit-nulls", 1007, "Insert must include all attrs" + " i.e. no implicit NULLs", (gptr*)&g_opts.no_implicit_nulls, (gptr*)&g_opts.no_implicit_nulls, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "no-multiops", 1008, "Allow only 1 operation per commit", + { "no-missing-update", 1008, "Update must include all non-PK attrs", + (gptr*)&g_opts.no_missing_update, (gptr*)&g_opts.no_missing_update, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "no-multiops", 1009, "Allow only 1 operation per commit", (gptr*)&g_opts.no_multiops, (gptr*)&g_opts.no_multiops, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "no-nulls", 1009, "Create no NULL values", + { "no-nulls", 1010, "Create no NULL values", (gptr*)&g_opts.no_nulls, (gptr*)&g_opts.no_nulls, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "one-blob", 1010, "Only one blob attribute (defautt 2)", + { "one-blob", 1011, "Only one blob attribute (default 2)", (gptr*)&g_opts.one_blob, (gptr*)&g_opts.one_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "opstring", 1011, "Operations to run e.g. idiucdc (c is commit) or" + { "opstring", 1012, "Operations to run e.g. idiucdc (c is commit) or" " iuuc:uudc (the : separates loops)", (gptr*)&g_opts.opstring, (gptr*)&g_opts.opstring, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "seed", 1012, "Random seed (0=loop number, default -1=random)", + { "seed", 1013, "Random seed (0=loop number, default -1=random)", (gptr*)&g_opts.seed, (gptr*)&g_opts.seed, 0, GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 }, - { "separate-events", 1013, "Do not combine events per GCI (5.0: true)", + { "separate-events", 1014, "Do not combine events per GCI (5.0: true)", (gptr*)&g_opts.separate_events, (gptr*)&g_opts.separate_events, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "use-table", 1014, "Use existing table 'tem1'", + { "tweak", 1015, "Whatever the source says", + (gptr*)&g_opts.tweak, (gptr*)&g_opts.tweak, 0, + GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "use-table", 1016, "Use existing table 'tem1'", (gptr*)&g_opts.use_table, (gptr*)&g_opts.use_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, @@ -1754,9 +1763,10 @@ usage() static int checkopts() { -#ifdef version50 - g_opts.separate_events = true; -#endif + if (g_opts.maxpk > g_maxpk) { + ll0("setting maxpk to " << g_maxpk); + g_opts.maxpk = g_maxpk; + } if (g_opts.separate_events) { g_opts.no_blobs = true; } From 30877fc5989594c00d4bb765992651c0410b7015 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 22 Jan 2006 10:37:57 +0100 Subject: [PATCH 02/15] ndb - wl#2972 injector saw blob table drop event => crash storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: catch non-data events on blob part tables --- storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index cf630c57cfe..adf2a198b30 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -942,6 +942,9 @@ NdbEventBuffer::nextEvent() NdbEventOperationImpl *op= data->m_event_op; DBUG_PRINT_EVENT("info", ("available data=%p op=%p", data, op)); + // blob table ops must not be seen at this level + assert(op->theMainOp == NULL); + // set NdbEventOperation data op->m_data_item= data; @@ -1378,10 +1381,18 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, DBUG_RETURN_EVENT(0); } + const bool is_blob_event = (op->theMainOp != NULL); const bool is_data_event = sdata->operation < NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT; const bool use_hash = op->m_mergeEvents && is_data_event; + if (! is_data_event && is_blob_event) + { + // currently subscribed to but not used + DBUG_PRINT_EVENT("info", ("ignore non-data event on blob table")); + DBUG_RETURN_EVENT(0); + } + // find position in bucket hash table EventBufData* data = 0; EventBufData_hash::Pos hpos; @@ -1400,14 +1411,13 @@ NdbEventBuffer::insertDataL(NdbEventOperationImpl *op, op->m_has_error = 2; DBUG_RETURN_EVENT(-1); } - if (unlikely(copy_data(sdata, ptr, data))) { op->m_has_error = 3; DBUG_RETURN_EVENT(-1); } data->m_event_op = op; - if (op->theMainOp == NULL || ! is_data_event) + if (! is_blob_event || ! is_data_event) { bucket->m_data.append(data); } From 567a31e33fa2171f361e0084a92cd4fe1cd7b6de Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 22 Jan 2006 13:28:43 +0100 Subject: [PATCH 03/15] ndb - wl#2972 fix tinyblob storage/ndb/src/ndbapi/NdbBlob.cpp: tinyblob of course has no blob table and no blob op storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: tinyblob of course has no blob table and no blob op storage/ndb/test/ndbapi/test_event_merge.cpp: tinyblob of course has no blob table and no blob op --- storage/ndb/src/ndbapi/NdbBlob.cpp | 32 +++++---- .../ndb/src/ndbapi/NdbEventOperationImpl.cpp | 66 ++++++++++--------- storage/ndb/test/ndbapi/test_event_merge.cpp | 32 ++++++--- 3 files changed, 78 insertions(+), 52 deletions(-) diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 375d64c2eab..17ca87371f4 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -1269,6 +1269,8 @@ NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, // prepare blob column and table if (prepareColumn() == -1) DBUG_RETURN(-1); + // tinyblob sanity + assert((theBlobEventOp == NULL) == (theBlobTable == NULL)); // extra buffers theBlobEventDataBuf.alloc(thePartSize); // prepare receive of head+inline @@ -1278,20 +1280,22 @@ NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, DBUG_RETURN(-1); } // prepare receive of blob part - if ((theBlobEventPkRecAttr = - theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0), - theKeyBuf.data, version)) == NULL || - (theBlobEventDistRecAttr = - theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1), - (char*)0, version)) == NULL || - (theBlobEventPartRecAttr = - theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)2), - (char*)&thePartNumber, version)) == NULL || - (theBlobEventDataRecAttr = - theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)3), - theBlobEventDataBuf.data, version)) == NULL) { - setErrorCode(theBlobEventOp); - DBUG_RETURN(-1); + if (theBlobEventOp != NULL) { + if ((theBlobEventPkRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0), + theKeyBuf.data, version)) == NULL || + (theBlobEventDistRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1), + (char*)0, version)) == NULL || + (theBlobEventPartRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)2), + (char*)&thePartNumber, version)) == NULL || + (theBlobEventDataRecAttr = + theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)3), + theBlobEventDataBuf.data, version)) == NULL) { + setErrorCode(theBlobEventOp); + DBUG_RETURN(-1); + } } setState(Prepared); DBUG_RETURN(0); diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index adf2a198b30..c195da16480 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -318,42 +318,48 @@ NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) tBlob = tBlob->theNext; } - // blob event name - char bename[MAX_TAB_NAME_SIZE]; - NdbBlob::getBlobEventName(bename, m_eventImpl, tAttrInfo); + NdbEventOperationImpl* tBlobOp = NULL; - // find blob event op if any (it serves both post and pre handles) - assert(tAttrInfo->m_blobTable != NULL); - NdbEventOperationImpl* tBlobOp = theBlobOpList; - NdbEventOperationImpl* tLastBlopOp = NULL; - while (tBlobOp != NULL) { - if (strcmp(tBlobOp->m_eventImpl->m_name.c_str(), bename) == 0) { - assert(tBlobOp->m_eventImpl->m_tableImpl == tAttrInfo->m_blobTable); - break; + const bool is_tinyblob = (tAttrInfo->getPartSize() == 0); + assert(is_tinyblob == (tAttrInfo->m_blobTable == NULL)); + + if (! is_tinyblob) { + // blob event name + char bename[MAX_TAB_NAME_SIZE]; + NdbBlob::getBlobEventName(bename, m_eventImpl, tAttrInfo); + + // find blob event op if any (it serves both post and pre handles) + tBlobOp = theBlobOpList; + NdbEventOperationImpl* tLastBlopOp = NULL; + while (tBlobOp != NULL) { + if (strcmp(tBlobOp->m_eventImpl->m_name.c_str(), bename) == 0) { + assert(tBlobOp->m_eventImpl->m_tableImpl == tAttrInfo->m_blobTable); + break; + } + tLastBlopOp = tBlobOp; + tBlobOp = tBlobOp->theNextBlobOp; } - tLastBlopOp = tBlobOp; - tBlobOp = tBlobOp->theNextBlobOp; - } - DBUG_PRINT("info", ("%s op %s", tBlobOp ? " reuse" : " create", bename)); + DBUG_PRINT("info", ("%s op %s", tBlobOp ? " reuse" : " create", bename)); - // create blob event op if not found - if (tBlobOp == NULL) { - NdbEventOperation* tmp = m_ndb->createEventOperation(bename); - if (tmp == NULL) - DBUG_RETURN(NULL); - tBlobOp = &tmp->m_impl; + // create blob event op if not found + if (tBlobOp == NULL) { + NdbEventOperation* tmp = m_ndb->createEventOperation(bename); + if (tmp == NULL) + DBUG_RETURN(NULL); + tBlobOp = &tmp->m_impl; - // pointer to main table op - tBlobOp->theMainOp = this; - tBlobOp->m_mergeEvents = m_mergeEvents; + // pointer to main table op + tBlobOp->theMainOp = this; + tBlobOp->m_mergeEvents = m_mergeEvents; - // add to list end - if (tLastBlopOp == NULL) - theBlobOpList = tBlobOp; - else - tLastBlopOp->theNextBlobOp = tBlobOp; - tBlobOp->theNextBlobOp = NULL; + // add to list end + if (tLastBlopOp == NULL) + theBlobOpList = tBlobOp; + else + tLastBlopOp->theNextBlobOp = tBlobOp; + tBlobOp->theNextBlobOp = NULL; + } } tBlob = m_ndb->getNdbBlob(); diff --git a/storage/ndb/test/ndbapi/test_event_merge.cpp b/storage/ndb/test/ndbapi/test_event_merge.cpp index 554d168b73c..d3c1ee70ce7 100644 --- a/storage/ndb/test/ndbapi/test_event_merge.cpp +++ b/storage/ndb/test/ndbapi/test_event_merge.cpp @@ -203,7 +203,9 @@ struct Col { uint length; uint size; bool isblob() const { - return type == NdbDictionary::Column::Text; + return + type == NdbDictionary::Column::Text || + type == NdbDictionary::Column::Blob; } }; @@ -213,19 +215,21 @@ static Col g_col[] = { { 2, "seq", NdbDictionary::Column::Unsigned, false, false, 1, 4 }, { 3, "cc1", NdbDictionary::Column::Char, false, true, g_charlen, g_charlen }, { 4, "tx1", NdbDictionary::Column::Text, false, true, 0, 0 }, - { 5, "tx2", NdbDictionary::Column::Text, false, true, 0, 0 } + { 5, "tx2", NdbDictionary::Column::Text, false, true, 0, 0 }, + { 6, "bl1", NdbDictionary::Column::Blob, false, true, 0, 0 } // tinyblob }; static const uint g_maxcol = sizeof(g_col)/sizeof(g_col[0]); +static const uint g_blobcols = 3; static uint ncol() { uint n = g_maxcol; if (g_opts.no_blobs) - n -= 2; + n -= g_blobcols; else if (g_opts.one_blob) - n -= 1; + n -= (g_blobcols - 1); return n; } @@ -278,6 +282,11 @@ createtable() col.setStripeSize(g_blobstripesize); col.setCharset(cs); break; + case NdbDictionary::Column::Blob: + col.setInlineSize(g_blobinlinesize); + col.setPartSize(0); + col.setStripeSize(0); + break; default: assert(false); break; @@ -332,6 +341,7 @@ struct Data { char cc1[g_charlen + 1]; Txt tx1; Txt tx2; + Txt bl1; Ptr ptr[g_maxcol]; int ind[g_maxcol]; // -1 = no data, 1 = NULL, 0 = not NULL uint noop; // bit: omit in NdbOperation (implicit NULL INS or no UPD) @@ -342,14 +352,15 @@ struct Data { memset(pk2, 0, sizeof(pk2)); seq = 0; memset(cc1, 0, sizeof(cc1)); - tx1.val = tx2.val = 0; - tx1.len = tx2.len = 0; + tx1.val = tx2.val = bl1.val = 0; + tx1.len = tx2.len = bl1.len = 0; ptr[0].u32 = &pk1; ptr[1].ch = pk2; ptr[2].u32 = &seq; ptr[3].ch = cc1; ptr[4].txt = &tx1; ptr[5].txt = &tx2; + ptr[6].txt = &bl1; for (i = 0; i < g_maxcol; i++) ind[i] = -1; noop = 0; @@ -358,6 +369,7 @@ struct Data { void free() { delete [] tx1.val; delete [] tx2.val; + delete [] bl1.val; init(); } }; @@ -379,6 +391,7 @@ cmpcol(const Col& c, const Data& d1, const Data& d2) return 1; break; case NdbDictionary::Column::Text: + case NdbDictionary::Column::Blob: { const Data::Txt& t1 = *d1.ptr[i].txt; const Data::Txt& t2 = *d2.ptr[i].txt; @@ -429,6 +442,7 @@ operator<<(NdbOut& out, const Data& d) } break; case NdbDictionary::Column::Text: + case NdbDictionary::Column::Blob: { Data::Txt& t = *d.ptr[i].txt; bool first = true; @@ -1071,19 +1085,21 @@ makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t) } break; case NdbDictionary::Column::Text: + case NdbDictionary::Column::Blob: { + const bool tinyblob = (c.type == NdbDictionary::Column::Blob); Data::Txt& t = *d.ptr[i].txt; delete [] t.val; t.val = 0; if (g_opts.tweak & 1) { - uint u = 256 + 2000; + uint u = g_blobinlinesize + (tinyblob ? 0 : g_blobpartsize); uint v = (g_opts.tweak & 2) ? 0 : urandom(strlen(g_charval)); t.val = new char [u]; t.len = u; memset(t.val, g_charval[v], u); break; } - uint u = urandom(g_maxblobsize); + uint u = urandom(tinyblob ? g_blobinlinesize : g_maxblobsize); u = urandom(u); // 4x bias for smaller blobs u = urandom(u); t.val = new char [u]; From 97c6ff7bf2d1d85c3e835ff924aec58a77029287 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2006 07:27:49 +0100 Subject: [PATCH 04/15] ndb - wl#2972 injector cleanup accessed blob event ops via Ndb => crash storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: hide blob event ops under main op storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp: hide blob event ops under main op --- .../ndb/src/ndbapi/NdbEventOperationImpl.cpp | 23 +++++++++++-------- .../ndb/src/ndbapi/NdbEventOperationImpl.hpp | 7 ++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index c195da16480..822a223cf5a 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -337,14 +337,16 @@ NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) break; } tLastBlopOp = tBlobOp; - tBlobOp = tBlobOp->theNextBlobOp; + tBlobOp = tBlobOp->m_next; } DBUG_PRINT("info", ("%s op %s", tBlobOp ? " reuse" : " create", bename)); // create blob event op if not found if (tBlobOp == NULL) { - NdbEventOperation* tmp = m_ndb->createEventOperation(bename); + // to hide blob op it is linked under main op, not under m_ndb + NdbEventOperation* tmp = + m_ndb->theEventBuffer->createEventOperation(bename, m_error); if (tmp == NULL) DBUG_RETURN(NULL); tBlobOp = &tmp->m_impl; @@ -357,8 +359,8 @@ NdbEventOperationImpl::getBlobHandle(const NdbColumnImpl *tAttrInfo, int n) if (tLastBlopOp == NULL) theBlobOpList = tBlobOp; else - tLastBlopOp->theNextBlobOp = tBlobOp; - tBlobOp->theNextBlobOp = NULL; + tLastBlopOp->m_next = tBlobOp; + tBlobOp->m_next = NULL; } } @@ -484,7 +486,7 @@ NdbEventOperationImpl::execute_nolock() r = blob_op->execute_nolock(); if (r != 0) break; - blob_op = blob_op->theNextBlobOp; + blob_op = blob_op->m_next; } } if (r == 0) @@ -2017,12 +2019,15 @@ NdbEventBuffer::dropEventOperation(NdbEventOperation* tOp) m_dropped_ev_op->m_prev= op; m_dropped_ev_op= op; - // drop blob ops - while (op->theBlobOpList != NULL) + // stop blob event ops + if (op->theMainOp == NULL) { NdbEventOperationImpl* tBlobOp = op->theBlobOpList; - op->theBlobOpList = op->theBlobOpList->theNextBlobOp; - (void)m_ndb->dropEventOperation(tBlobOp); + while (tBlobOp != NULL) + { + tBlobOp->stop(); + tBlobOp = tBlobOp->m_next; + } } // ToDo, take care of these to be deleted at the diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp index c91fd966b18..5e52befbf3f 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -223,11 +223,8 @@ public: NdbRecAttr *theCurrentDataAttrs[2]; NdbBlob* theBlobList; - union { - NdbEventOperationImpl* theBlobOpList; - NdbEventOperationImpl* theNextBlobOp; - }; - NdbEventOperationImpl* theMainOp; // blob op pointer to main op + NdbEventOperationImpl* theBlobOpList; // in main op, list of blob ops + NdbEventOperationImpl* theMainOp; // in blob op, the main op NdbEventOperation::State m_state; /* note connection to mi_type */ Uint32 mi_type; /* should be == 0 if m_state != EO_EXECUTING From f37545521b112444c5468fb37e00970c192000af Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2006 23:20:23 -0600 Subject: [PATCH 05/15] bug #14354 - data directory and index directory not working for partitions mysql-test/r/partition_mgm_err.result: only the single drop table since we have disabled query logging for the create table mysql-test/t/partition_mgm_err.test: test for bug #14354 first make sure /tmp/bug14354 is not there, then make the dir create a partitioned table with the partition using /tmp/bug14354 as it's data dir we are disabling query logging since we are using $MYSQL_TEST_DIR and we are not certain where the tmp files will be created. sql/ha_partition.cc: pass partition filename with pathname into set_up_table_before_create. remove the path from the passed in value and then append the filename to the data_file_name or index_file_name if those values were specified. sql/ha_partition.h: added partition_name_with_path to set_up_table_before_create sql/mysql_priv.h: move append_file_to_dir to mysql_priv.h sql/sql_parse.cc: moving append_file_to_dir to mysql_priv.h sql/sql_partition.cc: add_keyword_string was not writing keyword value with quotes --- mysql-test/r/partition_mgm_err.result | 1 + mysql-test/t/partition_mgm_err.test | 16 ++++++++++++++++ sql/ha_partition.cc | 16 +++++++++++++--- sql/ha_partition.h | 6 ++++-- sql/mysql_priv.h | 2 ++ sql/sql_parse.cc | 6 ++---- sql/sql_partition.cc | 16 ++++++++++++---- 7 files changed, 50 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/partition_mgm_err.result b/mysql-test/r/partition_mgm_err.result index 01709e726bd..840c9cc72ef 100644 --- a/mysql-test/r/partition_mgm_err.result +++ b/mysql-test/r/partition_mgm_err.result @@ -107,3 +107,4 @@ ALTER TABLE t1 DROP PARTITION x1; ALTER TABLE t1 DROP PARTITION x0; ERROR HY000: Cannot remove all partitions, use DROP TABLE instead DROP TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/t/partition_mgm_err.test b/mysql-test/t/partition_mgm_err.test index 92848fc135e..460171c99b5 100644 --- a/mysql-test/t/partition_mgm_err.test +++ b/mysql-test/t/partition_mgm_err.test @@ -158,3 +158,19 @@ ALTER TABLE t1 DROP PARTITION x1; ALTER TABLE t1 DROP PARTITION x0; DROP TABLE t1; + +# +# BUG: 14354 Partitions: data directory clause fails +# +--exec rm -rf $MYSQL_TEST_DIR/var/tmp/bug14354 +--exec mkdir $MYSQL_TEST_DIR/var/tmp/bug14354 +disable_query_log; +eval CREATE TABLE t1 (id int) PARTITION BY RANGE(id) ( +PARTITION p1 VALUES LESS THAN (20) ENGINE=myiasm +DATA DIRECTORY="$MYSQL_TEST_DIR/var/tmp/bug14354" +INDEX DIRECTORY="$MYSQL_TEST_DIR/var/tmp/bug14354"); +enable_query_log; +--exec test -f $MYSQL_TEST_DIR/var/tmp/bug14354/t1_p1.MYD +--exec test -f $MYSQL_TEST_DIR/var/tmp/bug14354/t1_p1.MYI +DROP TABLE t1; +--exec rm -rf $MYSQL_TEST_DIR/var/tmp/bug14354 diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d7549c1a95b..7e580b3b56d 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -507,7 +507,7 @@ uint ha_partition::del_ren_cre_table(const char *from, error= (*file)->delete_table((const char*) from_buff); else { - set_up_table_before_create(table_arg, create_info, i); + set_up_table_before_create(table_arg, from_buff, create_info, i); error= (*file)->create(from_buff, table_arg, create_info); } name_buffer_ptr= strend(name_buffer_ptr) + 1; @@ -550,8 +550,9 @@ partition_element *ha_partition::find_partition_element(uint part_id) void ha_partition::set_up_table_before_create(TABLE *table, - HA_CREATE_INFO *info, - uint part_id) + const char *partition_name_with_path, + HA_CREATE_INFO *info, + uint part_id) { /* Set up @@ -565,6 +566,15 @@ void ha_partition::set_up_table_before_create(TABLE *table, return; // Fatal error table->s->max_rows= part_elem->part_max_rows; table->s->min_rows= part_elem->part_min_rows; + char *partition_name= strrchr(partition_name_with_path, FN_LIBCHAR); + if (part_elem->index_file_name) + append_file_to_dir(current_thd, + (const char**)&part_elem->index_file_name, + partition_name+1); + if (part_elem->data_file_name) + append_file_to_dir(current_thd, + (const char**)&part_elem->data_file_name, + partition_name+1); info->index_file_name= part_elem->index_file_name; info->data_file_name= part_elem->data_file_name; } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 03acf217419..5491df596e5 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -197,8 +197,10 @@ private: bool new_handlers_from_part_info(); bool create_handlers(); void clear_handler_file(); - void set_up_table_before_create(TABLE * table_arg, HA_CREATE_INFO * info, - uint part_id); + void set_up_table_before_create(TABLE *table_arg, + const char *partition_name_with_path, + HA_CREATE_INFO *info, + uint part_id); partition_element *find_partition_element(uint part_id); public: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 026234caf34..763afe3da0a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -636,6 +636,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); bool check_dup(const char *db, const char *name, TABLE_LIST *tables); +bool append_file_to_dir(THD *thd, const char **filename_ptr, + const char *table_name); bool table_cache_init(void); void table_cache_free(void); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ecde4d01ae1..95b0ebdeead 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -68,8 +68,6 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_multi_update_lock(THD *thd); static void remove_escape(char *name); static void refresh_status(THD *thd); -static bool append_file_to_dir(THD *thd, const char **filename_ptr, - const char *table_name); const char *any_db="*any*"; // Special symbol for check_access @@ -6733,8 +6731,8 @@ static void refresh_status(THD *thd) /* If pointer is not a null pointer, append filename to it */ -static bool append_file_to_dir(THD *thd, const char **filename_ptr, - const char *table_name) +bool append_file_to_dir(THD *thd, const char **filename_ptr, + const char *table_name) { char buff[FN_REFLEN],*ptr, *end; if (!*filename_ptr) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 20d14f5f196..63b8f24a0cc 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1936,13 +1936,18 @@ static int add_int(File fptr, longlong number) } static int add_keyword_string(File fptr, const char *keyword, + bool should_use_quotes, const char *keystr) { int err= add_string(fptr, keyword); err+= add_space(fptr); err+= add_equal(fptr); err+= add_space(fptr); + if (should_use_quotes) + err+= add_string(fptr, "'"); err+= add_string(fptr, keystr); + if (should_use_quotes) + err+= add_string(fptr, "'"); return err + add_space(fptr); } @@ -1968,7 +1973,8 @@ static int add_partition_options(File fptr, partition_element *p_elem) { int err= 0; if (p_elem->tablespace_name) - err+= add_keyword_string(fptr,"TABLESPACE",p_elem->tablespace_name); + err+= add_keyword_string(fptr,"TABLESPACE", FALSE, + p_elem->tablespace_name); if (p_elem->nodegroup_id != UNDEF_NODEGROUP) err+= add_keyword_int(fptr,"NODEGROUP",(longlong)p_elem->nodegroup_id); if (p_elem->part_max_rows) @@ -1976,11 +1982,13 @@ static int add_partition_options(File fptr, partition_element *p_elem) if (p_elem->part_min_rows) err+= add_keyword_int(fptr,"MIN_ROWS",(longlong)p_elem->part_min_rows); if (p_elem->data_file_name) - err+= add_keyword_string(fptr,"DATA DIRECTORY",p_elem->data_file_name); + err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE, + p_elem->data_file_name); if (p_elem->index_file_name) - err+= add_keyword_string(fptr,"INDEX DIRECTORY",p_elem->index_file_name); + err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE, + p_elem->index_file_name); if (p_elem->part_comment) - err+= add_keyword_string(fptr, "COMMENT",p_elem->part_comment); + err+= add_keyword_string(fptr, "COMMENT", FALSE, p_elem->part_comment); return err + add_engine(fptr,p_elem->engine_type); } From 5f7d84930dd25cb0ddc63da501cf7b2177aea996 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Jan 2006 10:47:04 +0100 Subject: [PATCH 06/15] bug#16738 - ndb dd - out of diskspace fix typo + add error code to printable list storage/ndb/include/kernel/signaldata/Extent.hpp: Set correct error code storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp: err is already negative storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp: Set correct error code storage/ndb/src/ndbapi/ndberror.c: Add error code to printable list --- storage/ndb/include/kernel/signaldata/Extent.hpp | 2 +- storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp | 4 +--- storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp | 1 + storage/ndb/src/ndbapi/ndberror.c | 4 +++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/storage/ndb/include/kernel/signaldata/Extent.hpp b/storage/ndb/include/kernel/signaldata/Extent.hpp index 8443a2b3d45..86f45163be5 100644 --- a/storage/ndb/include/kernel/signaldata/Extent.hpp +++ b/storage/ndb/include/kernel/signaldata/Extent.hpp @@ -32,7 +32,7 @@ struct AllocExtentReq { enum ErrorCode { UnmappedExtentPageIsNotImplemented = 1, - NoExtentAvailable = 2 + NoExtentAvailable = 1601 }; union diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index 5dfe08fac28..36b259bdddc 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -270,11 +270,9 @@ Dbtup::disk_page_prealloc(Signal* signal, if ((err= tsman.alloc_extent(&ext.p->m_key)) < 0) { - //XXX c_extent_pool.release(ext); c_page_request_pool.release(req); - ndbout_c("no free extent"); - return -err; + return err; } int pages= err; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 42831fab667..bc186e53492 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1439,6 +1439,7 @@ int Dbtup::handleInsertReq(Signal* signal, int ret= disk_page_prealloc(signal, fragPtr, &tmp, size); if (unlikely(ret < 0)) { + terrorCode = -ret; goto disk_prealloc_error; } diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c index fc027721b23..389c1008536 100644 --- a/storage/ndb/src/ndbapi/ndberror.c +++ b/storage/ndb/src/ndbapi/ndberror.c @@ -80,6 +80,7 @@ static const char* empty_string = ""; * 1300 - BACKUP * 1400 - SUMA * 1500 - LGMAN + * 1600 - TSMAN * 4000 - API * 4100 - "" * 4200 - "" @@ -197,7 +198,8 @@ ErrorBundle ErrorCodes[] = { { 903, HA_ERR_INDEX_FILE_FULL, IS, "Too many ordered indexes (increase MaxNoOfOrderedIndexes)" }, { 904, HA_ERR_INDEX_FILE_FULL, IS, "Out of fragment records (increase MaxNoOfOrderedIndexes)" }, { 905, DMEC, IS, "Out of attribute records (increase MaxNoOfAttributes)" }, - + { 1601, HA_ERR_RECORD_FILE_FULL, IS, "Out extents, tablespace full" }, + /** * TimeoutExpired */ From d5e109ea6a115592f83b1c5346c252b344f9ba4d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Jan 2006 11:41:58 +0100 Subject: [PATCH 07/15] bug#16742 - ndb dd - round filesize upwards storage/ndb/src/kernel/blocks/tsman.cpp: Round filesize upwards --- storage/ndb/src/kernel/blocks/tsman.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/storage/ndb/src/kernel/blocks/tsman.cpp b/storage/ndb/src/kernel/blocks/tsman.cpp index 2bb08010abe..f73b7e14169 100644 --- a/storage/ndb/src/kernel/blocks/tsman.cpp +++ b/storage/ndb/src/kernel/blocks/tsman.cpp @@ -684,20 +684,15 @@ Tsman::open_file(Signal* signal, req->file_size_lo = lo; Uint64 pages = (Uint64(hi) << 32 | lo) / File_formats::NDB_PAGE_SIZE; - - // Extent size in #pages - Uint32 extent_size = ts_ptr.p->m_extent_size; + Uint32 extent_size = ts_ptr.p->m_extent_size; // Extent size in #pages + Uint64 extents = (pages + extent_size - 1) / extent_size; + extents = extents ? extents : 1; + Uint64 data_pages = extents * extent_size; + Uint32 eh_words = File_formats::Datafile::extent_header_words(extent_size); ndbrequire(eh_words < File_formats::Datafile::EXTENT_PAGE_WORDS); - Uint32 extents_per_page = File_formats::Datafile::EXTENT_PAGE_WORDS/eh_words; - Uint64 tmp = Uint64(extents_per_page) * Uint64(extent_size); - Uint64 extent_pages = pages / (1+tmp); - extent_pages = extent_pages ? extent_pages : 1; - - Uint64 data_pages = pages - extent_pages -1; - Uint64 extents = data_pages / extent_size; - data_pages = extents * extent_size; + Uint64 extent_pages = (extents + extents_per_page - 1) / extents_per_page; ptr.p->m_create.m_extent_pages = extent_pages; ptr.p->m_create.m_data_pages = data_pages; From 516a6d9375d0099a4c8a3d2ec45e9f4536e31b9b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 06:01:54 +0300 Subject: [PATCH 08/15] Compile failure fix for gcc 2.95x: Don't use unnamed union of unnamed structs in PARTITION_ITERATOR --- sql/handler.h | 34 ++++++++++++++++++++-------------- sql/sql_partition.cc | 36 ++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index a2f37168232..43495b46cce 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -737,17 +737,23 @@ typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter); typedef struct st_partition_iter { partition_iter_func get_next; + + struct st_part_num_range + { + uint32 start; + uint32 end; + }; - union { - struct { - uint32 start_part_num; - uint32 end_part_num; - }; - struct { - longlong start_val; - longlong end_val; - }; - bool null_returned; + struct st_field_value_range + { + longlong start; + longlong end; + }; + + union + { + struct st_part_num_range part_nums; + struct st_field_value_range field_vals; }; partition_info *part_info; } PARTITION_ITERATOR; @@ -1004,8 +1010,8 @@ uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); inline void init_single_partition_iterator(uint32 part_id, PARTITION_ITERATOR *part_iter) { - part_iter->start_part_num= part_id; - part_iter->end_part_num= part_id+1; + part_iter->part_nums.start= part_id; + part_iter->part_nums.end= part_id+1; part_iter->get_next= get_next_partition_id_range; } @@ -1013,8 +1019,8 @@ inline void init_all_partitions_iterator(partition_info *part_info, PARTITION_ITERATOR *part_iter) { - part_iter->start_part_num= 0; - part_iter->end_part_num= part_info->no_parts; + part_iter->part_nums.start= 0; + part_iter->part_nums.end= part_info->no_parts; part_iter->get_next= get_next_partition_id_range; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 453aca54e67..41531add51c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5751,7 +5751,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, /* Find minimum */ if (flags & NO_MIN_RANGE) - part_iter->start_part_num= 0; + part_iter->part_nums.start= 0; else { /* @@ -5763,21 +5763,21 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, store_key_image_to_rec(field, min_value, field_len); bool include_endp= part_info->range_analysis_include_bounds || !test(flags & NEAR_MIN); - part_iter->start_part_num= get_endpoint(part_info, 1, include_endp); - if (part_iter->start_part_num == max_endpoint_val) + part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); + if (part_iter->part_nums.start == max_endpoint_val) return 0; /* No partitions */ } /* Find maximum, do the same as above but for right interval bound */ if (flags & NO_MAX_RANGE) - part_iter->end_part_num= max_endpoint_val; + part_iter->part_nums.end= max_endpoint_val; else { store_key_image_to_rec(field, max_value, field_len); bool include_endp= part_info->range_analysis_include_bounds || !test(flags & NEAR_MAX); - part_iter->end_part_num= get_endpoint(part_info, 0, include_endp); - if (part_iter->start_part_num == part_iter->end_part_num) + part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp); + if (part_iter->part_nums.start== part_iter->part_nums.end) return 0; /* No partitions */ } return 1; /* Ok, iterator initialized */ @@ -5907,8 +5907,8 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (n_values > total_parts || n_values > MAX_RANGE_TO_WALK) return -1; - part_iter->start_val= a; - part_iter->end_val= b; + part_iter->field_vals.start= a; + part_iter->field_vals.end= b; part_iter->part_info= part_info; part_iter->get_next= get_next_func; return 1; @@ -5933,10 +5933,10 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) { - if (part_iter->start_part_num == part_iter->end_part_num) + if (part_iter->part_nums.start== part_iter->part_nums.end) return NOT_A_PARTITION_ID; else - return part_iter->start_part_num++; + return part_iter->part_nums.start++; } @@ -5959,11 +5959,11 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) { - if (part_iter->start_part_num == part_iter->end_part_num) + if (part_iter->part_nums.start == part_iter->part_nums.end) return NOT_A_PARTITION_ID; else return part_iter->part_info->list_array[part_iter-> - start_part_num++].partition_id; + part_nums.start++].partition_id; } @@ -5988,10 +5988,10 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter) { uint32 part_id; Field *field= part_iter->part_info->part_field_array[0]; - while (part_iter->start_val != part_iter->end_val) + while (part_iter->field_vals.start != part_iter->field_vals.end) { - field->store(part_iter->start_val, FALSE); - part_iter->start_val++; + field->store(part_iter->field_vals.start, FALSE); + part_iter->field_vals.start++; longlong dummy; if (!part_iter->part_info->get_partition_id(part_iter->part_info, &part_id, &dummy)) @@ -6007,10 +6007,10 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) { uint32 part_id; Field *field= part_iter->part_info->subpart_field_array[0]; - if (part_iter->start_val == part_iter->end_val) + if (part_iter->field_vals.start == part_iter->field_vals.end) return NOT_A_PARTITION_ID; - field->store(part_iter->start_val, FALSE); - part_iter->start_val++; + field->store(part_iter->field_vals.start, FALSE); + part_iter->field_vals.start++; return part_iter->part_info->get_subpartition_id(part_iter->part_info); } #endif From 8dc5a6c6ebd5e81c178ce05b26ac5df0d243d46d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 09:47:56 +0100 Subject: [PATCH 09/15] bug#16771 - ndb dd - fix leak of extents storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp: Add debug printouts storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp: Add debug printouts Fix leak of extents storage/ndb/src/kernel/blocks/pgman.cpp: Add debug printouts --- storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp | 3 +- .../kernel/blocks/dbtup/DbtupDiskAlloc.cpp | 207 +++++++++++++----- storage/ndb/src/kernel/blocks/pgman.cpp | 20 ++ 3 files changed, 178 insertions(+), 52 deletions(-) diff --git a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index e49ca17b880..df929dafbd1 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -565,7 +565,6 @@ typedef Ptr FragoperrecPtr; * */ STATIC_CONST( SZ = EXTENT_SEARCH_MATRIX_SIZE ); - Uint32 m_extent_search_matrix[SZ]; // 4x4 DLList::Head m_free_extents[SZ]; Uint32 m_total_extent_free_space_thresholds[EXTENT_SEARCH_MATRIX_ROWS]; Uint32 m_page_free_bits_map[EXTENT_SEARCH_MATRIX_COLS]; @@ -593,6 +592,8 @@ typedef Ptr FragoperrecPtr; SLList::Head m_extent_list; }; + void dump_disk_alloc(Disk_alloc_info&); + struct Fragrecord { Uint32 nextStartRange; Uint32 currentPageRange; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index 36b259bdddc..dbc0e254e57 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -17,6 +17,112 @@ #define DBTUP_C #include "Dbtup.hpp" +static +NdbOut& +operator<<(NdbOut& out, const Ptr & ptr) +{ + out << "[ Page: ptr.i: " << ptr.i + << " [ m_file_no: " << ptr.p->m_file_no + << " m_page_no: " << ptr.p->m_page_no << "]" + << " list_index: " << ptr.p->list_index + << " free_space: " << ptr.p->free_space + << " uncommitted_used_space: " << ptr.p->uncommitted_used_space + << " ]"; + return out; +} + +static +NdbOut& +operator<<(NdbOut& out, const Ptr & ptr) +{ + out << "[ Page_request: ptr.i: " << ptr.i + << " " << ptr.p->m_key + << " m_estimated_free_space: " << ptr.p->m_estimated_free_space + << " m_list_index: " << ptr.p->m_list_index + << " m_frag_ptr_i: " << ptr.p->m_frag_ptr_i + << " m_extent_info_ptr: " << ptr.p->m_extent_info_ptr + << " m_ref_count: " << ptr.p->m_ref_count + << " m_uncommitted_used_space: " << ptr.p->m_uncommitted_used_space + << " ]"; + + return out; +} + +static +NdbOut& +operator<<(NdbOut& out, const Ptr & ptr) +{ + out << "[ Extent_info: ptr.i " << ptr.i + << " " << ptr.p->m_key + << " m_first_page_no: " << ptr.p->m_first_page_no + << " m_free_space: " << ptr.p->m_free_space + << " m_free_matrix_pos: " << ptr.p->m_free_matrix_pos + << " m_free_page_count: ["; + + for(Uint32 i = 0; im_free_page_count[i]; + out << " ] ]"; + + return out; +} + +void +Dbtup::dump_disk_alloc(Dbtup::Disk_alloc_info & alloc) +{ + ndbout_c("dirty pages"); + for(Uint32 i = 0; i ptr; + ArrayPool *pool= (ArrayPool*)&m_global_page_pool; + LocalDLList list(*pool, alloc.m_dirty_pages[i]); + for(list.first(ptr); !ptr.isNull(); list.next(ptr)) + { + ndbout << ptr << " "; + } + ndbout_c(""); + } + ndbout_c("page requests"); + for(Uint32 i = 0; i ptr; + LocalDLList list(c_page_request_pool, + alloc.m_page_requests[i]); + for(list.first(ptr); !ptr.isNull(); list.next(ptr)) + { + ndbout << ptr << " "; + } + ndbout_c(""); + } + + ndbout_c("Extent matrix"); + for(Uint32 i = 0; i ptr; + LocalDLList list(c_extent_pool, alloc.m_free_extents[i]); + for(list.first(ptr); !ptr.isNull(); list.next(ptr)) + { + ndbout << ptr << " "; + } + ndbout_c(""); + } + + if (alloc.m_curr_extent_info_ptr_i != RNIL) + { + Ptr ptr; + c_extent_pool.getPtr(ptr, alloc.m_curr_extent_info_ptr_i); + ndbout << "current extent: " << ptr << endl; + } +} + +#if defined VM_TRACE || true +#define ddassert(x) do { if(unlikely(!(x))) { dump_disk_alloc(alloc); ndbrequire(false); } } while(0) +#else +#define ddassert(x) +#endif + Dbtup::Disk_alloc_info::Disk_alloc_info(const Tablerec* tabPtrP, Uint32 extent_size) { @@ -60,20 +166,20 @@ Dbtup::Disk_alloc_info::find_extent(Uint32 sz) const * Find the biggest available (with most free space) * Return position in matrix */ + Uint32 col = calc_page_free_bits(sz); Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1; for(Uint32 i= 0; i= col) + { + i = (i & ~mask) + mask; + } } return RNIL; @@ -92,13 +198,7 @@ Dbtup::Disk_alloc_info::calc_extent_pos(const Extent_info* extP) const * if zero (or very small free space) put * absolutly last */ - { - - printf("free space %d free_page_thresholds ", free); - for(Uint32 i = 0; im_free_page_count[i]); - ndbout_c(" -> row: %d col: %d -> pos= %d", row, col, pos); - assert(pos < EXTENT_SEARCH_MATRIX_SIZE); return pos; } @@ -237,7 +332,9 @@ Dbtup::disk_page_prealloc(Signal* signal, * and since it couldn't accomadate the request * we put it on the free list */ + alloc.m_curr_extent_info_ptr_i = RNIL; Uint32 pos= alloc.calc_extent_pos(ext.p); + ext.p->m_free_matrix_pos = pos; LocalDLList list(c_extent_pool, alloc.m_free_extents[pos]); list.add(ext); } @@ -290,7 +387,14 @@ Dbtup::disk_page_prealloc(Signal* signal, alloc.m_curr_extent_info_ptr_i= ext.i; ext.p->m_free_matrix_pos= RNIL; pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits); - ndbassert(pageBits >= 0); +#ifdef VM_TRACE + ddassert(pageBits >= 0); +#else + if (unlikely(pageBits < 0)) + { + return -AllocExtentReq::NoExtentAvailable; + } +#endif } /** @@ -305,18 +409,18 @@ Dbtup::disk_page_prealloc(Signal* signal, */ Uint32 size= alloc.calc_page_free_space((Uint32)pageBits); - ndbassert(size >= sz); + ddassert(size >= sz); Uint32 new_size = size - sz; // Subtract alloc rec req.p->m_estimated_free_space= new_size; // Store on page request Uint32 newPageBits= alloc.calc_page_free_bits(new_size); if (newPageBits != (Uint32)pageBits) { - ndbassert(ext.p->m_free_page_count[pageBits] > 0); + ddassert(ext.p->m_free_page_count[pageBits] > 0); ext.p->m_free_page_count[pageBits]--; ext.p->m_free_page_count[newPageBits]++; } - ndbassert(ext.p->m_free_space >= sz); + ddassert(ext.p->m_free_space >= sz); ext.p->m_free_space -= sz; // And put page request in correct free list @@ -365,13 +469,13 @@ Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc, Ptr pagePtr, Uint32 old_idx, Uint32 sz) { - ndbassert(pagePtr.p->list_index == old_idx); + ddassert(pagePtr.p->list_index == old_idx); Uint32 free= pagePtr.p->free_space; Uint32 used= pagePtr.p->uncommitted_used_space + sz; Uint32 ext= pagePtr.p->m_extent_info_ptr; - ndbassert(free >= used); + ddassert(free >= used); Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); @@ -385,14 +489,14 @@ Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc, old_list.remove(pagePtr); new_list.add(pagePtr); - ndbassert(extentPtr.p->m_free_page_count[old_idx]); + ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; pagePtr.p->list_index= new_idx; } pagePtr.p->uncommitted_used_space = used; - ndbassert(extentPtr.p->m_free_space >= sz); + ddassert(extentPtr.p->m_free_space >= sz); extentPtr.p->m_free_space -= sz; Uint32 old_pos= extentPtr.p->m_free_matrix_pos; if (old_pos != RNIL) // Current extent @@ -417,7 +521,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, Ptr req, Uint32 old_idx, Uint32 sz) { - ndbassert(req.p->m_list_index == old_idx); + ddassert(req.p->m_list_index == old_idx); Uint32 free= req.p->m_estimated_free_space; Uint32 used= req.p->m_uncommitted_used_space + sz; @@ -426,7 +530,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); - ndbassert(free >= sz); + ddassert(free >= sz); Uint32 new_idx= alloc.calc_page_free_bits(free - sz); if (old_idx != new_idx) @@ -437,7 +541,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, old_list.remove(req); new_list.add(req); - ndbassert(extentPtr.p->m_free_page_count[old_idx]); + ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; req.p->m_list_index= new_idx; @@ -445,7 +549,7 @@ Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, req.p->m_uncommitted_used_space = used; req.p->m_estimated_free_space = free - sz; - ndbassert(extentPtr.p->m_free_space >= sz); + ddassert(extentPtr.p->m_free_space >= sz); extentPtr.p->m_free_space -= sz; Uint32 old_pos= extentPtr.p->m_free_matrix_pos; if (old_pos != RNIL) // Current extent @@ -551,11 +655,11 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, * 3) register callback in pgman (unmap callback) * 4) inform pgman about current users */ - ndbassert((page->list_index & 0x8000) == 0x8000); - ndbassert(page->m_extent_info_ptr == req.p->m_extent_info_ptr); - ndbassert(page->m_page_no == req.p->m_key.m_page_no); - ndbassert(page->m_file_no == req.p->m_key.m_file_no); Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; + ddassert((page->list_index & 0x8000) == 0x8000); + ddassert(page->m_extent_info_ptr == req.p->m_extent_info_ptr); + ddassert(page->m_page_no == req.p->m_key.m_page_no); + ddassert(page->m_file_no == req.p->m_key.m_file_no); Uint32 old_idx = req.p->m_list_index; Uint32 free= req.p->m_estimated_free_space; @@ -564,9 +668,9 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, Uint32 real_free = page->free_space; Uint32 real_used = used + page->uncommitted_used_space; - ndbassert(real_free >= free); - ndbassert(real_free >= real_used); - ndbassert(alloc.calc_page_free_bits(free) == old_idx); + ddassert(real_free >= free); + ddassert(real_free >= real_used); + ddassert(alloc.calc_page_free_bits(free) == old_idx); Uint32 new_idx= alloc.calc_page_free_bits(real_free - real_used); /** @@ -587,7 +691,7 @@ Dbtup::disk_page_prealloc_callback_common(Signal* signal, if (old_idx != new_idx) { - ndbassert(extentPtr.p->m_free_page_count[old_idx]); + ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; } @@ -721,13 +825,14 @@ Dbtup::disk_page_alloc(Signal* signal, Local_key* key, PagePtr pagePtr, Uint32 gci) { Uint32 logfile_group_id= fragPtrP->m_logfile_group_id; + Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; Uint64 lsn; Uint32 old_free = pagePtr.p->free_space; - Uint32 old_bits= fragPtrP->m_disk_alloc_info.calc_page_free_bits(old_free); + Uint32 old_bits= alloc.calc_page_free_bits(old_free); if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0) { - ndbassert(pagePtr.p->uncommitted_used_space > 0); + ddassert(pagePtr.p->uncommitted_used_space > 0); pagePtr.p->uncommitted_used_space--; key->m_page_idx= ((Fix_page*)pagePtr.p)->alloc_record(); lsn= disk_page_undo_alloc(pagePtr.p, key, 1, gci, logfile_group_id); @@ -735,7 +840,7 @@ Dbtup::disk_page_alloc(Signal* signal, else { Uint32 sz= key->m_page_idx; - ndbassert(pagePtr.p->uncommitted_used_space >= sz); + ddassert(pagePtr.p->uncommitted_used_space >= sz); pagePtr.p->uncommitted_used_space -= sz; key->m_page_idx= ((Var_page*)pagePtr.p)-> alloc_record(sz, (Var_page*)ctemp_page, 0); @@ -744,7 +849,7 @@ Dbtup::disk_page_alloc(Signal* signal, } Uint32 new_free = pagePtr.p->free_space; - Uint32 new_bits= fragPtrP->m_disk_alloc_info.calc_page_free_bits(new_free); + Uint32 new_bits= alloc.calc_page_free_bits(new_free); if (old_bits != new_bits) { @@ -806,20 +911,20 @@ Dbtup::disk_page_free(Signal *signal, Uint32 ext = pagePtr.p->m_extent_info_ptr; Uint32 used = pagePtr.p->uncommitted_used_space; - ndbassert(old_free >= used); - ndbassert(new_free >= used); - ndbassert(new_free >= old_free); + ddassert(old_free >= used); + ddassert(new_free >= used); + ddassert(new_free >= old_free); page_idx = pagePtr.p->list_index; Uint32 old_idx = page_idx & 0x7FFF; Uint32 new_idx = alloc.calc_page_free_bits(new_free - used); - ndbassert(alloc.calc_page_free_bits(old_free - used) == old_idx); + ddassert(alloc.calc_page_free_bits(old_free - used) == old_idx); Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); if (old_idx != new_idx) { - ndbassert(extentPtr.p->m_free_page_count[old_idx]); + ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; @@ -915,16 +1020,16 @@ Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, Uint32 ext = pagePtr.p->m_extent_info_ptr; Uint32 old_idx = page_idx & 0x7FFF; - ndbassert(free >= used); - ndbassert(used >= sz); - ndbassert(alloc.calc_page_free_bits(free - used) == old_idx); + ddassert(free >= used); + ddassert(used >= sz); + ddassert(alloc.calc_page_free_bits(free - used) == old_idx); Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz); Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); if (old_idx != new_idx) { - ndbassert(extentPtr.p->m_free_page_count[old_idx]); + ddassert(extentPtr.p->m_free_page_count[old_idx]); extentPtr.p->m_free_page_count[old_idx]--; extentPtr.p->m_free_page_count[new_idx]++; diff --git a/storage/ndb/src/kernel/blocks/pgman.cpp b/storage/ndb/src/kernel/blocks/pgman.cpp index e7285fc7058..4d85456e960 100644 --- a/storage/ndb/src/kernel/blocks/pgman.cpp +++ b/storage/ndb/src/kernel/blocks/pgman.cpp @@ -40,6 +40,12 @@ #define dbg(x) #endif +#if 1 +#define DBG_LCP(x) +#else +#define DBG_LCP(x) ndbout << x +#endif + Pgman::Pgman(const Configuration & conf) : SimulatedBlock(PGMAN, conf), m_file_map(m_data_buffer_pool), @@ -1083,6 +1089,7 @@ Pgman::execLCP_FRAG_ORD(Signal* signal) LcpFragOrd* ord = (LcpFragOrd*)signal->getDataPtr(); ndbrequire(ord->lcpId >= m_last_lcp_complete + 1 || m_last_lcp_complete == 0); m_last_lcp = ord->lcpId; + DBG_LCP("execLCP_FRAG_ORD" << endl); ndbrequire(!m_lcp_outstanding); ndbrequire(m_lcp_copy_page_free); @@ -1104,6 +1111,8 @@ Pgman::execEND_LCP_REQ(Signal* signal) EndLcpReq* req = (EndLcpReq*)signal->getDataPtr(); m_end_lcp_req = *req; + DBG_LCP("execEND_LCP_REQ" << endl); + #ifdef VM_TRACE debugOut << "PGMAN: execEND_LCP_REQ" @@ -1117,6 +1126,7 @@ Pgman::execEND_LCP_REQ(Signal* signal) ndbrequire(! m_lcp_loop_on); signal->theData[0] = m_end_lcp_req.senderData; sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB); + DBG_LCP("GSN_END_LCP_CONF" << endl); } m_last_lcp_complete = m_last_lcp; @@ -1149,6 +1159,8 @@ Pgman::process_lcp(Signal* signal) Ptr& ptr = iter.curr; Uint16 state = ptr.p->m_state; + DBG_LCP("PROCESS LCP: " << ptr); + if (ptr.p->m_last_lcp < m_last_lcp && (state & Page_entry::DIRTY)) { @@ -1159,6 +1171,7 @@ Pgman::process_lcp(Signal* signal) } if (state & Page_entry::BUSY) { + DBG_LCP(" BUSY" << endl); break; // wait for it } if (state & Page_entry::LOCKED) @@ -1169,6 +1182,7 @@ Pgman::process_lcp(Signal* signal) */ if (!m_lcp_copy_page_free) { + DBG_LCP(" !m_lcp_copy_page_free" << endl); break; } m_lcp_copy_page_free = false; @@ -1183,10 +1197,12 @@ Pgman::process_lcp(Signal* signal) } else if (state & Page_entry::PAGEOUT) { + DBG_LCP(" PAGEOUT -> state |= LCP" << endl); set_page_state(ptr, state | Page_entry::LCP); } else { + DBG_LCP(" pageout()" << endl); ptr.p->m_state |= Page_entry::LCP; pageout(signal, ptr); } @@ -1205,11 +1221,15 @@ Pgman::process_lcp(Signal* signal) { signal->theData[0] = m_end_lcp_req.senderData; sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB); + DBG_LCP("GSN_END_LCP_CONF" << endl); } + DBG_LCP(" -- RETURN FALSE" << endl); m_last_lcp_complete = m_last_lcp; m_lcp_curr_bucket = ~(Uint32)0; return false; } + + DBG_LCP(" -- RETURN TRUE" << endl); return true; } From 837723f652a400a8d85616bec096bfab1a9d93dd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 11:02:19 +0100 Subject: [PATCH 10/15] bug#10987 - ndb - unable to find restorable replica Add massive printout when failure detected storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp: Add dumping of replica info storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Add dumping of replica info --- storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp | 2 + .../ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 79 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp b/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp index 18b0929b017..166917b00d2 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp +++ b/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp @@ -1601,6 +1601,8 @@ private: * Reply from nodeId */ void startInfoReply(Signal *, Uint32 nodeId); + + void dump_replica_info(); }; #if (DIH_CDATA_SIZE < _SYSFILE_SIZE32) diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index de9524d1aee..51c81803ca7 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -8925,6 +8925,80 @@ void Dbdih::packFragIntoPagesLab(Signal* signal, RWFragment* wf) /*****************************************************************************/ /* ********** START FRAGMENT MODULE *************/ /*****************************************************************************/ +void +Dbdih::dump_replica_info() +{ + TabRecordPtr tabPtr; + FragmentstorePtr fragPtr; + + for(tabPtr.i = 0; tabPtr.i < ctabFileSize; tabPtr.i++) + { + ptrCheckGuard(tabPtr, ctabFileSize, tabRecord); + if (tabPtr.p->tabStatus != TabRecord::TS_ACTIVE) + continue; + + for(Uint32 fid = 0; fidtotalfragments; fid++) + { + getFragstore(tabPtr.p, fid, fragPtr); + ndbout_c("tab: %d frag: %d gci: %d\n -- storedReplicas:", + tabPtr.i, fid, SYSFILE->newestRestorableGCI); + + Uint32 i; + ReplicaRecordPtr replicaPtr; + replicaPtr.i = fragPtr.p->storedReplicas; + for(; replicaPtr.i != RNIL; replicaPtr.i = replicaPtr.p->nextReplica) + { + ptrCheckGuard(replicaPtr, creplicaFileSize, replicaRecord); + ndbout_c(" node: %d initialGci: %d nextLcp: %d noCrashedReplicas: %d", + replicaPtr.p->procNode, + replicaPtr.p->initialGci, + replicaPtr.p->nextLcp, + replicaPtr.p->noCrashedReplicas); + for(i = 0; ilcpStatus[i] == ZVALID ?"VALID":"INVALID"), + replicaPtr.p->lcpId[i], + replicaPtr.p->maxGciCompleted[i], + replicaPtr.p->maxGciStarted[i]); + } + + for (i = 0; i < 8; i++) + { + ndbout_c(" crashed replica: %d replicaLastGci: %d createGci: %d", + i, + replicaPtr.p->replicaLastGci[i], + replicaPtr.p->createGci[i]); + } + } + ndbout_c(" -- oldStoredReplicas"); + replicaPtr.i = fragPtr.p->oldStoredReplicas; + for(; replicaPtr.i != RNIL; replicaPtr.i = replicaPtr.p->nextReplica) + { + ptrCheckGuard(replicaPtr, creplicaFileSize, replicaRecord); + for(i = 0; ilcpStatus[i] == ZVALID ?"VALID":"INVALID"), + replicaPtr.p->lcpId[i], + replicaPtr.p->maxGciCompleted[i], + replicaPtr.p->maxGciStarted[i]); + } + + for (i = 0; i < 8; i++) + { + ndbout_c(" crashed replica: %d replicaLastGci: %d createGci: %d", + i, + replicaPtr.p->replicaLastGci[i], + replicaPtr.p->createGci[i]); + } + } + } + } +} + void Dbdih::startFragment(Signal* signal, Uint32 tableId, Uint32 fragId) { Uint32 TloopCount = 0; @@ -8986,6 +9060,7 @@ void Dbdih::startFragment(Signal* signal, Uint32 tableId, Uint32 fragId) /* SEARCH FOR STORED REPLICAS THAT CAN BE USED TO RESTART THE SYSTEM. */ /* ----------------------------------------------------------------------- */ searchStoredReplicas(fragPtr); + if (cnoOfCreateReplicas == 0) { /* --------------------------------------------------------------------- */ /* THERE WERE NO STORED REPLICAS AVAILABLE THAT CAN SERVE AS REPLICA TO*/ @@ -8998,6 +9073,10 @@ void Dbdih::startFragment(Signal* signal, Uint32 tableId, Uint32 fragId) char buf[64]; BaseString::snprintf(buf, sizeof(buf), "table: %d fragment: %d gci: %d", tableId, fragId, SYSFILE->newestRestorableGCI); + + ndbout_c(buf); + dump_replica_info(); + progError(__LINE__, NDBD_EXIT_NO_RESTORABLE_REPLICA, buf); ndbrequire(false); return; From 465960c2e3a5c9bf69e4ac25aec56081ec4edc4a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 22:22:50 +0100 Subject: [PATCH 11/15] ndb - wl#2972 rbr blobs: write blob data to binlog mysql-test/t/disabled.def: rbr blobs: write data + dict cache workarounds sql/ha_ndbcluster.cc: rbr blobs: write data + dict cache workarounds sql/ha_ndbcluster.h: rbr blobs: write data + dict cache workarounds sql/ha_ndbcluster_binlog.cc: rbr blobs: write data + dict cache workarounds storage/ndb/include/ndbapi/NdbDictionary.hpp: rbr blobs: write data + dict cache workarounds storage/ndb/src/ndbapi/NdbBlob.cpp: rbr blobs: write data + dict cache workarounds storage/ndb/src/ndbapi/NdbDictionary.cpp: rbr blobs: write data + dict cache workarounds storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: rbr blobs: write data + dict cache workarounds storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp: rbr blobs: write data + dict cache workarounds --- mysql-test/t/disabled.def | 4 + sql/ha_ndbcluster.cc | 103 +++++++++----- sql/ha_ndbcluster.h | 8 ++ sql/ha_ndbcluster_binlog.cc | 142 +++++++++++++++---- storage/ndb/include/ndbapi/NdbDictionary.hpp | 2 + storage/ndb/src/ndbapi/NdbBlob.cpp | 6 +- storage/ndb/src/ndbapi/NdbDictionary.cpp | 6 + storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp | 46 +++++- storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp | 3 + 9 files changed, 247 insertions(+), 73 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 869b9211e59..6aafa2d8a15 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -28,3 +28,7 @@ ndb_autodiscover : Needs to be fixed w.r.t binlog ndb_autodiscover2 : Needs to be fixed w.r.t binlog system_mysql_db : Needs fixing system_mysql_db_fix : Needs fixing +#ndb_alter_table_row : sometimes wrong error 1015!=1046 +ndb_gis : garbled msgs from corrupt THD* + partitioning problem + +# vim: set filetype=conf: diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3d44c731b80..16b37ede164 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -35,6 +35,11 @@ #include "ha_ndbcluster_binlog.h" +#ifdef ndb_dynamite +#undef assert +#define assert(x) do { if(x) break; ::printf("%s %d: assert failed: %s\n", __FILE__, __LINE__, #x); ::fflush(stdout); ::signal(SIGABRT,SIG_DFL); ::abort(); ::kill(::getpid(),6); ::kill(::getpid(),9); } while (0) +#endif + // options from from mysqld.cc extern my_bool opt_ndb_optimized_node_selection; extern const char *opt_ndbcluster_connectstring; @@ -791,10 +796,20 @@ int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg) if (ndb_blob->blobsNextBlob() != NULL) DBUG_RETURN(0); ha_ndbcluster *ha= (ha_ndbcluster *)arg; - DBUG_RETURN(ha->get_ndb_blobs_value(ndb_blob)); + int ret= get_ndb_blobs_value(ha->table, ha->m_value, + ha->m_blobs_buffer, ha->m_blobs_buffer_size, + 0); + DBUG_RETURN(ret); } -int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob) +/* + This routine is shared by injector. There is no common blobs buffer + so the buffer and length are passed by reference. Injector also + passes a record pointer diff. + */ +int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, + byte*& buffer, uint& buffer_size, + my_ptrdiff_t ptrdiff) { DBUG_ENTER("get_ndb_blobs_value"); @@ -803,44 +818,51 @@ int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob) for (int loop= 0; loop <= 1; loop++) { uint32 offset= 0; - for (uint i= 0; i < table_share->fields; i++) + for (uint i= 0; i < table->s->fields; i++) { Field *field= table->field[i]; - NdbValue value= m_value[i]; + NdbValue value= value_array[i]; if (value.ptr != NULL && (field->flags & BLOB_FLAG)) { Field_blob *field_blob= (Field_blob *)field; NdbBlob *ndb_blob= value.blob; - Uint64 blob_len= 0; - if (ndb_blob->getLength(blob_len) != 0) - DBUG_RETURN(-1); - // Align to Uint64 - uint32 blob_size= blob_len; - if (blob_size % 8 != 0) - blob_size+= 8 - blob_size % 8; - if (loop == 1) - { - char *buf= m_blobs_buffer + offset; - uint32 len= 0xffffffff; // Max uint32 - DBUG_PRINT("value", ("read blob ptr=%lx len=%u", - buf, (uint) blob_len)); - if (ndb_blob->readData(buf, len) != 0) + int isNull; + ndb_blob->getDefined(isNull); + if (isNull == 0) { // XXX -1 should be allowed only for events + Uint64 blob_len= 0; + if (ndb_blob->getLength(blob_len) != 0) DBUG_RETURN(-1); - DBUG_ASSERT(len == blob_len); - field_blob->set_ptr(len, buf); + // Align to Uint64 + uint32 blob_size= blob_len; + if (blob_size % 8 != 0) + blob_size+= 8 - blob_size % 8; + if (loop == 1) + { + char *buf= buffer + offset; + uint32 len= 0xffffffff; // Max uint32 + DBUG_PRINT("info", ("read blob ptr=%p len=%u", + buf, (uint) blob_len)); + if (ndb_blob->readData(buf, len) != 0) + DBUG_RETURN(-1); + DBUG_ASSERT(len == blob_len); + // Ugly hack assumes only ptr needs to be changed + field_blob->ptr += ptrdiff; + field_blob->set_ptr(len, buf); + field_blob->ptr -= ptrdiff; + } + offset+= blob_size; } - offset+= blob_size; } } - if (loop == 0 && offset > m_blobs_buffer_size) + if (loop == 0 && offset > buffer_size) { - my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR)); - m_blobs_buffer_size= 0; - DBUG_PRINT("value", ("allocate blobs buffer size %u", offset)); - m_blobs_buffer= my_malloc(offset, MYF(MY_WME)); - if (m_blobs_buffer == NULL) + my_free(buffer, MYF(MY_ALLOW_ZERO_PTR)); + buffer_size= 0; + DBUG_PRINT("info", ("allocate blobs buffer size %u", offset)); + buffer= my_malloc(offset, MYF(MY_WME)); + if (buffer == NULL) DBUG_RETURN(-1); - m_blobs_buffer_size= offset; + buffer_size= offset; } } DBUG_RETURN(0); @@ -2713,14 +2735,22 @@ void ndb_unpack_record(TABLE *table, NdbValue *value, else { NdbBlob *ndb_blob= (*value).blob; - bool isNull= TRUE; -#ifndef DBUG_OFF - int ret= -#endif - ndb_blob->getNull(isNull); - DBUG_ASSERT(ret == 0); - if (isNull) - field->set_null(row_offset); + int isNull; + ndb_blob->getDefined(isNull); + if (isNull != 0) + { + uint col_no = ndb_blob->getColumn()->getColumnNo(); + if (isNull == 1) + { + DBUG_PRINT("info",("[%u] NULL", col_no)) + field->set_null(row_offset); + } + else + { + DBUG_PRINT("info",("[%u] UNDEFINED", col_no)); + bitmap_clear_bit(defined, col_no); + } + } } } } @@ -4713,6 +4743,7 @@ int ha_ndbcluster::alter_table_name(const char *to) NDBDICT *dict= ndb->getDictionary(); const NDBTAB *orig_tab= (const NDBTAB *) m_table; DBUG_ENTER("alter_table_name"); + DBUG_PRINT("info", ("from: %s to: %s", orig_tab->getName(), to)); NdbDictionary::Table new_tab= *orig_tab; new_tab.setName(to); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 73b1b27ede2..a62356d41ab 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -25,6 +25,9 @@ #pragma interface /* gcc class implementation */ #endif +/* Blob tables and events are internal to NDB and must never be accessed */ +#define IS_NDB_BLOB_PREFIX(A) is_prefix(A, "NDB$BLOB") + #include #include @@ -78,6 +81,10 @@ typedef struct ndb_index_data { typedef union { const NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue; +int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, + byte*& buffer, uint& buffer_size, + my_ptrdiff_t ptrdiff); + typedef enum { NSS_INITIAL= 0, NSS_DROPPED, @@ -114,6 +121,7 @@ typedef struct st_ndbcluster_share { #ifdef HAVE_NDB_BINLOG /* NDB_SHARE.flags */ #define NSF_HIDDEN_PK 1 /* table has hidden primary key */ +#define NSF_BLOB_FLAG 2 /* table has blob attributes */ #define NSF_NO_BINLOG 4 /* table should not be binlogged */ #endif diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index f1da21a3ad5..1b3833fe443 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -23,6 +23,11 @@ #include "slave.h" #include "ha_ndbcluster_binlog.h" +#ifdef ndb_dynamite +#undef assert +#define assert(x) do { if(x) break; ::printf("%s %d: assert failed: %s\n", __FILE__, __LINE__, #x); ::fflush(stdout); ::signal(SIGABRT,SIG_DFL); ::abort(); ::kill(::getpid(),6); ::kill(::getpid(),9); } while (0) +#endif + /* defines for cluster replication table names */ @@ -237,6 +242,8 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table) DBUG_ASSERT(_table != 0); if (_table->s->primary_key == MAX_KEY) share->flags|= NSF_HIDDEN_PK; + if (_table->s->blob_fields != 0) + share->flags|= NSF_BLOB_FLAG; return; } while (1) @@ -316,6 +323,8 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table) } if (table->s->primary_key == MAX_KEY) share->flags|= NSF_HIDDEN_PK; + if (table->s->blob_fields != 0) + share->flags|= NSF_BLOB_FLAG; break; } } @@ -1622,6 +1631,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key, NDB_SHARE *share) { DBUG_ENTER("ndbcluster_create_binlog_setup"); + DBUG_ASSERT(! IS_NDB_BLOB_PREFIX(table_name)); pthread_mutex_lock(&ndbcluster_mutex); @@ -1713,6 +1723,10 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, const char *event_name, NDB_SHARE *share) { DBUG_ENTER("ndbcluster_create_event"); + DBUG_PRINT("info", ("table=%s version=%d event=%s share=%s", + ndbtab->getName(), ndbtab->getObjectVersion(), + event_name, share ? share->key : "(nil)")); + DBUG_ASSERT(! IS_NDB_BLOB_PREFIX(ndbtab->getName())); if (!share) { DBUG_PRINT("info", ("share == NULL")); @@ -1730,7 +1744,14 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, my_event.addTableEvent(NDBEVENT::TE_ALL); if (share->flags & NSF_HIDDEN_PK) { - /* No primary key, susbscribe for all attributes */ + if (share->flags & NSF_BLOB_FLAG) + { + sql_print_error("NDB Binlog: logging of table %s " + "with no PK and blob attributes is not supported", + share->key); + DBUG_RETURN(-1); + } + /* No primary key, subscribe for all attributes */ my_event.setReport(NDBEVENT::ER_ALL); DBUG_PRINT("info", ("subscription all")); } @@ -1749,6 +1770,8 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, DBUG_PRINT("info", ("subscription all and subscribe")); } } + if (share->flags & NSF_BLOB_FLAG) + my_event.mergeEvents(true); /* add all columns to the event */ int n_cols= ndbtab->getNoOfColumns(); @@ -1837,6 +1860,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, */ DBUG_ENTER("ndbcluster_create_event_ops"); + DBUG_ASSERT(! IS_NDB_BLOB_PREFIX(ndbtab->getName())); DBUG_ASSERT(share != 0); @@ -1857,22 +1881,6 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, } TABLE *table= share->table; - if (table) - { - /* - Logging of blob tables is not yet implemented, it would require: - 1. setup of events also on the blob attribute tables - 2. collect the pieces of the blob into one from an epoch to - provide a full blob to binlog - */ - if (table->s->blob_fields) - { - sql_print_error("NDB Binlog: logging of blob table %s " - "is not supported", share->key); - share->flags|= NSF_NO_BINLOG; - DBUG_RETURN(0); - } - } int do_schema_share= 0, do_apply_status_share= 0; int retries= 100; @@ -1910,37 +1918,64 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, DBUG_RETURN(-1); } + if (share->flags & NSF_BLOB_FLAG) + op->mergeEvents(true); // currently not inherited from event + + if (share->flags & NSF_BLOB_FLAG) + { + /* + * Given servers S1 S2, following results in out-of-date + * event->m_tableImpl and column->m_blobTable. + * + * S1: create table t1(a int primary key); + * S2: drop table t1; + * S1: create table t2(a int primary key, b blob); + * S1: alter table t2 add x int; + * S1: alter table t2 drop x; + * + * TODO fix at right place before we get here + */ + ndb->getDictionary()->fix_blob_events(ndbtab, event_name); + } + int n_columns= ndbtab->getNoOfColumns(); - int n_fields= table ? table->s->fields : 0; + int n_fields= table ? table->s->fields : 0; // XXX ??? for (int j= 0; j < n_columns; j++) { const char *col_name= ndbtab->getColumn(j)->getName(); - NdbRecAttr *attr0, *attr1; + NdbValue attr0, attr1; if (j < n_fields) { Field *f= share->table->field[j]; if (is_ndb_compatible_type(f)) { DBUG_PRINT("info", ("%s compatible", col_name)); - attr0= op->getValue(col_name, f->ptr); - attr1= op->getPreValue(col_name, (f->ptr-share->table->record[0]) + + attr0.rec= op->getValue(col_name, f->ptr); + attr1.rec= op->getPreValue(col_name, + (f->ptr - share->table->record[0]) + share->table->record[1]); } + else if (! (f->flags & BLOB_FLAG)) + { + DBUG_PRINT("info", ("%s non compatible", col_name)); + attr0.rec= op->getValue(col_name); + attr1.rec= op->getPreValue(col_name); + } else { - DBUG_PRINT("info", ("%s non compatible", col_name)); - attr0= op->getValue(col_name); - attr1= op->getPreValue(col_name); + DBUG_PRINT("info", ("%s blob", col_name)); + attr0.blob= op->getBlobHandle(col_name); + attr1.blob= op->getPreBlobHandle(col_name); } } else { DBUG_PRINT("info", ("%s hidden key", col_name)); - attr0= op->getValue(col_name); - attr1= op->getPreValue(col_name); + attr0.rec= op->getValue(col_name); + attr1.rec= op->getPreValue(col_name); } - share->ndb_value[0][j].rec= attr0; - share->ndb_value[1][j].rec= attr1; + share->ndb_value[0][j].ptr= attr0.ptr; + share->ndb_value[1][j].ptr= attr1.ptr; } op->setCustomData((void *) share); // set before execute share->op= op; // assign op in NDB_SHARE @@ -2229,12 +2264,27 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, (saves moving data about many times) */ + /* + for now malloc/free blobs buffer each time + TODO if possible share single permanent buffer with handlers + */ + byte* blobs_buffer[2] = { 0, 0 }; + uint blobs_buffer_size[2] = { 0, 0 }; + switch(pOp->getEventType()) { case NDBEVENT::TE_INSERT: row.n_inserts++; DBUG_PRINT("info", ("INSERT INTO %s", share->key)); { + if (share->flags & NSF_BLOB_FLAG) + { + my_ptrdiff_t ptrdiff= 0; + int ret= get_ndb_blobs_value(table, share->ndb_value[0], + blobs_buffer[0], blobs_buffer_size[0], + ptrdiff); + DBUG_ASSERT(ret == 0); + } ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]); trans.write_row(::server_id, injector::transaction::table(table, true), &b, n_fields, table->record[0]); @@ -2261,6 +2311,14 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, key */ + if (share->flags & NSF_BLOB_FLAG) + { + my_ptrdiff_t ptrdiff= table->record[n] - table->record[0]; + int ret= get_ndb_blobs_value(table, share->ndb_value[n], + blobs_buffer[n], blobs_buffer_size[n], + ptrdiff); + DBUG_ASSERT(ret == 0); + } ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]); print_records(table, table->record[n]); trans.delete_row(::server_id, injector::transaction::table(table, true), @@ -2271,13 +2329,21 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, row.n_updates++; DBUG_PRINT("info", ("UPDATE %s", share->key)); { + if (share->flags & NSF_BLOB_FLAG) + { + my_ptrdiff_t ptrdiff= 0; + int ret= get_ndb_blobs_value(table, share->ndb_value[0], + blobs_buffer[0], blobs_buffer_size[0], + ptrdiff); + DBUG_ASSERT(ret == 0); + } ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]); print_records(table, table->record[0]); if (table->s->primary_key != MAX_KEY) { /* - since table has a primary key, we can to a write + since table has a primary key, we can do a write using only after values */ trans.write_row(::server_id, injector::transaction::table(table, true), @@ -2289,6 +2355,14 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, mysql server cannot handle the ndb hidden key and therefore needs the before image as well */ + if (share->flags & NSF_BLOB_FLAG) + { + my_ptrdiff_t ptrdiff= table->record[1] - table->record[0]; + int ret= get_ndb_blobs_value(table, share->ndb_value[1], + blobs_buffer[1], blobs_buffer_size[1], + ptrdiff); + DBUG_ASSERT(ret == 0); + } ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]); print_records(table, table->record[1]); trans.update_row(::server_id, @@ -2305,6 +2379,12 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, break; } + if (share->flags & NSF_BLOB_FLAG) + { + my_free(blobs_buffer[0], MYF(MY_ALLOW_ZERO_PTR)); + my_free(blobs_buffer[1], MYF(MY_ALLOW_ZERO_PTR)); + } + return 0; } @@ -2544,6 +2624,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) Binlog_index_row row; while (pOp != NULL) { + // sometimes get TE_ALTER with invalid table + DBUG_ASSERT(pOp->getEventType() == NdbDictionary::Event::TE_ALTER || + ! IS_NDB_BLOB_PREFIX(pOp->getTable()->getName())); ndb-> setReportThreshEventGCISlip(ndb_report_thresh_binlog_epoch_slip); ndb->setReportThreshEventFreeMem(ndb_report_thresh_binlog_mem_usage); @@ -2684,6 +2767,7 @@ err: DBUG_PRINT("info",("removing all event operations")); while ((op= ndb->getEventOperation())) { + DBUG_ASSERT(! IS_NDB_BLOB_PREFIX(op->getTable()->getName())); DBUG_PRINT("info",("removing event operation on %s", op->getEvent()->getName())); NDB_SHARE *share= (NDB_SHARE*) op->getCustomData(); diff --git a/storage/ndb/include/ndbapi/NdbDictionary.hpp b/storage/ndb/include/ndbapi/NdbDictionary.hpp index dd3d06f419e..4196328976a 100644 --- a/storage/ndb/include/ndbapi/NdbDictionary.hpp +++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp @@ -883,6 +883,7 @@ public: private: #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + friend class NdbDictionaryImpl; friend class NdbTableImpl; #endif class NdbTableImpl & m_impl; @@ -1764,6 +1765,7 @@ public: #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL const Table * getTable(const char * name, void **data) const; void set_local_table_data_size(unsigned sz); + void fix_blob_events(const Table* table, const char* ev_name); #endif }; }; diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 17ca87371f4..19a86cbf557 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -1327,10 +1327,10 @@ NdbBlob::prepareColumn() assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head)); assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize); if (thePartSize > 0) { - const NdbDictionary::Table* bt = NULL; - const NdbDictionary::Column* bc = NULL; + const NdbTableImpl* bt = NULL; + const NdbColumnImpl* bc = NULL; if (theStripeSize == 0 || - (bt = theColumn->getBlobTable()) == NULL || + (bt = theColumn->m_blobTable) == NULL || (bc = bt->getColumn("DATA")) == NULL || bc->getType() != partType || bc->getLength() != (int)thePartSize) { diff --git a/storage/ndb/src/ndbapi/NdbDictionary.cpp b/storage/ndb/src/ndbapi/NdbDictionary.cpp index ac3bb235b8e..3dd73a57346 100644 --- a/storage/ndb/src/ndbapi/NdbDictionary.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp @@ -1478,6 +1478,12 @@ NdbDictionary::Dictionary::getNdbError() const { return m_impl.getNdbError(); } +void +NdbDictionary::Dictionary::fix_blob_events(const Table* table, const char* ev_name) +{ + m_impl.fix_blob_events(table, ev_name); +} + // printers NdbOut& diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 355684d218d..4f8ab972bd6 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -3398,12 +3398,14 @@ NdbDictionaryImpl::getEvent(const char * eventName) if (ev->m_tableId == info->m_table_impl->m_id && ev->m_tableVersion == info->m_table_impl->m_version) break; + DBUG_PRINT("error",("%s: retry=%d: " + "table version mismatch, event: [%u,%u] table: [%u,%u]", + ev->getTableName(), retry, + ev->m_tableId, ev->m_tableVersion, + info->m_table_impl->m_id, info->m_table_impl->m_version)); if (retry) { m_error.code= 241; - DBUG_PRINT("error",("%s: table version mismatch, event: [%u,%u] table: [%u,%u]", - ev->getTableName(), ev->m_tableId, ev->m_tableVersion, - info->m_table_impl->m_id, info->m_table_impl->m_version)); delete ev; DBUG_RETURN(NULL); } @@ -3607,7 +3609,7 @@ NdbDictionaryImpl::dropEvent(const char * eventName) if (m_error.code != 723 && // no such table m_error.code != 241) // invalid table DBUG_RETURN(-1); - DBUG_PRINT("info", ("no table, drop by name alone")); + DBUG_PRINT("info", ("no table err=%d, drop by name alone", m_error.code)); evnt = new NdbEventImpl(); evnt->setName(eventName); } @@ -3644,7 +3646,17 @@ NdbDictionaryImpl::dropBlobEvents(const NdbEventImpl& evnt) (void)dropEvent(bename); } } else { - // could loop over MAX_ATTRIBUTES_IN_TABLE ... + // loop over MAX_ATTRIBUTES_IN_TABLE ... + Uint32 i; + for (i = 0; i < MAX_ATTRIBUTES_IN_TABLE; i++) { + char bename[MAX_TAB_NAME_SIZE]; + // XXX should get name from NdbBlob + sprintf(bename, "NDB$BLOBEVENT_%s_%u", evnt.getName(), i); + NdbEventImpl* bevnt = new NdbEventImpl(); + bevnt->setName(bename); + (void)m_receiver.dropEvent(*bevnt); + delete bevnt; + } } DBUG_RETURN(0); } @@ -4631,6 +4643,30 @@ NdbDictInterface::parseFileInfo(NdbFileImpl &dst, return 0; } +// XXX temp +void +NdbDictionaryImpl::fix_blob_events(const NdbDictionary::Table* table, const char* ev_name) +{ + const NdbTableImpl& t = table->m_impl; + const NdbEventImpl* ev = getEvent(ev_name); + assert(ev != NULL && ev->m_tableImpl == &t); + Uint32 i; + for (i = 0; i < t.m_columns.size(); i++) { + assert(t.m_columns[i] != NULL); + const NdbColumnImpl& c = *t.m_columns[i]; + if (! c.getBlobType() || c.getPartSize() == 0) + continue; + char bename[200]; + NdbBlob::getBlobEventName(bename, ev, &c); + // following fixes dict cache blob table + NdbEventImpl* bev = getEvent(bename); + if (c.m_blobTable != bev->m_tableImpl) { + // XXX const violation + ((NdbColumnImpl*)&c)->m_blobTable = bev->m_tableImpl; + } + } +} + template class Vector; template class Vector; template class Vector; diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 22fa13a4c71..bd59fc8cc5b 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -592,6 +592,9 @@ public: NdbDictInterface m_receiver; Ndb & m_ndb; + + // XXX temp + void fix_blob_events(const NdbDictionary::Table* table, const char* ev_name); private: NdbIndexImpl * getIndexImpl(const char * name, const BaseString& internalName); From 58de75fae8bcfebea7549fa3eb909ca6fe8cb090 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 22:49:31 +0100 Subject: [PATCH 12/15] add myself to checkout:get (should be default for all) BitKeeper/etc/config: why is this not default? --- BitKeeper/etc/config | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index b68810b77ac..6d06edd193e 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -74,5 +74,6 @@ hours: [jonas:]checkout:get [tomas:]checkout:get [guilhem:]checkout:get +[pekka:]checkout:get checkout:edit eoln:unix From 456524c0608c0fdbf61c585b2bd5dea57e861ef2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 19:54:42 -0800 Subject: [PATCH 13/15] Rename of my_strdup_with_lenght to match the more common "strndup" method. Soo its now my_strndup(). my_stat() gettinng the correct parameter list may be next :) client/mysqlslap.c: rename extra/comp_err.c: rename include/my_sys.h: replace mysys/mf_tempdir.c: replace mysys/my_malloc.c: replace mysys/safemalloc.c: replace sql/ha_federated.cc: replace sql/log_event.cc: replace sql/set_var.cc: replace sql/set_var.h: replace storage/myisam/ft_stopwords.c: replace --- client/mysqlslap.c | 4 ++-- extra/comp_err.c | 6 +++--- include/my_sys.h | 6 +++--- mysys/mf_tempdir.c | 2 +- mysys/my_malloc.c | 2 +- mysys/safemalloc.c | 2 +- sql/ha_federated.cc | 2 +- sql/log_event.cc | 4 ++-- sql/set_var.cc | 2 +- sql/set_var.h | 2 +- storage/myisam/ft_stopwords.c | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/client/mysqlslap.c b/client/mysqlslap.c index c993b93e608..be034da0c8c 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1184,7 +1184,7 @@ parse_delimiter(const char *script, statement **stmt, char delm) tmp= tmp->next) { count++; - tmp->string= my_strdup_with_length(ptr, (size_t)(retstr - ptr), MYF(MY_FAE)); + tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE)); tmp->length= (size_t)(retstr - ptr); DBUG_PRINT("info", (" Creating : %.*s\n", (uint)tmp->length, tmp->string)); ptr+= retstr - ptr + 1; @@ -1195,7 +1195,7 @@ parse_delimiter(const char *script, statement **stmt, char delm) if (ptr != script+length) { - tmp->string= my_strdup_with_length(ptr, (size_t)((script + length) - ptr), + tmp->string= my_strndup(ptr, (size_t)((script + length) - ptr), MYF(MY_FAE)); tmp->length= (size_t)((script + length) - ptr); DBUG_PRINT("info", (" Creating : %.*s\n", (uint)tmp->length, tmp->string)); diff --git a/extra/comp_err.c b/extra/comp_err.c index 65fc131a5fc..2d685a04087 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -638,7 +638,7 @@ static char *get_word(char **str) DBUG_ENTER("get_word"); *str= find_end_of_word(start); - DBUG_RETURN(my_strdup_with_length(start, (uint) (*str - start), + DBUG_RETURN(my_strndup(start, (uint) (*str - start), MYF(MY_WME | MY_FAE))); } @@ -672,7 +672,7 @@ static struct message *parse_message_string(struct message *new_message, while (*str != ' ' && *str != '\t' && *str) str++; if (!(new_message->lang_short_name= - my_strdup_with_length(start, (uint) (str - start), + my_strndup(start, (uint) (str - start), MYF(MY_WME | MY_FAE)))) DBUG_RETURN(0); /* Fatal error */ DBUG_PRINT("info", ("msg_slang: %s", new_message->lang_short_name)); @@ -692,7 +692,7 @@ static struct message *parse_message_string(struct message *new_message, start= str + 1; str= parse_text_line(start); - if (!(new_message->text= my_strdup_with_length(start, (uint) (str - start), + if (!(new_message->text= my_strndup(start, (uint) (str - start), MYF(MY_WME | MY_FAE)))) DBUG_RETURN(0); /* Fatal error */ DBUG_PRINT("info", ("msg_text: %s", new_message->text)); diff --git a/include/my_sys.h b/include/my_sys.h index 89b0bd4fbec..00c42fc5935 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -136,7 +136,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define my_free(PTR,FLAG) _myfree((PTR), __FILE__, __LINE__,FLAG) #define my_memdup(A,B,C) _my_memdup((A),(B), __FILE__,__LINE__,C) #define my_strdup(A,C) _my_strdup((A), __FILE__,__LINE__,C) -#define my_strdup_with_length(A,B,C) _my_strdup_with_length((A),(B),__FILE__,__LINE__,C) +#define my_strndup(A,B,C) _my_strndup((A),(B),__FILE__,__LINE__,C) #define TRASH(A,B) bfill(A, B, 0x8F) #define QUICK_SAFEMALLOC sf_malloc_quick=1 #define NORMAL_SAFEMALLOC sf_malloc_quick=0 @@ -158,7 +158,7 @@ extern gptr my_realloc(gptr oldpoint,uint Size,myf MyFlags); extern void my_no_flags_free(gptr ptr); extern gptr my_memdup(const byte *from,uint length,myf MyFlags); extern char *my_strdup(const char *from,myf MyFlags); -extern char *my_strdup_with_length(const byte *from, uint length, +extern char *my_strndup(const byte *from, uint length, myf MyFlags); /* we do use FG (as a no-op) in below so that a typo on FG is caught */ #define my_free(PTR,FG) ((void)FG,my_no_flags_free(PTR)) @@ -597,7 +597,7 @@ extern gptr _my_memdup(const byte *from,uint length, const char *sFile, uint uLine,myf MyFlag); extern my_string _my_strdup(const char *from, const char *sFile, uint uLine, myf MyFlag); -extern char *_my_strdup_with_length(const byte *from, uint length, +extern char *_my_strndup(const byte *from, uint length, const char *sFile, uint uLine, myf MyFlag); diff --git a/mysys/mf_tempdir.c b/mysys/mf_tempdir.c index 0a3d41efdc5..e79980ab931 100644 --- a/mysys/mf_tempdir.c +++ b/mysys/mf_tempdir.c @@ -53,7 +53,7 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) end=strcend(pathlist, DELIM); strmake(buff, pathlist, (uint) (end-pathlist)); length= cleanup_dirname(buff, buff); - if (!(copy= my_strdup_with_length(buff, length, MYF(MY_WME))) || + if (!(copy= my_strndup(buff, length, MYF(MY_WME))) || insert_dynamic(&t_arr, (gptr) ©)) DBUG_RETURN(TRUE); pathlist=end+1; diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c index 3f601a42dc9..3fb3866f79c 100644 --- a/mysys/my_malloc.c +++ b/mysys/my_malloc.c @@ -83,7 +83,7 @@ char *my_strdup(const char *from, myf my_flags) } -char *my_strdup_with_length(const byte *from, uint length, myf my_flags) +char *my_strndup(const byte *from, uint length, myf my_flags) { gptr ptr; if ((ptr=my_malloc(length+1,my_flags)) != 0) diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index 6cdf98c5f5f..e40fd751037 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -525,7 +525,7 @@ char *_my_strdup(const char *from, const char *filename, uint lineno, } /* _my_strdup */ -char *_my_strdup_with_length(const byte *from, uint length, +char *_my_strndup(const byte *from, uint length, const char *filename, uint lineno, myf MyFlags) { diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 0dbbf8e1175..af8dfb9a111 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -647,7 +647,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, DBUG_PRINT("info", ("Length: %d", table->s->connect_string.length)); DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length, table->s->connect_string.str)); - share->scheme= my_strdup_with_length((const byte*)table->s-> + share->scheme= my_strndup((const byte*)table->s-> connect_string.str, table->s->connect_string.length, MYF(0)); diff --git a/sql/log_event.cc b/sql/log_event.cc index f63c454b5ed..15eb4c3aaf0 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3138,7 +3138,7 @@ Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg, llstr(pos_arg, buff), flags)); #endif if (flags & DUP_NAME) - new_log_ident= my_strdup_with_length((const byte*) new_log_ident_arg, + new_log_ident= my_strndup((const byte*) new_log_ident_arg, ident_len, MYF(MY_WME)); DBUG_VOID_RETURN; } @@ -3162,7 +3162,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, (header_size+post_header_len)); ident_offset = post_header_len; set_if_smaller(ident_len,FN_REFLEN-1); - new_log_ident= my_strdup_with_length((byte*) buf + ident_offset, + new_log_ident= my_strndup((byte*) buf + ident_offset, (uint) ident_len, MYF(MY_WME)); DBUG_VOID_RETURN; diff --git a/sql/set_var.cc b/sql/set_var.cc index 1385155c3b3..b85b2576b83 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1021,7 +1021,7 @@ bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex, uint new_length= (var ? var->value->str_value.length() : 0); if (!old_value) old_value= (char*) ""; - if (!(res= my_strdup_with_length((byte*)old_value, new_length, MYF(0)))) + if (!(res= my_strndup((byte*)old_value, new_length, MYF(0)))) return 1; /* Replace the old value in such a way that the any thread using diff --git a/sql/set_var.h b/sql/set_var.h index 01705d5ff4d..34873947483 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -926,7 +926,7 @@ public: uint name_length_arg, gptr data_arg) :name_length(name_length_arg), data(data_arg) { - name= my_strdup_with_length((byte*) name_arg, name_length, MYF(MY_WME)); + name= my_strndup((byte*) name_arg, name_length, MYF(MY_WME)); links->push_back(this); } inline bool cmp(const char *name_cmp, uint length) diff --git a/storage/myisam/ft_stopwords.c b/storage/myisam/ft_stopwords.c index ab51afb0e82..3b5a1752ff7 100644 --- a/storage/myisam/ft_stopwords.c +++ b/storage/myisam/ft_stopwords.c @@ -83,7 +83,7 @@ int ft_init_stopwords() end=start+len; while (ft_simple_get_word(default_charset_info, &start, end, &w, TRUE)) { - if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0)))) + if (ft_add_stopword(my_strndup(w.pos, w.len, MYF(0)))) goto err1; } error=0; From 375afff3bd9d427921c81c3f190789b96c9c83ee Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jan 2006 21:54:43 -0600 Subject: [PATCH 14/15] fixed test issues with bug #14354. I had mistakenly included /var/tmp in my path when testing data diretory. the var directory exists in a src tree but may not exist in a different testing build setup. mysql-test/r/partition_mgm_err.result: added a row insert just to make sure the data and index files are made mysql-test/t/partition_mgm_err.test: removed the /var/tmp path elements since there is not guarantee that other build setups will include this path --- mysql-test/r/partition_mgm_err.result | 2 ++ mysql-test/t/partition_mgm_err.test | 15 ++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/partition_mgm_err.result b/mysql-test/r/partition_mgm_err.result index 38a69e93536..4129a1e61d8 100644 --- a/mysql-test/r/partition_mgm_err.result +++ b/mysql-test/r/partition_mgm_err.result @@ -112,6 +112,8 @@ ALTER TABLE t1 DROP PARTITION x1; ALTER TABLE t1 DROP PARTITION x0; ERROR HY000: Cannot remove all partitions, use DROP TABLE instead DROP TABLE t1; +INSERT INTO t1 VALUES (15); +DROP TABLE t1; CREATE TABLE t1 ( id INT NOT NULL, fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL, diff --git a/mysql-test/t/partition_mgm_err.test b/mysql-test/t/partition_mgm_err.test index cbecac96afb..793968c87f3 100644 --- a/mysql-test/t/partition_mgm_err.test +++ b/mysql-test/t/partition_mgm_err.test @@ -171,18 +171,19 @@ DROP TABLE t1; # # BUG: 14354 Partitions: data directory clause fails # ---exec rm -rf $MYSQL_TEST_DIR/var/tmp/bug14354 ---exec mkdir $MYSQL_TEST_DIR/var/tmp/bug14354 +--exec rm -rf $MYSQL_TEST_DIR/bug14354 +--exec mkdir $MYSQL_TEST_DIR/bug14354 disable_query_log; eval CREATE TABLE t1 (id int) PARTITION BY RANGE(id) ( PARTITION p1 VALUES LESS THAN (20) ENGINE=myiasm -DATA DIRECTORY="$MYSQL_TEST_DIR/var/tmp/bug14354" -INDEX DIRECTORY="$MYSQL_TEST_DIR/var/tmp/bug14354"); +DATA DIRECTORY="$MYSQL_TEST_DIR/bug14354" +INDEX DIRECTORY="$MYSQL_TEST_DIR/bug14354"); enable_query_log; ---exec test -f $MYSQL_TEST_DIR/var/tmp/bug14354/t1_p1.MYD ---exec test -f $MYSQL_TEST_DIR/var/tmp/bug14354/t1_p1.MYI +INSERT INTO t1 VALUES (15); +--exec test -f $MYSQL_TEST_DIR/bug14354/t1#P#p1.MYD +--exec test -f $MYSQL_TEST_DIR/bug14354/t1#P#p1.MYI DROP TABLE t1; ---exec rm -rf $MYSQL_TEST_DIR/var/tmp/bug14354 +--exec rm -rf $MYSQL_TEST_DIR/bug14354 # # Bug# 16534 - Trying to add multiple partitions crashes server From 77f51bf11a0a5cc7ad6bc9d1628d13a268dd1d4f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 26 Jan 2006 11:14:20 +0100 Subject: [PATCH 15/15] Bug #16152, create event assertion in debug version, list corruption --- .../include/kernel/signaldata/UtilExecute.hpp | 5 ++--- .../debugger/signaldata/UtilExecute.cpp | 8 ++++---- .../ndb/src/kernel/blocks/dbutil/DbUtil.cpp | 19 +++++-------------- .../ndb/src/kernel/blocks/dbutil/DbUtil.hpp | 1 - 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/storage/ndb/include/kernel/signaldata/UtilExecute.hpp b/storage/ndb/include/kernel/signaldata/UtilExecute.hpp index 551fb172cac..d74057e78d6 100644 --- a/storage/ndb/include/kernel/signaldata/UtilExecute.hpp +++ b/storage/ndb/include/kernel/signaldata/UtilExecute.hpp @@ -49,9 +49,9 @@ public: GET_SET_SENDERREF GET_SET_SENDERDATA void setPrepareId(Uint32 pId) { prepareId = pId; }; // !! unsets release flag - Uint32 getPrepareId() { return prepareId & 0xFF; }; + Uint32 getPrepareId() const { return prepareId & 0xFF; }; void setReleaseFlag() { prepareId |= 0x100; }; - bool getReleaseFlag() { return (prepareId & 0x100) != 0; }; + bool getReleaseFlag() const { return (prepareId & 0x100) != 0; }; private: Uint32 senderData; // MUST be no 1! Uint32 senderRef; @@ -117,7 +117,6 @@ public: IllegalKeyNumber = 1, IllegalAttrNumber = 2, TCError = 3, - IllegalPrepareId = 4, AllocationError = 5, MissingDataSection = 6, MissingData = 7 diff --git a/storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp b/storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp index 2c88fa174d4..0c774942977 100644 --- a/storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp +++ b/storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp @@ -20,10 +20,12 @@ bool printUTIL_EXECUTE_REQ(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) { const UtilExecuteReq* const sig = (UtilExecuteReq*)data; - fprintf(out, " senderRef: H'%.8x, senderData: H'%.8x prepareId: %d\n", + fprintf(out, " senderRef: H'%.8x, senderData: H'%.8x prepareId: %d " + " releaseFlag: %d\n", sig->senderRef, sig->senderData, - sig->prepareId); + sig->getPrepareId(), + sig->getReleaseFlag()); return true; } @@ -48,8 +50,6 @@ printUTIL_EXECUTE_REF(FILE* out, const Uint32 * data, Uint32 len, Uint16 rec) "IllegalAttrNumber" : sig->errorCode == UtilExecuteRef::TCError ? "TCError" : - sig->errorCode == UtilExecuteRef::IllegalPrepareId ? - "IllegalPrepareId" : sig->errorCode == UtilExecuteRef::AllocationError ? "AllocationError" : "Unknown"); diff --git a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp index 6401ac35820..8e3e2452a23 100644 --- a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp +++ b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp @@ -52,7 +52,6 @@ DbUtil::DbUtil(const Configuration & conf) : SimulatedBlock(DBUTIL, conf), c_runningPrepares(c_preparePool), - c_runningPreparedOperations(c_preparedOperationPool), c_seizingTransactions(c_transactionPool), c_runningTransactions(c_transactionPool), c_lockQueues(c_lockQueuePool) @@ -566,12 +565,13 @@ DbUtil::execDUMP_STATE_ORD(Signal* signal){ } ndbout << "PreparedOperation Id: " << signal->theData[2] << endl; PreparedOperationPtr prepOpPtr; - c_runningPreparedOperations.getPtr(prepOpPtr, signal->theData[2]); + c_preparedOperationPool.getPtr(prepOpPtr, signal->theData[2]); prepOpPtr.p->print(); return; } // ** Print all records ** +#if 0 // not implemented PreparedOperationPtr prepOpPtr; if (!c_runningPreparedOperations.first(prepOpPtr)) { ndbout << "No PreparedOperations exist" << endl; @@ -583,6 +583,7 @@ DbUtil::execDUMP_STATE_ORD(Signal* signal){ ndbout << "]"; c_runningPreparedOperations.next(prepOpPtr); } +#endif return; case 3: @@ -988,7 +989,7 @@ DbUtil::prepareOperation(Signal* signal, PreparePtr prepPtr) * Seize and store PreparedOperation struct *******************************************/ PreparedOperationPtr prepOpPtr; - if(!c_runningPreparedOperations.seize(prepOpPtr)) { + if(!c_preparedOperationPool.seize(prepOpPtr)) { jam(); releaseSections(signal); sendUtilPrepareRef(signal, UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR, @@ -1738,17 +1739,7 @@ DbUtil::execUTIL_EXECUTE_REQ(Signal* signal) * Get PreparedOperation struct *******************************/ PreparedOperationPtr prepOpPtr; - c_runningPreparedOperations.first(prepOpPtr); - while (!prepOpPtr.isNull() && prepOpPtr.i != prepareId) - c_runningPreparedOperations.next(prepOpPtr); - - if (prepOpPtr.i != prepareId) { - jam(); - releaseSections(signal); - sendUtilExecuteRef(signal, UtilExecuteRef::IllegalPrepareId, - 0, clientRef, clientData); - return; - } + c_preparedOperationPool.getPtr(prepOpPtr, prepareId); prepOpPtr.p->releaseFlag = releaseFlag; diff --git a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp index 983dd4402a4..2d0fa250c2e 100644 --- a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp +++ b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp @@ -389,7 +389,6 @@ public: DataBuffer<1>::DataBufferPool c_attrMappingPool; DataBuffer<11>::DataBufferPool c_dataBufPool; DLList c_runningPrepares; - DLList c_runningPreparedOperations; DLList c_seizingTransactions; // Being seized at TC DLList c_runningTransactions; // Seized and now exec.