diff options
author | unknown <stewart@willster.(none)> | 2006-10-05 18:51:13 +1000 |
---|---|---|
committer | unknown <stewart@willster.(none)> | 2006-10-05 18:51:13 +1000 |
commit | db16cae578dd32ee2e66d8746444613c34b1e3e8 (patch) | |
tree | b95cd7b958b532ad93aa61c6d5a0e2408297c383 /ndb | |
parent | 81526834b5c4f3c1672bcfc3759592798d68b72e (diff) | |
download | mariadb-git-db16cae578dd32ee2e66d8746444613c34b1e3e8.tar.gz |
BUG#13987 Cluster: Loss of data nodes can cause high CPU usage from ndb_mgmd
smaller patch for 5.0.
complete patch going to 5.1 due to more intrusiveness for 'list sessions' etc
ndb/include/mgmapi/mgmapi.h:
add internal get_fd to use in test
ndb/include/util/InputStream.hpp:
- add this weird startover member to SocketInputStream
- this helps work out if we've read a newline yet and should start inserting
into buffer from the start
ndb/src/common/util/InputStream.cpp:
remove evil, add more.
keep track internally we've retrieved a newline yet (m_startover)
ndb/src/common/util/Parser.cpp:
change way detecting of NoLine
remove some trailing whitespace that was uglying the place up a bit
ndb/src/common/util/socket_io.cpp:
Always retrieve data from the OS so that we instantly get EOF on disconnect
and don't end up spinning looking for a newline.
ndb/src/mgmapi/mgmapi.cpp:
add internal ndb_mgm_get_fd() for internal testing
handle 'node status' a bit better
ndb/test/ndbapi/testMgm.cpp:
Add test for MgmApiSession disconnection (mgmd at 100%)
not fully automated due to smaller patch for 5.0
will be complete in 5.1
Diffstat (limited to 'ndb')
-rw-r--r-- | ndb/include/mgmapi/mgmapi.h | 13 | ||||
-rw-r--r-- | ndb/include/util/InputStream.hpp | 1 | ||||
-rw-r--r-- | ndb/src/common/util/InputStream.cpp | 39 | ||||
-rw-r--r-- | ndb/src/common/util/Parser.cpp | 35 | ||||
-rw-r--r-- | ndb/src/common/util/socket_io.cpp | 28 | ||||
-rw-r--r-- | ndb/src/mgmapi/mgmapi.cpp | 26 | ||||
-rw-r--r-- | ndb/test/ndbapi/testMgm.cpp | 27 |
7 files changed, 114 insertions, 55 deletions
diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 4e015cc3d7e..0cc9b2b9e78 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -1072,6 +1072,19 @@ extern "C" { int ndb_mgm_end_session(NdbMgmHandle handle); /** + * ndb_mgm_get_fd + * + * get the file descriptor of the handle. + * INTERNAL ONLY. + * USE FOR TESTING. OTHER USES ARE NOT A GOOD IDEA. + * + * @param handle NDB management handle + * @return handle->socket + * + */ + int ndb_mgm_get_fd(NdbMgmHandle handle); + + /** * Get the node id of the mgm server we're connected to */ Uint32 ndb_mgm_get_mgmd_nodeid(NdbMgmHandle handle); diff --git a/ndb/include/util/InputStream.hpp b/ndb/include/util/InputStream.hpp index b2a56b1e433..4d7d06aeaa3 100644 --- a/ndb/include/util/InputStream.hpp +++ b/ndb/include/util/InputStream.hpp @@ -40,6 +40,7 @@ extern FileInputStream Stdin; class SocketInputStream : public InputStream { NDB_SOCKET_TYPE m_socket; unsigned m_timeout; + bool m_startover; public: SocketInputStream(NDB_SOCKET_TYPE socket, unsigned readTimeout = 1000); char* gets(char * buf, int bufLen); diff --git a/ndb/src/common/util/InputStream.cpp b/ndb/src/common/util/InputStream.cpp index 410e9a70e9c..1b0e809a047 100644 --- a/ndb/src/common/util/InputStream.cpp +++ b/ndb/src/common/util/InputStream.cpp @@ -36,26 +36,35 @@ FileInputStream::gets(char * buf, int bufLen){ SocketInputStream::SocketInputStream(NDB_SOCKET_TYPE socket, unsigned readTimeout) - : m_socket(socket) { - m_timeout = readTimeout; + : m_socket(socket) { + m_startover= true; + m_timeout = readTimeout; } -char* +char* SocketInputStream::gets(char * buf, int bufLen) { - buf[0] = 77; assert(bufLen >= 2); - int res = readln_socket(m_socket, m_timeout, buf, bufLen - 1); + int offset= 0; + if(m_startover) + { + buf[0]= '\0'; + m_startover= false; + } + else + offset= strlen(buf); + + int res = readln_socket(m_socket, m_timeout, buf+offset, bufLen-offset); + + if(res == 0) + { + buf[0]=0; + return buf; + } + + m_startover= true; + if(res == -1) return 0; - if(res == 0 && buf[0] == 77){ // select return 0 - buf[0] = 0; - } else if(res == 0 && buf[0] == 0){ // only newline - buf[0] = '\n'; - buf[1] = 0; - } else { - int len = strlen(buf); - buf[len + 1] = '\0'; - buf[len] = '\n'; - } + return buf; } diff --git a/ndb/src/common/util/Parser.cpp b/ndb/src/common/util/Parser.cpp index 3a86ae8f318..392c3e83825 100644 --- a/ndb/src/common/util/Parser.cpp +++ b/ndb/src/common/util/Parser.cpp @@ -148,21 +148,26 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, bool ownStop = false; if(stop == 0) stop = &ownStop; - + ctx->m_aliasUsed.clear(); - + const unsigned sz = sizeof(ctx->m_tokenBuffer); ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); if(Eof(ctx->m_currentToken)){ ctx->m_status = Parser<Dummy>::Eof; DBUG_RETURN(false); } - - if(ctx->m_currentToken[0] == 0){ + + int last= strlen(ctx->m_currentToken); + if(last>0) + last--; + + if(ctx->m_currentToken[last] !='\n'){ ctx->m_status = Parser<Dummy>::NoLine; + ctx->m_tokenBuffer[0]= '\0'; DBUG_RETURN(false); } - + if(Empty(ctx->m_currentToken)){ ctx->m_status = Parser<Dummy>::EmptyLine; DBUG_RETURN(false); @@ -174,14 +179,14 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, ctx->m_status = Parser<Dummy>::UnknownCommand; DBUG_RETURN(false); } - + Properties * p = new Properties(); - + bool invalidArgument = false; ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); - - while((! * stop) && - !Eof(ctx->m_currentToken) && + + while((! * stop) && + !Eof(ctx->m_currentToken) && !Empty(ctx->m_currentToken)){ if(ctx->m_currentToken[0] != 0){ trim(ctx->m_currentToken); @@ -193,7 +198,7 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, } ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); } - + if(invalidArgument){ char buf[sz]; char * tmp; @@ -204,13 +209,13 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, } DBUG_RETURN(false); } - + if(* stop){ delete p; ctx->m_status = Parser<Dummy>::ExternalStop; DBUG_RETURN(false); } - + if(!checkMandatory(ctx, p)){ ctx->m_status = Parser<Dummy>::MissingMandatoryArgument; delete p; @@ -226,9 +231,9 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, tmp.put("name", alias->name); tmp.put("realName", alias->realName); p->put("$ALIAS", i, &tmp); - } + } p->put("$ALIAS", ctx->m_aliasUsed.size()); - + ctx->m_status = Parser<Dummy>::Ok; * pDst = p; DBUG_RETURN(true); diff --git a/ndb/src/common/util/socket_io.cpp b/ndb/src/common/util/socket_io.cpp index 58636e6663d..ba2794e4374 100644 --- a/ndb/src/common/util/socket_io.cpp +++ b/ndb/src/common/util/socket_io.cpp @@ -75,7 +75,6 @@ readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, return -1; } - buf[0] = 0; const int t = recv(socket, buf, buflen, MSG_PEEK); if(t < 1) @@ -87,27 +86,28 @@ readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, for(int i=0; i< t;i++) { if(buf[i] == '\n'){ - recv(socket, buf, i+1, 0); - buf[i] = 0; + int r= recv(socket, buf, i+1, 0); + buf[i+1]= 0; + if(r < 1) { + fcntl(socket, F_SETFL, sock_flags); + return -1; + } if(i > 0 && buf[i-1] == '\r'){ - i--; - buf[i] = 0; + buf[i-1] = '\n'; + buf[i]= '\0'; } fcntl(socket, F_SETFL, sock_flags); - return t; + return r; } } - if(t == (buflen - 1)){ - recv(socket, buf, t, 0); - buf[t] = 0; - fcntl(socket, F_SETFL, sock_flags); - return buflen; - } - - return 0; + int r= recv(socket, buf, t, 0); + if(r>=0) + buf[r] = 0; + fcntl(socket, F_SETFL, sock_flags); + return r; } extern "C" diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 9bf19dda3a4..12222f25eb8 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -503,6 +503,18 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, } /** + * Only used for low level testing + * Never to be used by end user. + * Or anybody who doesn't know exactly what they're doing. + */ +extern "C" +int +ndb_mgm_get_fd(NdbMgmHandle handle) +{ + return handle->socket; +} + +/** * Disconnect from a mgm server */ extern "C" @@ -692,22 +704,16 @@ ndb_mgm_get_status(NdbMgmHandle handle) SET_ERROR(handle, NDB_MGM_ILLEGAL_SERVER_REPLY, "Probably disconnected"); return NULL; } - if(buf[strlen(buf)-1] == '\n') - buf[strlen(buf)-1] = '\0'; - - if(strcmp("node status", buf) != 0) { + if(strcmp("node status\n", buf) != 0) { SET_ERROR(handle, NDB_MGM_ILLEGAL_NODE_STATUS, buf); return NULL; } - if(!in.gets(buf, sizeof(buf))) { SET_ERROR(handle, NDB_MGM_ILLEGAL_SERVER_REPLY, "Probably disconnected"); return NULL; } - if(buf[strlen(buf)-1] == '\n') - buf[strlen(buf)-1] = '\0'; - + BaseString tmp(buf); Vector<BaseString> split; tmp.split(split, ":"); @@ -715,7 +721,7 @@ ndb_mgm_get_status(NdbMgmHandle handle) SET_ERROR(handle, NDB_MGM_ILLEGAL_NODE_STATUS, buf); return NULL; } - + if(!(split[0].trim() == "nodes")){ SET_ERROR(handle, NDB_MGM_ILLEGAL_NODE_STATUS, buf); return NULL; @@ -2280,7 +2286,6 @@ ndb_mgm_check_connection(NdbMgmHandle handle){ SocketOutputStream out(handle->socket); SocketInputStream in(handle->socket, handle->read_timeout); char buf[32]; - if (out.println("check connection")) goto ndb_mgm_check_connection_error; @@ -2490,7 +2495,6 @@ int ndb_mgm_end_session(NdbMgmHandle handle) SocketInputStream in(handle->socket, handle->read_timeout); char buf[32]; - in.gets(buf, sizeof(buf)); DBUG_RETURN(0); diff --git a/ndb/test/ndbapi/testMgm.cpp b/ndb/test/ndbapi/testMgm.cpp index ef653d3f972..3234117405c 100644 --- a/ndb/test/ndbapi/testMgm.cpp +++ b/ndb/test/ndbapi/testMgm.cpp @@ -21,6 +21,8 @@ #include <NdbRestarter.hpp> #include <Vector.hpp> #include <random.h> +#include <mgmapi.h> +#include <mgmapi_debug.h> int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ @@ -167,6 +169,26 @@ int runTestSingleUserMode(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runTestApiSession(NDBT_Context* ctx, NDBT_Step* step) +{ + char *mgm= ctx->getRemoteMgm(); + + NdbMgmHandle h; + h= ndb_mgm_create_handle(); + ndb_mgm_set_connectstring(h, mgm); + ndb_mgm_connect(h,0,0,0); + int s= ndb_mgm_get_fd(h); + write(s,"get",3); + ndb_mgm_disconnect(h); + ndb_mgm_destroy_handle(&h); + /** NOTE: WE CANNOT REALLY TEST ANYTHING in 5.0 + * + * a more conservative patch for 5.0, full get and list + * sessions in 5.1. + * + * This is kept so that we can at least manually test easily + */ +} NDBT_TESTSUITE(testMgm); @@ -175,6 +197,11 @@ TESTCASE("SingleUserMode", INITIALIZER(runTestSingleUserMode); FINALIZER(runClearTable); } +TESTCASE("ApiSessionFailure", + "Test failures in MGMAPI session"){ + INITIALIZER(runTestApiSession); + +} NDBT_TESTSUITE_END(testMgm); int main(int argc, const char** argv){ |