diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_34541.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_34541.result new file mode 100644 index 00000000000..acc1528efc4 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_34541.result @@ -0,0 +1,35 @@ +for master_1 +for child2 +for child3 +SET SESSION spider_same_server_link=1; +SET sql_mode=''; +set @old_table_open_cache=@@global.table_open_cache; +set global table_open_cache=10; +set spider_same_server_link= 1; +CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); +CREATE TABLE t1 (c INT) ENGINE=InnoDB; +CREATE TABLE t2 (c INT) ENGINE=InnoDB; +CREATE TABLE t3 (c INT) ENGINE=InnoDB; +CREATE TABLE ta (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t5 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t6 (c INT KEY) ENGINE=InnoDB PARTITION BY RANGE (c) (PARTITION p VALUES LESS THAN (5)); +CREATE TABLE t7 (a INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t8 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +SELECT * FROM t8; +ERROR HY000: Remote table 'test.t' is not found +CREATE TEMPORARY TABLE t7 (c INT) ENGINE=InnoDB SELECT * FROM t7; +ERROR HY000: Remote table 'test.t' is not found +CALL foo; +ERROR 42000: PROCEDURE test.foo does not exist +CREATE TEMPORARY TABLE t7 (c INT) ENGINE=InnoDB; +SELECT * FROM t7 JOIN t6 ON tc=t0.c; +ERROR 42S22: Unknown column 'tc' in 'on clause' +SHOW TABLE STATUS; +drop table ta, t8, t7, t6, t5, t3, t2, t1; +drop table t7; +drop server srv; +set global table_open_cache=@old_table_open_cache; +for master_1 +for child2 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_34555.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_34555.result new file mode 100644 index 00000000000..5e464ea77bb --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_34555.result @@ -0,0 +1,32 @@ +for master_1 +for child2 +for child3 +set spider_same_server_link= 1; +CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE '',user 'Spider', password 'foo'); +CREATE TABLE tSpider (a INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t2 (c INT,c2 CHAR(1)) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +XA START 'a'; +SELECT * FROM information_schema.table_constraints; +SELECT SLEEP (1); +SLEEP (1) +0 +SELECT * FROM t2; +ERROR HY000: Unable to connect to foreign data source: srv +SELECT SLEEP (1); +SLEEP (1) +0 +SELECT * FROM t2; +ERROR HY000: Unable to connect to foreign data source: srv +SELECT SLEEP (1); +SLEEP (1) +0 +SELECT * FROM t2; +ERROR HY000: Unable to connect to foreign data source: srv +xa end 'a'; +xa rollback 'a'; +drop table tSpider, t2; +drop server srv; +for master_1 +for child2 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_34541.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_34541.test new file mode 100644 index 00000000000..8a36eb58f10 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_34541.test @@ -0,0 +1,48 @@ +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +SET SESSION spider_same_server_link=1; +SET sql_mode=''; + +set @old_table_open_cache=@@global.table_open_cache; +set global table_open_cache=10; + +set spider_same_server_link= 1; +evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); + +CREATE TABLE t1 (c INT) ENGINE=InnoDB; +CREATE TABLE t2 (c INT) ENGINE=InnoDB; +CREATE TABLE t3 (c INT) ENGINE=InnoDB; +CREATE TABLE ta (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t5 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t6 (c INT KEY) ENGINE=InnoDB PARTITION BY RANGE (c) (PARTITION p VALUES LESS THAN (5)); +CREATE TABLE t7 (a INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t8 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +--error 12702 +SELECT * FROM t8; +--error 12702 +CREATE TEMPORARY TABLE t7 (c INT) ENGINE=InnoDB SELECT * FROM t7; +--error ER_SP_DOES_NOT_EXIST +CALL foo; +CREATE TEMPORARY TABLE t7 (c INT) ENGINE=InnoDB; +--error ER_BAD_FIELD_ERROR +SELECT * FROM t7 JOIN t6 ON tc=t0.c; +--disable_result_log +SHOW TABLE STATUS; +--enable_result_log + +# we need to drop t7 twice +drop table ta, t8, t7, t6, t5, t3, t2, t1; +drop table t7; +drop server srv; +set global table_open_cache=@old_table_open_cache; + +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_34555.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_34555.test new file mode 100644 index 00000000000..3a1cf604140 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_34555.test @@ -0,0 +1,33 @@ +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log +set spider_same_server_link= 1; +evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE '',user 'Spider', password 'foo'); +CREATE TABLE tSpider (a INT) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +CREATE TABLE t2 (c INT,c2 CHAR(1)) ENGINE=Spider COMMENT='WRAPPER "mysql",SRV "srv",TABLE "t"'; +XA START 'a'; +--disable_result_log +--error 0,ER_CONNECT_TO_FOREIGN_DATA_SOURCE +SELECT * FROM information_schema.table_constraints; +--enable_result_log +SELECT SLEEP (1); +--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE +SELECT * FROM t2; +SELECT SLEEP (1); +--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE +SELECT * FROM t2; +SELECT SLEEP (1); +--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE +SELECT * FROM t2; +xa end 'a'; +xa rollback 'a'; +drop table tSpider, t2; +drop server srv; +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/spd_conn.cc b/storage/spider/spd_conn.cc index 453e0aaf709..0ebd6d7d0cd 100644 --- a/storage/spider/spd_conn.cc +++ b/storage/spider/spd_conn.cc @@ -1151,27 +1151,41 @@ void spider_conn_queue_UTC_time_zone( DBUG_VOID_RETURN; } +/* + Construct merged values and insert into the loop check queue + + Search the loop_check_queue for the data node table, and if one does + not exist, construct the merged value in the same format as the + right hand side. Otherwise, merge the right hand side of the + existing SPIDER_CONN_LOOP_CHECK with the right hand side of lcptr + into one right hand side. In either case, add the + SPIDER_CONN_LOOP_CHECK to the loop check queue +*/ int spider_conn_queue_and_merge_loop_check( SPIDER_CONN *conn, SPIDER_CONN_LOOP_CHECK *lcptr ) { int error_num = HA_ERR_OUT_OF_MEM; - char *tmp_name, *from_name, *cur_name, *to_name, *full_name, *from_value, + char *tmp_name, *cur_name, *to_name, *full_name, *from_value, *merged_value; SPIDER_CONN_LOOP_CHECK *lcqptr, *lcrptr; DBUG_ENTER("spider_conn_queue_and_merge_loop_check"); DBUG_PRINT("info", ("spider conn=%p", conn)); #ifdef SPIDER_HAS_HASH_VALUE_TYPE - if (unlikely(!(lcqptr = (SPIDER_CONN_LOOP_CHECK *) + if (!(lcqptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_search_using_hash_value(&conn->loop_check_queue, lcptr->hash_value_to, - (uchar *) lcptr->to_name.str, lcptr->to_name.length)))) + (uchar *) lcptr->to_name.str, lcptr->to_name.length))) #else if (unlikely(!(lcqptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_search( &conn->loop_check_queue, (uchar *) lcptr->to_name.str, lcptr->to_name.length)))) #endif { + /* + Construct the right hand side: + ---- + */ DBUG_PRINT("info", ("spider create merged_value and insert")); lcptr->merged_value.length = spider_unique_id.length + lcptr->cur_name.length + lcptr->from_value.length + 1; @@ -1194,10 +1208,10 @@ int spider_conn_queue_and_merge_loop_check( } lcptr->flag |= SPIDER_LOP_CHK_QUEUED; } else { + /* Merge lcptr and lcqptr into a newly created lcrptr. */ DBUG_PRINT("info", ("spider append merged_value and replace")); if (unlikely(!spider_bulk_malloc(spider_current_trx, 271, MYF(MY_WME), &lcrptr, (uint) (sizeof(SPIDER_CONN_LOOP_CHECK)), - &from_name, (uint) (lcqptr->from_name.length + 1), &cur_name, (uint) (lcqptr->cur_name.length + 1), &to_name, (uint) (lcqptr->to_name.length + 1), &full_name, (uint) (lcqptr->full_name.length + 1), @@ -1209,13 +1223,13 @@ int spider_conn_queue_and_merge_loop_check( )) { goto error_alloc_loop_check_replace; } + /* + TODO: the new lcrptr has the same cur_name, to_name, full_name + and from_value as lcqptr, but they do not seem to be relevant. + */ #ifdef SPIDER_HAS_HASH_VALUE_TYPE lcrptr->hash_value_to = lcqptr->hash_value_to; - lcrptr->hash_value_full = lcqptr->hash_value_full; #endif - lcrptr->from_name.str = from_name; - lcrptr->from_name.length = lcqptr->from_name.length; - memcpy(from_name, lcqptr->from_name.str, lcqptr->from_name.length + 1); lcrptr->cur_name.str = cur_name; lcrptr->cur_name.length = lcqptr->cur_name.length; memcpy(cur_name, lcqptr->cur_name.str, lcqptr->cur_name.length + 1); @@ -1228,8 +1242,14 @@ int spider_conn_queue_and_merge_loop_check( lcrptr->from_value.str = from_value; lcrptr->from_value.length = lcqptr->from_value.length; memcpy(from_value, lcqptr->from_value.str, lcqptr->from_value.length + 1); + /* + The merged_value of lcrptr is a concatenation of that of lcqptr + and constructed merged_value from lcptr. + */ lcrptr->merged_value.str = merged_value; - lcrptr->merged_value.length = lcqptr->merged_value.length; + lcrptr->merged_value.length = + lcqptr->merged_value.length + spider_unique_id.length + + lcptr->cur_name.length + 1 + lcptr->from_value.length; memcpy(merged_value, lcqptr->merged_value.str, lcqptr->merged_value.length); merged_value += lcqptr->merged_value.length; @@ -1273,9 +1293,6 @@ int spider_conn_queue_and_merge_loop_check( goto error_hash_insert_queue; } lcptr->flag = SPIDER_LOP_CHK_MERAGED; - lcptr->next = NULL; - if (!conn->loop_check_meraged_first) - conn->loop_check_meraged_first = lcptr; } DBUG_RETURN(0); @@ -1296,7 +1313,6 @@ error_hash_insert: int spider_conn_reset_queue_loop_check( SPIDER_CONN *conn ) { - int error_num; SPIDER_CONN_LOOP_CHECK *lcptr; DBUG_ENTER("spider_conn_reset_queue_loop_check"); uint l = 0; @@ -1318,30 +1334,8 @@ int spider_conn_reset_queue_loop_check( ++l; } - lcptr = conn->loop_check_ignored_first; - while (lcptr) - { - lcptr->flag = 0; - if ((error_num = spider_conn_queue_and_merge_loop_check(conn, lcptr))) - { - goto error_queue_and_merge; - } - lcptr = lcptr->next; - } - conn->loop_check_meraged_first = NULL; pthread_mutex_unlock(&conn->loop_check_mutex); DBUG_RETURN(0); - -error_queue_and_merge: - lcptr = lcptr->next; - while (lcptr) - { - lcptr->flag = 0; - lcptr = lcptr->next; - } - conn->loop_check_meraged_first = NULL; - pthread_mutex_unlock(&conn->loop_check_mutex); - DBUG_RETURN(error_num); } int spider_conn_queue_loop_check( @@ -1352,7 +1346,7 @@ int spider_conn_queue_loop_check( int error_num = HA_ERR_OUT_OF_MEM; uint conn_link_idx = spider->conn_link_idx[link_idx], buf_sz; char path[FN_REFLEN + 1]; - char *tmp_name, *from_name, *cur_name, *to_name, *full_name, *from_value, + char *tmp_name, *cur_name, *to_name, *full_name, *from_value, *merged_value; user_var_entry *loop_check; char *loop_check_buf; @@ -1363,6 +1357,17 @@ int spider_conn_queue_loop_check( LEX_CSTRING lex_str, from_str, to_str; DBUG_ENTER("spider_conn_queue_loop_check"); DBUG_PRINT("info", ("spider conn=%p", conn)); + /* + construct loop check user var name (left hand side) into + lex_str. It is of the format + + spider_lc_ + + So if the spider table name is ./test/t1, then the constructed + user var name is: + + spider_lc_./test/t1 + */ lex_str.length = top_share->path.length + SPIDER_SQL_LOP_CHK_PRM_PRF_LEN; buf_sz = lex_str.length + 2; loop_check_buf = (char *) my_alloca(buf_sz); @@ -1388,6 +1393,16 @@ int spider_conn_queue_loop_check( } else { lex_str.str = loop_check->value; lex_str.length = loop_check->length; + /* + Validate that there are at least four dashes in the user var + value: ---- + + Note: if the value is merged from multiple values, such as + + "------------" + + then only the first component is put into from_str + */ DBUG_PRINT("info", ("spider from_str=%s", lex_str.str)); if (unlikely(!(tmp_name = strchr(loop_check->value, '-')))) { @@ -1415,12 +1430,23 @@ int spider_conn_queue_loop_check( } else { + /* + Validation passed. Put the first component of rhs in from_str + */ from_str.str = lex_str.str; from_str.length = tmp_name - lex_str.str + 1; } } my_afree(loop_check_buf); + /* + construct loop_check_buf as -- e.g. + "---./test/t0--./test/t1-./test/t2", later used as + full_name + from_str is the first component in the user var value (RHS) or + empty if user var value is empty, cur is the spider table, to_str + is the remote data node table + */ to_str.length = build_table_filename(path, FN_REFLEN, share->tgt_dbs[conn_link_idx] ? share->tgt_dbs[conn_link_idx] : "", share->tgt_table_names[conn_link_idx], "", 0); @@ -1457,7 +1483,7 @@ int spider_conn_queue_loop_check( lcptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_search( &conn->loop_checked, (uchar *) loop_check_buf, buf_sz - 1); #endif - if (unlikely( + if ( !lcptr || ( !lcptr->flag && @@ -1466,7 +1492,7 @@ int spider_conn_queue_loop_check( memcmp(lcptr->from_value.str, lex_str.str, lex_str.length) ) ) - )) + ) { if (unlikely(lcptr)) { @@ -1482,7 +1508,6 @@ int spider_conn_queue_loop_check( DBUG_PRINT("info", ("spider alloc_lcptr")); if (unlikely(!spider_bulk_malloc(spider_current_trx, 272, MYF(MY_WME), &lcptr, (uint) (sizeof(SPIDER_CONN_LOOP_CHECK)), - &from_name, (uint) (from_str.length + 1), &cur_name, (uint) (top_share->path.length + 1), &to_name, (uint) (to_str.length + 1), &full_name, (uint) (buf_sz), @@ -1495,9 +1520,6 @@ int spider_conn_queue_loop_check( goto error_alloc_loop_check; } lcptr->flag = 0; - lcptr->from_name.str = from_name; - lcptr->from_name.length = from_str.length; - memcpy(from_name, from_str.str, from_str.length + 1); lcptr->cur_name.str = cur_name; lcptr->cur_name.length = top_share->path.length; memcpy(cur_name, top_share->path.str, top_share->path.length + 1); @@ -1510,12 +1532,19 @@ int spider_conn_queue_loop_check( lcptr->from_value.str = from_value; lcptr->from_value.length = lex_str.length; memcpy(from_value, lex_str.str, lex_str.length + 1); + /* + merged_value will only be populated later, in + spider_conn_queue_and_merge_loop_check() + */ lcptr->merged_value.str = merged_value; #ifdef SPIDER_HAS_HASH_VALUE_TYPE - lcptr->hash_value_to = my_calc_hash(&conn->loop_checked, + lcptr->hash_value_to = my_calc_hash(&conn->loop_check_queue, (uchar *) to_str.str, to_str.length); - lcptr->hash_value_full = hash_value; #endif + /* + Mark as checked. It will be added to loop_check_queue in + spider_conn_queue_and_merge_loop_check() below for checking + */ #ifdef HASH_UPDATE_WITH_HASH_VALUE if (unlikely(my_hash_insert_with_hash_value(&conn->loop_checked, lcptr->hash_value_full, (uchar *) lcptr))) @@ -1527,19 +1556,11 @@ int spider_conn_queue_loop_check( goto error_hash_insert; } } else { + /* Already marked as checked, ignore and return. */ if (!lcptr->flag) { DBUG_PRINT("info", ("spider add to ignored list")); lcptr->flag |= SPIDER_LOP_CHK_IGNORED; - lcptr->next = NULL; - if (!conn->loop_check_ignored_first) - { - conn->loop_check_ignored_first = lcptr; - conn->loop_check_ignored_last = lcptr; - } else { - conn->loop_check_ignored_last->next = lcptr; - conn->loop_check_ignored_last = lcptr; - } } pthread_mutex_unlock(&conn->loop_check_mutex); my_afree(loop_check_buf); diff --git a/storage/spider/spd_conn.h b/storage/spider/spd_conn.h index 92da278eecc..c9eeb9d66d4 100644 --- a/storage/spider/spd_conn.h +++ b/storage/spider/spd_conn.h @@ -26,24 +26,62 @@ #define SPIDER_SIMPLE_CHECKSUM_TABLE 4 #endif +/* + The SPIDER_CONN_LOOP_CHECK has been added to the loop_check queue to + check for self-reference. +*/ #define SPIDER_LOP_CHK_QUEUED (1 << 0) +/* + The SPIDER_CONN_LOOP_CHECK is a merge of multiple + SPIDER_CONN_LOOP_CHECKs with the same data node table +*/ #define SPIDER_LOP_CHK_MERAGED (1 << 1) +/* + The SPIDER_CONN_LOOP_CHECK has been ignored because it has already + been marked as checked +*/ #define SPIDER_LOP_CHK_IGNORED (1 << 2) +/* Used for self-reference check. */ typedef struct st_spider_conn_loop_check { + /* + Could be 0, SPIDER_LOP_CHK_QUEUED, SPIDER_LOP_CHK_MERAGED, or + SPIDER_LOP_CHK_IGNORED + */ uint flag; #ifdef SPIDER_HAS_HASH_VALUE_TYPE + /* hash value of to_name, used for the hash conn->loop_checked */ my_hash_value_type hash_value_to; - my_hash_value_type hash_value_full; #endif - LEX_CSTRING from_name; + /* + The fully qualified name of the current spider table, which will + also be used to construct the user var name to set in the data + node + */ LEX_CSTRING cur_name; + /* + The fully qualified data node table name, also used as key in + conn->loop_check_queue + */ LEX_CSTRING to_name; + /* + A concatenation of from_value, cur_name and to_name, used as key + in hash conn->loop_checked + */ LEX_CSTRING full_name; + /* + The first component of the uservar value on the current server, + consisting of information of a table that uses the current spider + table as a data node + */ LEX_CSTRING from_value; + /* + The uservar value to set in the data node, a concatenation of info + of tables, mac addresses and process ids of tables that use the + current spider table as the data node + */ LEX_CSTRING merged_value; - st_spider_conn_loop_check *next; } SPIDER_CONN_LOOP_CHECK; uchar *spider_conn_get_key( diff --git a/storage/spider/spd_db_include.cc b/storage/spider/spd_db_include.cc index e8ee365ba5d..4a422e0e1f2 100644 --- a/storage/spider/spd_db_include.cc +++ b/storage/spider/spd_db_include.cc @@ -66,7 +66,7 @@ spider_db_conn::spider_db_conn( DBUG_VOID_RETURN; } -int spider_db_conn::fin_loop_check() +int spider_db_conn::fin_loop_check() /* reset flags of all relevant SPIDER_CONN_LOOP_CHECKs */ { st_spider_conn_loop_check *lcptr; DBUG_ENTER("spider_db_conn::fin_loop_check"); @@ -82,20 +82,6 @@ int spider_db_conn::fin_loop_check() } my_hash_reset(&conn->loop_check_queue); } - lcptr = conn->loop_check_ignored_first; - while (lcptr) - { - lcptr->flag = 0; - lcptr = lcptr->next; - } - conn->loop_check_ignored_first = NULL; - lcptr = conn->loop_check_meraged_first; - while (lcptr) - { - lcptr->flag = 0; - lcptr = lcptr->next; - } - conn->loop_check_meraged_first = NULL; DBUG_RETURN(0); } diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index 232a2b02c25..7ea91073cf2 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -5283,6 +5283,22 @@ int spider_db_mbase_util::append_time_zone( DBUG_RETURN(0); } +/* + iterate over loop_check_queue and build queries for loop check + + The query is in the form of + + set @`spider_lc_.` = + '--------...' + + where from_table1, from_table2 etc. are spider tables whose direct + or indirect remote data nodes contain to_table. + + e.g. if t0->t1->t2, then the query could be: + + set @`spider_lc_./test/t2` = + '-234567890abc-def012-./test/t1--1234567890ab-cdef01-./test/t0-' + */ int spider_db_mbase_util::append_loop_check( spider_string *str, SPIDER_CONN *conn diff --git a/storage/spider/spd_include.h b/storage/spider/spd_include.h index 6b9e2998144..1d190ec2348 100644 --- a/storage/spider/spd_include.h +++ b/storage/spider/spd_include.h @@ -793,19 +793,24 @@ typedef struct st_spider_conn SPIDER_IP_PORT_CONN *ip_port_conn; pthread_mutex_t loop_check_mutex; + /* + A hash of SPIDER_CONN_LOOP_CHECK, indexed by + SPIDER_CONN_LOOP_CHECK::full_name + */ HASH loop_checked; uint loop_checked_id; const char *loop_checked_func_name; const char *loop_checked_file_name; ulong loop_checked_line_no; + /* + A hash of SPIDER_CONN_LOOP_CHECK, indexed by + SPIDER_CONN_LOOP_CHECK::to_name + */ HASH loop_check_queue; uint loop_check_queue_id; const char *loop_check_queue_func_name; const char *loop_check_queue_file_name; ulong loop_check_queue_line_no; - SPIDER_CONN_LOOP_CHECK *loop_check_ignored_first; - SPIDER_CONN_LOOP_CHECK *loop_check_ignored_last; - SPIDER_CONN_LOOP_CHECK *loop_check_meraged_first; } SPIDER_CONN; typedef struct st_spider_lgtm_tblhnd_share