@@ -131,6 +131,9 @@ static int cdb2_comdb2db_timeout_set_from_env = 0;
131131static int CDB2_API_CALL_TIMEOUT = 120000 ; /* defaults to 2 minute */
132132static int cdb2_api_call_timeout_set_from_env = 0 ;
133133
134+ static int CDB2_ENFORCE_API_CALL_TIMEOUT = 0 ;
135+ static int cdb2_enforce_api_call_timeout_set_from_env = 0 ;
136+
134137static int CDB2_SOCKET_TIMEOUT = 5000 ;
135138static int cdb2_socket_timeout_set_from_env = 0 ;
136139
@@ -856,6 +859,37 @@ static int is_sql_read(const char *sqlstr)
856859#define HAVE_MSGHDR_MSG_CONTROL
857860#endif
858861
862+ static int is_api_call_timedout (cdb2_hndl_tp * hndl ) {
863+ struct timeval tv ;
864+ gettimeofday (& tv , NULL );
865+ long long current_time = tv .tv_sec * 1000 + tv .tv_usec /1000 ;
866+ if (hndl -> max_call_time && (hndl -> max_call_time < current_time )) {
867+ return 1 ;
868+ }
869+ return 0 ;
870+ }
871+
872+ static long long get_call_timeout (const cdb2_hndl_tp * hndl , long long timeout ) {
873+ if (!hndl )
874+ return timeout ;
875+ struct timeval tv ;
876+ gettimeofday (& tv , NULL );
877+ long long current_time = tv .tv_sec * 1000 + tv .tv_usec /1000 ;
878+ long long time_left = hndl -> max_call_time - current_time ;
879+ if (hndl -> max_call_time && time_left <= 0 )
880+ time_left = 1 ;
881+ if (time_left > 0 && (time_left < timeout ))
882+ return time_left ;
883+ return timeout ;
884+ }
885+
886+ static void set_max_call_time (cdb2_hndl_tp * hndl ) {
887+ struct timeval tv ;
888+ gettimeofday (& tv , NULL );
889+ if (hndl )
890+ hndl -> max_call_time = tv .tv_sec * 1000 + tv .tv_usec /1000 + hndl -> api_call_timeout ;
891+ }
892+
859893enum {
860894 PASSFD_SUCCESS = 0 ,
861895 PASSFD_RECVMSG = -1 , /* error with recvmsg() */
@@ -995,8 +1029,7 @@ static int recv_fd_int(int sockfd, void *data, size_t nbytes, int *fd_recvd, int
9951029static int recv_fd (const cdb2_hndl_tp * hndl , int sockfd , void * data , size_t nbytes , int * fd_recvd )
9961030{
9971031 int rc , timeoutms = hndl ? hndl -> sockpool_recv_timeoutms : CDB2_SOCKPOOL_RECV_TIMEOUTMS ;
998- if (hndl && hndl -> api_call_timeout && (timeoutms > hndl -> api_call_timeout ))
999- timeoutms = hndl -> api_call_timeout ;
1032+ timeoutms = get_call_timeout (hndl , timeoutms );
10001033 rc = recv_fd_int (sockfd , data , nbytes , fd_recvd , timeoutms );
10011034 if (rc != 0 && * fd_recvd != -1 ) {
10021035 int errno_save = errno ;
@@ -1116,8 +1149,7 @@ static int send_fd_to(int sockfd, const void *data, size_t nbytes,
11161149static int send_fd (const cdb2_hndl_tp * hndl , int sockfd , const void * data , size_t nbytes , int fd_to_send )
11171150{
11181151 int timeoutms = hndl ? hndl -> sockpool_send_timeoutms : CDB2_SOCKPOOL_SEND_TIMEOUTMS ;
1119- if (hndl && hndl -> api_call_timeout && (timeoutms > hndl -> api_call_timeout ))
1120- timeoutms = hndl -> api_call_timeout ;
1152+ timeoutms = get_call_timeout (hndl , timeoutms );
11211153 return send_fd_to (sockfd , data , nbytes , fd_to_send , timeoutms );
11221154}
11231155
@@ -1591,6 +1623,8 @@ static void read_comdb2db_environment_cfg(cdb2_hndl_tp *hndl, const char *comdb2
15911623 & cdb2_sockpool_recv_timeoutms_set_from_env );
15921624 process_env_var_int ("COMDB2_CONFIG_API_CALL_TIMEOUT" , & CDB2_API_CALL_TIMEOUT ,
15931625 & cdb2_api_call_timeout_set_from_env );
1626+ process_env_var_int ("COMDB2_CONFIG_ENFORCE_API_CALL_TIMEOUT" , & CDB2_ENFORCE_API_CALL_TIMEOUT ,
1627+ & cdb2_enforce_api_call_timeout_set_from_env );
15941628 process_env_var_int ("COMDB2_CONFIG_COMDB2DB_TIMEOUT" , & COMDB2DB_TIMEOUT , & cdb2_comdb2db_timeout_set_from_env );
15951629 process_env_var_int ("COMDB2_CONFIG_SOCKET_TIMEOUT" , & CDB2_SOCKET_TIMEOUT , & cdb2_socket_timeout_set_from_env );
15961630 process_env_var_int ("COMDB2_CONFIG_PROTOBUF_SIZE" , & CDB2_PROTOBUF_SIZE , & cdb2_protobuf_size_set_from_env );
@@ -1841,6 +1875,9 @@ static void read_comdb2db_cfg(cdb2_hndl_tp *hndl, SBUF2 *s, const char *comdb2db
18411875 hndl -> api_call_timeout = atoi (tok );
18421876 else if (tok )
18431877 CDB2_API_CALL_TIMEOUT = atoi (tok );
1878+ } else if (!cdb2_api_call_timeout_set_from_env && (strcasecmp ("enforce_api_call_timeout" ,tok ) == 0 )) {
1879+ tok = strtok_r (NULL , " :," , & last );
1880+ CDB2_ENFORCE_API_CALL_TIMEOUT = value_on_off (tok , & err );
18441881 } else if (strcasecmp ("auto_consume_timeout" , tok ) == 0 ) {
18451882 tok = strtok_r (NULL , " :," , & last );
18461883 if (tok )
@@ -2125,6 +2162,8 @@ static void set_cdb2_timeouts(cdb2_hndl_tp *hndl)
21252162 hndl -> comdb2db_timeout = hndl -> api_call_timeout ;
21262163 if (hndl -> socket_timeout > hndl -> api_call_timeout )
21272164 hndl -> socket_timeout = hndl -> api_call_timeout ;
2165+
2166+ set_max_call_time (hndl );
21282167}
21292168
21302169/* Read all available comdb2 configuration files.
@@ -3688,8 +3727,22 @@ static int cdb2portmux_get(cdb2_hndl_tp *hndl, const char *type,
36883727
36893728 debugprint ("name %s\n" , name );
36903729
3730+ int connect_timeout = hndl -> connect_timeout ;
3731+
3732+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3733+ # ifdef CDB2API_TEST
3734+ printf ("RETRY with timeout %d\n" , get_call_timeout (hndl , connect_timeout ));
3735+ # endif
3736+ if (is_api_call_timedout (hndl )) {
3737+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out connecting to db\n" , __func__ , __LINE__ );
3738+ port = -1 ;
3739+ goto after_callback ;
3740+ }
3741+ connect_timeout = get_call_timeout (hndl , connect_timeout );
3742+ }
3743+
36913744 fd = cdb2_tcpconnecth_to (hndl , remote_host , CDB2_PORTMUXPORT , 0 ,
3692- hndl -> connect_timeout );
3745+ connect_timeout );
36933746 if (fd < 0 ) {
36943747 debugprint ("cdb2_tcpconnecth_to returns fd=%d'\n" , fd );
36953748 if (errno == EINPROGRESS ) {
@@ -3715,7 +3768,18 @@ static int cdb2portmux_get(cdb2_hndl_tp *hndl, const char *type,
37153768 port = -1 ;
37163769 goto after_callback ;
37173770 }
3718- sbuf2settimeout (ss , hndl -> connect_timeout , hndl -> connect_timeout );
3771+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3772+ # ifdef CDB2API_TEST
3773+ printf ("RETRY with timeout %d\n" , get_call_timeout (hndl , connect_timeout ));
3774+ # endif
3775+ if (is_api_call_timedout (hndl )) {
3776+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out connecting to db\n" , __func__ , __LINE__ );
3777+ port = -1 ;
3778+ goto after_callback ;
3779+ }
3780+ connect_timeout = get_call_timeout (hndl , connect_timeout );
3781+ }
3782+ sbuf2settimeout (ss , connect_timeout , connect_timeout );
37193783 sbuf2printf (ss , "get %s\n" , name );
37203784 sbuf2flush (ss );
37213785 res [0 ] = 0 ;
@@ -3904,6 +3968,17 @@ static int cdb2_read_record(cdb2_hndl_tp *hndl, uint8_t **buf, int *len, int *ty
39043968 goto after_callback ;
39053969
39063970retry :
3971+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3972+ int socket_timeout = get_call_timeout (hndl , hndl -> socket_timeout );
3973+ # ifdef CDB2API_TEST
3974+ printf ("GOT HEARTBEAT || Set timeout to %d\n" , socket_timeout );
3975+ # endif
3976+ if (is_api_call_timedout (hndl )) {
3977+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out reading response from the db\n" , __func__ , __LINE__ );
3978+ rc = -1 ;
3979+ }
3980+ sbuf2settimeout (sb , socket_timeout , socket_timeout );
3981+ }
39073982 b_read = sbuf2fread ((char * )& hdr , 1 , sizeof (hdr ), sb );
39083983 debugprint ("READ HDR b_read=%d, sizeof(hdr)=(%zu):\n" , b_read , sizeof (hdr ));
39093984
@@ -4068,6 +4143,10 @@ static int cdb2_read_record(cdb2_hndl_tp *hndl, uint8_t **buf, int *len, int *ty
40684143
40694144 rc = 0 ;
40704145after_callback :
4146+ // reset here
4147+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
4148+ sbuf2settimeout (sb , hndl -> socket_timeout , hndl -> socket_timeout );
4149+ }
40714150 while ((e = cdb2_next_callback (hndl , CDB2_AFTER_READ_RECORD , e )) != NULL ) {
40724151 callbackrc =
40734152 cdb2_invoke_callback (hndl , e , 1 , CDB2_RETURN_VALUE , (intptr_t )rc );
@@ -5954,10 +6033,8 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql, int
59546033 hndl -> retry_all = 1 ;
59556034 int run_last = 1 ;
59566035
5957- time_t max_time =
5958- time (NULL ) + (hndl -> api_call_timeout - hndl -> connect_timeout ) / 1000 ;
5959- if (max_time < 0 )
5960- max_time = 0 ;
6036+ set_max_call_time (hndl );
6037+
59616038retry_queries :
59626039 debugprint (
59636040 "retry_queries: hndl->host=%d (%s)\n" , hndl -> connected_host ,
@@ -5985,18 +6062,11 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql, int
59856062 cdb2_get_dbhosts (hndl );
59866063 }
59876064
5988- int tmsec = 0 ;
5989-
5990- // Add wait if we have already tried on all the nodes.
5991- if (!hndl -> sb && (retries_done > hndl -> num_hosts )) {
5992- tmsec = (retries_done - hndl -> num_hosts ) * 100 ;
5993- }
5994-
59956065 if (hndl -> sslerr != 0 )
59966066 PRINT_AND_RETURN (CDB2ERR_CONNECT_ERROR );
59976067
59986068 if ((retries_done > 1 ) && ((retries_done > hndl -> max_retries ) ||
5999- (( time ( NULL ) + ( tmsec / 1000 )) >= max_time ))) {
6069+ (is_api_call_timedout ( hndl ) ))) {
60006070 sprintf (hndl -> errstr , "%s: Maximum number of retries done." , __func__ );
60016071 if (is_hasql_commit ) {
60026072 cleanup_query_list (hndl , & commit_query_list , __LINE__ );
@@ -7873,17 +7943,13 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
78737943 }
78747944 }
78757945
7876- time_t max_time =
7877- time (NULL ) +
7878- (hndl -> api_call_timeout - (CDB2_POLL_TIMEOUT + hndl -> connect_timeout )) /
7879- 1000 ;
7880- if (max_time < 0 )
7881- max_time = 0 ;
7946+ if (!hndl -> max_call_time )
7947+ set_max_call_time (hndl );
78827948
78837949 use_bmsd = cdb2_use_bmsd && (* cdb2_bmssuffix != '\0' ) && !hndl -> num_shards ; // cannot find shards via bmsd yet
78847950retry :
78857951 if (rc ) {
7886- if (num_retry >= MAX_RETRIES || time ( NULL ) > max_time )
7952+ if (num_retry >= MAX_RETRIES || is_api_call_timedout ( hndl ) )
78877953 goto after_callback ;
78887954
78897955 num_retry ++ ;
@@ -7901,7 +7967,7 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
79017967 hndl , cdb2_default_cluster , comdb2db_name , comdb2db_num ,
79027968 comdb2db_hosts [i ], comdb2db_hosts , comdb2db_ports , & master ,
79037969 & num_comdb2db_hosts , NULL );
7904- if (rc == 0 || time ( NULL ) >= max_time ) {
7970+ if (rc == 0 || is_api_call_timedout ( hndl ) ) {
79057971 break ;
79067972 }
79077973 }
@@ -7918,15 +7984,15 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
79187984 hndl -> hosts , & hndl -> num_hosts , hndl -> dbname , hndl -> cluster , & hndl -> dbnum ,
79197985 & hndl -> num_hosts_sameroom , num_retry , use_bmsd , hndl -> shards , & hndl -> num_shards ,
79207986 & hndl -> num_shards_sameroom );
7921- if (rc == 0 || time ( NULL ) >= max_time ) {
7987+ if (rc == 0 || is_api_call_timedout ( hndl ) ) {
79227988 break ;
79237989 } else if (use_bmsd ) {
79247990 if (cdb2_comdb2db_fallback )
79257991 use_bmsd = 0 ;
79267992 goto retry ;
79277993 }
79287994 }
7929- if (rc == -1 && time ( NULL ) < max_time ) {
7995+ if (rc == -1 && ! is_api_call_timedout ( hndl ) ) {
79307996 rc = comdb2db_get_dbhosts (hndl , comdb2db_name , comdb2db_num , comdb2db_hosts [master ], comdb2db_ports [master ],
79317997 hndl -> hosts , & hndl -> num_hosts , hndl -> dbname , hndl -> cluster , & hndl -> dbnum ,
79327998 & hndl -> num_hosts_sameroom , num_retry , use_bmsd , hndl -> shards , & hndl -> num_shards ,
0 commit comments