From 4984af30ecbe62ab5d4bbb60a1820bad689a5372 Mon Sep 17 00:00:00 2001 From: "stewart@willster.(none)" <> Date: Tue, 23 Jan 2007 17:07:09 +1100 Subject: [PATCH 1/3] Bug #25487 deleting ndb_cluster_connection object takes long time aim is to: a) if set_connect_timeout called, timeout connect attempt (for retry on next call) after timeout period b) preserve existing blocking behaviour otherwise (for, e.g. mgmapi) Related to customer issue with long time deleting ndb_cluster_connection object. believe we're hanging on the connect(2) call until timeout (when we then realise we should exit the thread). --- ndb/include/mgmapi/mgmapi.h | 10 ++++ ndb/include/util/SocketClient.hpp | 4 ++ ndb/src/common/transporter/Transporter.cpp | 8 ++- ndb/src/common/util/SocketClient.cpp | 60 ++++++++++++++++++++-- ndb/src/mgmapi/mgmapi.cpp | 13 +++++ 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 2010aa8cc33..2423048f98f 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -540,6 +540,16 @@ extern "C" { */ const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz); + /** + * Sets the number of seconds to wait for connect(2) during ndb_mgm_connect + * Default is no timeout + * + * @param handle NdbMgmHandle + * @param seconds number of seconds + * @return non-zero on success + */ + int ndb_mgm_set_connect_timeout(NdbMgmHandle handle, unsigned int seconds); + /** * Connects to a management server. Connectstring is set by * ndb_mgm_set_connectstring(). diff --git a/ndb/include/util/SocketClient.hpp b/ndb/include/util/SocketClient.hpp index e1f1752e9a8..bb8d9b9ac41 100644 --- a/ndb/include/util/SocketClient.hpp +++ b/ndb/include/util/SocketClient.hpp @@ -23,6 +23,7 @@ class SocketClient { NDB_SOCKET_TYPE m_sockfd; struct sockaddr_in m_servaddr; + unsigned int m_connect_timeout_sec; unsigned short m_port; char *m_server_name; SocketAuthenticator *m_auth; @@ -34,6 +35,9 @@ public: m_port = port; m_servaddr.sin_port = htons(m_port); }; + void set_connect_timeout(unsigned int s) { + m_connect_timeout_sec= s; + } unsigned short get_port() { return m_port; }; char *get_server_name() { return m_server_name; }; int bind(const char* toaddress, unsigned short toport); diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp index 339533c8d27..d1e88e303e7 100644 --- a/ndb/src/common/transporter/Transporter.cpp +++ b/ndb/src/common/transporter/Transporter.cpp @@ -79,9 +79,13 @@ Transporter::Transporter(TransporterRegistry &t_reg, if (isServer) m_socket_client= 0; else + { m_socket_client= new SocketClient(remoteHostName, s_port, new SocketAuthSimple("ndbd", "ndbd passwd")); + + m_socket_client->set_connect_timeout(m_timeOutMillis/1000); + } DBUG_VOID_RETURN; } @@ -140,9 +144,9 @@ Transporter::connect_client() { } sockfd= m_socket_client->connect(); } - + return connect_client(sockfd); -} +} bool Transporter::connect_client(NDB_SOCKET_TYPE sockfd) { diff --git a/ndb/src/common/util/SocketClient.cpp b/ndb/src/common/util/SocketClient.cpp index bb059585863..ec35fd3eb90 100644 --- a/ndb/src/common/util/SocketClient.cpp +++ b/ndb/src/common/util/SocketClient.cpp @@ -26,6 +26,7 @@ SocketClient::SocketClient(const char *server_name, unsigned short port, SocketA m_port= port; m_server_name= server_name ? strdup(server_name) : 0; m_sockfd= NDB_INVALID_SOCKET; + m_connect_timeout_sec= 0; } SocketClient::~SocketClient() @@ -58,7 +59,7 @@ SocketClient::init() if (m_sockfd == NDB_INVALID_SOCKET) { return false; } - + DBUG_PRINT("info",("NDB_SOCKET: %d", m_sockfd)); return true; @@ -104,6 +105,13 @@ SocketClient::bind(const char* bindaddress, unsigned short localport) NDB_SOCKET_TYPE SocketClient::connect(const char *toaddress, unsigned short toport) { + fd_set rset, wset; + struct timeval tval; + int r; + bool use_timeout; + socklen_t len; + int flags; + if (m_sockfd == NDB_INVALID_SOCKET) { if (!init()) { @@ -127,14 +135,58 @@ SocketClient::connect(const char *toaddress, unsigned short toport) if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name)) return NDB_INVALID_SOCKET; } - - const int r = ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr)); - if (r == -1) { + + flags= fcntl(m_sockfd, F_GETFL, 0); + fcntl(m_sockfd, F_SETFL, flags | O_NONBLOCK); + + r= ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr)); + + if (r == 0) + goto done; // connected immediately. + + if (r < 0 && (errno != EINPROGRESS)) { NDB_CLOSE_SOCKET(m_sockfd); m_sockfd= NDB_INVALID_SOCKET; return NDB_INVALID_SOCKET; } + FD_ZERO(&rset); + FD_SET(m_sockfd, &rset); + wset= rset; + tval.tv_sec= m_connect_timeout_sec; + tval.tv_usec= 0; + use_timeout= m_connect_timeout_sec; + + if ((r= select(m_sockfd+1, &rset, &wset, NULL, + use_timeout? &tval : NULL)) == 0) + { + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return NDB_INVALID_SOCKET; + } + + if (FD_ISSET(m_sockfd, &rset) || FD_ISSET(m_sockfd, &wset)) + { + len= sizeof(r); + if (getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &r, &len) < 0) + { + // Solaris got an error... different than others + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return NDB_INVALID_SOCKET; + } + } + else + { + // select error, probably m_sockfd not set. + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return NDB_INVALID_SOCKET; + } + +done: + fcntl(m_sockfd, F_SETFL, flags); + if (m_auth) { if (!m_auth->client_authenticate(m_sockfd)) { diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 2f49efd9f58..fa7aed8b182 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -93,6 +93,7 @@ struct ndb_mgm_handle { char last_error_desc[NDB_MGM_MAX_ERR_DESC_SIZE]; int read_timeout; int write_timeout; + unsigned int connect_timeout; NDB_SOCKET_TYPE socket; @@ -159,6 +160,7 @@ ndb_mgm_create_handle() h->socket = NDB_INVALID_SOCKET; h->read_timeout = 50000; h->write_timeout = 100; + h->connect_timeout = 0; h->cfg_i = -1; h->errstream = stdout; h->m_name = 0; @@ -426,6 +428,16 @@ int ndb_mgm_is_connected(NdbMgmHandle handle) return handle->connected; } +extern "C" +int ndb_mgm_set_connect_timeout(NdbMgmHandle handle, unsigned int seconds) +{ + if(!handle) + return -1; + + handle->connect_timeout= seconds; + return 0; +} + /** * Connect to a management server */ @@ -456,6 +468,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, Uint32 i; int binderror = 0; SocketClient s(0, 0); + s.set_connect_timeout(handle->connect_timeout); if (!s.init()) { fprintf(handle->errstream, From 5b886fa35848d1dc875d0d34d9a286a6514f0c9e Mon Sep 17 00:00:00 2001 From: "stewart@willster.(none)" <> Date: Tue, 23 Jan 2007 17:19:27 +1100 Subject: [PATCH 2/3] round up Transporter connect timeout --- ndb/src/common/transporter/Transporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp index d1e88e303e7..20b6be8ce26 100644 --- a/ndb/src/common/transporter/Transporter.cpp +++ b/ndb/src/common/transporter/Transporter.cpp @@ -84,7 +84,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, new SocketAuthSimple("ndbd", "ndbd passwd")); - m_socket_client->set_connect_timeout(m_timeOutMillis/1000); + m_socket_client->set_connect_timeout((m_timeOutMillis+999)/1000); } DBUG_VOID_RETURN; } From adf40be13bd993cf118484c4f8d52e0ba5348b21 Mon Sep 17 00:00:00 2001 From: "stewart@willster.(none)" <> Date: Wed, 24 Jan 2007 00:27:19 +1100 Subject: [PATCH 3/3] Bug#25567 records() call performs scan in NDB, performance bug --- mysql-test/r/ndb_basic.result | 12 ++++++------ sql/ha_ndbcluster.h | 2 ++ sql/sql_select.cc | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index ec7f8186c49..b4a55641e80 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -757,12 +757,12 @@ PRIMARY KEY (b,c)) ENGINE=ndbcluster; INSERT INTO t1 VALUES ("a","ab","abc"),("b","abc","abcd"),("c","abc","ab"),("d","ab","ab"),("e","abc","abc"); SELECT * FROM t1 ORDER BY a; -a b c -a ab abc -b abc abcd -c abc ab -d ab ab -e abc abc +a b c +a ab abc +b abc abcd +c abc ab +d ab ab +e abc abc DROP TABLE t1; End of 5.0 tests CREATE TABLE t1 (a VARCHAR(255) NOT NULL, diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 50f24c7a4cf..5b6900766b6 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -676,6 +676,8 @@ class ha_ndbcluster: public handler bool get_error_message(int error, String *buf); ha_rows records(); + ha_rows estimate_rows_upper_bound() + { return HA_POS_ERROR; } int info(uint); void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id); int extra(enum ha_extra_function operation); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7715575d65b..919024ba457 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2197,7 +2197,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, s->key_dependent= 0; if (tables->schema_table) table->file->stats.records= 2; - table->quick_condition_rows= table->file->records(); + table->quick_condition_rows= table->file->stats.records; s->on_expr_ref= &tables->on_expr; if (*s->on_expr_ref)