@@ -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,34 @@ 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+ struct timeval tv ;
874+ gettimeofday (& tv , NULL );
875+ long long current_time = tv .tv_sec * 1000 + tv .tv_usec /1000 ;
876+ long long time_left = hndl -> max_call_time - current_time ;
877+ if (hndl -> max_call_time && time_left <= 0 )
878+ time_left = 1 ;
879+ if (time_left > 0 && (time_left < timeout ))
880+ return time_left ;
881+ return timeout ;
882+ }
883+
884+ static void set_max_call_time (cdb2_hndl_tp * hndl ) {
885+ struct timeval tv ;
886+ gettimeofday (& tv , NULL );
887+ hndl -> max_call_time = tv .tv_sec * 1000 + tv .tv_usec /1000 + hndl -> api_call_timeout ;
888+ }
889+
859890enum {
860891 PASSFD_SUCCESS = 0 ,
861892 PASSFD_RECVMSG = -1 , /* error with recvmsg() */
@@ -995,8 +1026,7 @@ static int recv_fd_int(int sockfd, void *data, size_t nbytes, int *fd_recvd, int
9951026static int recv_fd (const cdb2_hndl_tp * hndl , int sockfd , void * data , size_t nbytes , int * fd_recvd )
9961027{
9971028 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 ;
1029+ timeoutms = get_call_timeout (hndl , timeoutms );
10001030 rc = recv_fd_int (sockfd , data , nbytes , fd_recvd , timeoutms );
10011031 if (rc != 0 && * fd_recvd != -1 ) {
10021032 int errno_save = errno ;
@@ -1116,8 +1146,7 @@ static int send_fd_to(int sockfd, const void *data, size_t nbytes,
11161146static int send_fd (const cdb2_hndl_tp * hndl , int sockfd , const void * data , size_t nbytes , int fd_to_send )
11171147{
11181148 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 ;
1149+ timeoutms = get_call_timeout (hndl , timeoutms );
11211150 return send_fd_to (sockfd , data , nbytes , fd_to_send , timeoutms );
11221151}
11231152
@@ -1591,6 +1620,8 @@ static void read_comdb2db_environment_cfg(cdb2_hndl_tp *hndl, const char *comdb2
15911620 & cdb2_sockpool_recv_timeoutms_set_from_env );
15921621 process_env_var_int ("COMDB2_CONFIG_API_CALL_TIMEOUT" , & CDB2_API_CALL_TIMEOUT ,
15931622 & cdb2_api_call_timeout_set_from_env );
1623+ process_env_var_int ("COMDB2_CONFIG_ENFORCE_API_CALL_TIMEOUT" , & CDB2_ENFORCE_API_CALL_TIMEOUT ,
1624+ & cdb2_enforce_api_call_timeout_set_from_env );
15941625 process_env_var_int ("COMDB2_CONFIG_COMDB2DB_TIMEOUT" , & COMDB2DB_TIMEOUT , & cdb2_comdb2db_timeout_set_from_env );
15951626 process_env_var_int ("COMDB2_CONFIG_SOCKET_TIMEOUT" , & CDB2_SOCKET_TIMEOUT , & cdb2_socket_timeout_set_from_env );
15961627 process_env_var_int ("COMDB2_CONFIG_PROTOBUF_SIZE" , & CDB2_PROTOBUF_SIZE , & cdb2_protobuf_size_set_from_env );
@@ -1841,6 +1872,9 @@ static void read_comdb2db_cfg(cdb2_hndl_tp *hndl, SBUF2 *s, const char *comdb2db
18411872 hndl -> api_call_timeout = atoi (tok );
18421873 else if (tok )
18431874 CDB2_API_CALL_TIMEOUT = atoi (tok );
1875+ } else if (!cdb2_api_call_timeout_set_from_env && (strcasecmp ("enforce_api_call_timeout" ,tok ) == 0 )) {
1876+ tok = strtok_r (NULL , " :," , & last );
1877+ CDB2_ENFORCE_API_CALL_TIMEOUT = value_on_off (tok , & err );
18441878 } else if (strcasecmp ("auto_consume_timeout" , tok ) == 0 ) {
18451879 tok = strtok_r (NULL , " :," , & last );
18461880 if (tok )
@@ -2125,6 +2159,8 @@ static void set_cdb2_timeouts(cdb2_hndl_tp *hndl)
21252159 hndl -> comdb2db_timeout = hndl -> api_call_timeout ;
21262160 if (hndl -> socket_timeout > hndl -> api_call_timeout )
21272161 hndl -> socket_timeout = hndl -> api_call_timeout ;
2162+
2163+ set_max_call_time (hndl );
21282164}
21292165
21302166/* Read all available comdb2 configuration files.
@@ -3688,8 +3724,22 @@ static int cdb2portmux_get(cdb2_hndl_tp *hndl, const char *type,
36883724
36893725 debugprint ("name %s\n" , name );
36903726
3727+ int connect_timeout = hndl -> connect_timeout ;
3728+
3729+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3730+ # ifdef CDB2API_TEST
3731+ printf ("RETRY with timeout %d\n" , get_call_timeout (hndl , connect_timeout ));
3732+ # endif
3733+ if (is_api_call_timedout (hndl )) {
3734+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out connecting to db\n" , __func__ , __LINE__ );
3735+ port = -1 ;
3736+ goto after_callback ;
3737+ }
3738+ connect_timeout = get_call_timeout (hndl , connect_timeout );
3739+ }
3740+
36913741 fd = cdb2_tcpconnecth_to (hndl , remote_host , CDB2_PORTMUXPORT , 0 ,
3692- hndl -> connect_timeout );
3742+ connect_timeout );
36933743 if (fd < 0 ) {
36943744 debugprint ("cdb2_tcpconnecth_to returns fd=%d'\n" , fd );
36953745 if (errno == EINPROGRESS ) {
@@ -3715,7 +3765,18 @@ static int cdb2portmux_get(cdb2_hndl_tp *hndl, const char *type,
37153765 port = -1 ;
37163766 goto after_callback ;
37173767 }
3718- sbuf2settimeout (ss , hndl -> connect_timeout , hndl -> connect_timeout );
3768+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3769+ # ifdef CDB2API_TEST
3770+ printf ("RETRY with timeout %d\n" , get_call_timeout (hndl , connect_timeout ));
3771+ # endif
3772+ if (is_api_call_timedout (hndl )) {
3773+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out connecting to db\n" , __func__ , __LINE__ );
3774+ port = -1 ;
3775+ goto after_callback ;
3776+ }
3777+ connect_timeout = get_call_timeout (hndl , connect_timeout );
3778+ }
3779+ sbuf2settimeout (ss , connect_timeout , connect_timeout );
37193780 sbuf2printf (ss , "get %s\n" , name );
37203781 sbuf2flush (ss );
37213782 res [0 ] = 0 ;
@@ -3904,6 +3965,17 @@ static int cdb2_read_record(cdb2_hndl_tp *hndl, uint8_t **buf, int *len, int *ty
39043965 goto after_callback ;
39053966
39063967retry :
3968+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
3969+ int socket_timeout = get_call_timeout (hndl , hndl -> socket_timeout );
3970+ # ifdef CDB2API_TEST
3971+ printf ("GOT HEARTBEAT || Set timeout to %d\n" , socket_timeout );
3972+ # endif
3973+ if (is_api_call_timedout (hndl )) {
3974+ snprintf (hndl -> errstr , sizeof (hndl -> errstr ), "%s:%d Timed out reading response from the db\n" , __func__ , __LINE__ );
3975+ rc = -1 ;
3976+ }
3977+ sbuf2settimeout (sb , socket_timeout , socket_timeout );
3978+ }
39073979 b_read = sbuf2fread ((char * )& hdr , 1 , sizeof (hdr ), sb );
39083980 debugprint ("READ HDR b_read=%d, sizeof(hdr)=(%zu):\n" , b_read , sizeof (hdr ));
39093981
@@ -4068,6 +4140,10 @@ static int cdb2_read_record(cdb2_hndl_tp *hndl, uint8_t **buf, int *len, int *ty
40684140
40694141 rc = 0 ;
40704142after_callback :
4143+ // reset here
4144+ if (CDB2_ENFORCE_API_CALL_TIMEOUT ) {
4145+ sbuf2settimeout (sb , hndl -> socket_timeout , hndl -> socket_timeout );
4146+ }
40714147 while ((e = cdb2_next_callback (hndl , CDB2_AFTER_READ_RECORD , e )) != NULL ) {
40724148 callbackrc =
40734149 cdb2_invoke_callback (hndl , e , 1 , CDB2_RETURN_VALUE , (intptr_t )rc );
@@ -5954,10 +6030,8 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql, int
59546030 hndl -> retry_all = 1 ;
59556031 int run_last = 1 ;
59566032
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 ;
6033+ set_max_call_time (hndl );
6034+
59616035retry_queries :
59626036 debugprint (
59636037 "retry_queries: hndl->host=%d (%s)\n" , hndl -> connected_host ,
@@ -5985,18 +6059,11 @@ static int cdb2_run_statement_typed_int(cdb2_hndl_tp *hndl, const char *sql, int
59856059 cdb2_get_dbhosts (hndl );
59866060 }
59876061
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-
59956062 if (hndl -> sslerr != 0 )
59966063 PRINT_AND_RETURN (CDB2ERR_CONNECT_ERROR );
59976064
59986065 if ((retries_done > 1 ) && ((retries_done > hndl -> max_retries ) ||
5999- (( time ( NULL ) + ( tmsec / 1000 )) >= max_time ))) {
6066+ (is_api_call_timedout ( hndl ) ))) {
60006067 sprintf (hndl -> errstr , "%s: Maximum number of retries done." , __func__ );
60016068 if (is_hasql_commit ) {
60026069 cleanup_query_list (hndl , & commit_query_list , __LINE__ );
@@ -7873,17 +7940,13 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
78737940 }
78747941 }
78757942
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 ;
7943+ if (!hndl -> max_call_time )
7944+ set_max_call_time (hndl );
78827945
78837946 use_bmsd = cdb2_use_bmsd && (* cdb2_bmssuffix != '\0' ) && !hndl -> num_shards ; // cannot find shards via bmsd yet
78847947retry :
78857948 if (rc ) {
7886- if (num_retry >= MAX_RETRIES || time ( NULL ) > max_time )
7949+ if (num_retry >= MAX_RETRIES || is_api_call_timedout ( hndl ) )
78877950 goto after_callback ;
78887951
78897952 num_retry ++ ;
@@ -7901,7 +7964,7 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
79017964 hndl , cdb2_default_cluster , comdb2db_name , comdb2db_num ,
79027965 comdb2db_hosts [i ], comdb2db_hosts , comdb2db_ports , & master ,
79037966 & num_comdb2db_hosts , NULL );
7904- if (rc == 0 || time ( NULL ) >= max_time ) {
7967+ if (rc == 0 || is_api_call_timedout ( hndl ) ) {
79057968 break ;
79067969 }
79077970 }
@@ -7918,15 +7981,15 @@ static int cdb2_get_dbhosts(cdb2_hndl_tp *hndl)
79187981 hndl -> hosts , & hndl -> num_hosts , hndl -> dbname , hndl -> cluster , & hndl -> dbnum ,
79197982 & hndl -> num_hosts_sameroom , num_retry , use_bmsd , hndl -> shards , & hndl -> num_shards ,
79207983 & hndl -> num_shards_sameroom );
7921- if (rc == 0 || time ( NULL ) >= max_time ) {
7984+ if (rc == 0 || is_api_call_timedout ( hndl ) ) {
79227985 break ;
79237986 } else if (use_bmsd ) {
79247987 if (cdb2_comdb2db_fallback )
79257988 use_bmsd = 0 ;
79267989 goto retry ;
79277990 }
79287991 }
7929- if (rc == -1 && time ( NULL ) < max_time ) {
7992+ if (rc == -1 && ! is_api_call_timedout ( hndl ) ) {
79307993 rc = comdb2db_get_dbhosts (hndl , comdb2db_name , comdb2db_num , comdb2db_hosts [master ], comdb2db_ports [master ],
79317994 hndl -> hosts , & hndl -> num_hosts , hndl -> dbname , hndl -> cluster , & hndl -> dbnum ,
79327995 & hndl -> num_hosts_sameroom , num_retry , use_bmsd , hndl -> shards , & hndl -> num_shards ,
0 commit comments