NCBI C++ ToolKit
timeout.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * Purpose: Test handling of timeouts with an error handler
3  * Functions: dberrhandle, dbsetlogintime, dbsettime, dbsetopt, dbclropt, dbisopt
4  * \todo We test returning INT_CANCEL for a login timeout. We don't test it for a query_timeout.
5  */
6 
7 #include "common.h"
8 #include <time.h>
9 
10 #include <common/test_assert.h>
11 
12 static int ntimeouts = 0, ncancels = 0;
13 static const int max_timeouts = 2, timeout_seconds = 2;
14 static time_t start_time;
15 
16 static int timeout_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
17 static int chkintr(DBPROCESS * dbproc);
18 static int hndlintr(DBPROCESS * dbproc);
19 
20 #if !defined(SYBETIME)
21 #define SYBETIME SQLETIME
22 #define INT_TIMEOUT INT_CANCEL
23 dbsetinterrupt(DBPROCESS *dbproc, void* hand, void* p) {}
24 #endif
25 
26 static int
27 timeout_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
28 {
29  /*
30  * For server messages, cancel the query and rely on the
31  * message handler to spew the appropriate error messages out.
32  */
33  if (dberr == SYBESMSG)
34  return INT_CANCEL;
35 
36  if (dberr == SYBETIME) {
37  fprintf(stderr, "%d timeouts received in %ld seconds, ", ++ntimeouts, (long int) (time(NULL) - start_time));
38  if (ntimeouts > max_timeouts) {
39  if (++ncancels > 1) {
40  fprintf(stderr, "could not timeout cleanly, breaking connection\n");
41  ncancels = 0;
42  return INT_CANCEL;
43  }
44  fprintf(stderr, "lost patience, cancelling (allowing 10 seconds)\n");
45  if (dbsettime(10) == FAIL)
46  fprintf(stderr, "... but dbsettime() failed in error handler\n");
47  return INT_TIMEOUT;
48  }
49  fprintf(stderr, "continuing to wait\n");
50  return INT_CONTINUE;
51  }
52 
53  ntimeouts = 0; /* reset */
54 
55  fprintf(stderr,
56  "DB-LIBRARY error (severity %d, dberr %d, oserr %d, dberrstr %s, oserrstr %s):\n",
57  severity, dberr, oserr, dberrstr ? dberrstr : "(null)", oserrstr ? oserrstr : "(null)");
58  fflush(stderr);
59 
60  /*
61  * If the dbprocess is dead or the dbproc is a NULL pointer and
62  * we are not in the middle of logging in, then we need to exit.
63  * We can't do anything from here on out anyway.
64  * It's OK to end up here in response to a dbconvert() that
65  * resulted in overflow, so don't exit in that case.
66  */
67  if ((dbproc == NULL) || DBDEAD(dbproc)) {
68  if (dberr != SYBECOFL) {
69  fprintf(stderr, "error: dbproc (%p) is %s, goodbye\n",
70  dbproc, dbproc? (DBDEAD(dbproc)? "DEAD" : "OK") : "NULL");
71  exit(255);
72  }
73  }
74 
75  return INT_CANCEL;
76 }
77 
78 static int
80 {
81  printf("in chkintr, %ld seconds elapsed\n", (long int) (time(NULL) - start_time));
82  return FALSE;
83 }
84 
85 static int
87 {
88  printf("in hndlintr, %ld seconds elapsed\n", (long int) (time(NULL) - start_time));
89  return INT_CONTINUE;
90 }
91 
92 static int failed = 0;
93 
94 static void
95 test(int per_process)
96 {
97  LOGINREC *login;
99  int i, r;
100  RETCODE erc, row_code;
101  int num_resultset = 0;
102  char teststr[1024];
103  char timeout[32];
104 
105  sprintf(timeout, "%d", timeout_seconds);
106 
107  ntimeouts = 0;
108  ncancels = 0;
109 
110  /*
111  * Connect to server
112  */
115 
116  printf("About to logon\n");
117 
118  login = dblogin();
121  DBSETLAPP(login, "#timeout");
122 
123  printf("About to open %s.%s\n", SERVER, DATABASE);
124 
125  /*
126  * One way to test the login timeout is to connect to a discard server (grep discard /etc/services).
127  * It's normally supported by inetd.
128  */
129  printf ("using %d 1-second login timeouts\n", max_timeouts);
130  dbsetlogintime(1);
131 
132  start_time = time(NULL); /* keep track of when we started for reporting purposes */
133 
134  if (NULL == (dbproc = dbopen(login, SERVER))){
135  fprintf(stderr, "Failed: dbopen\n");
136  exit(1);
137  }
138 
139  printf ("connected.\n");
140 
141  if (strlen(DATABASE))
143 
145 
146  /* Set a very long global timeout. */
147  if (per_process)
148  dbsettime(5 * 60);
149 
150  /* Verify no query timeout is set for this DBPROCESS */
151  if (dbisopt(dbproc, DBSETTIME, 0)) {
152  printf("unexpected return code from dbisopt() before calling dbsetopt(..., DBSETTIME, ...)\n");
153  exit(1);
154  }
155 
156  if (FAIL == dbsetopt(dbproc, DBSETTIME, timeout, 0)) {
157  fprintf(stderr, "Failed: dbsetopt(..., DBSETTIME, \"%d\")\n", timeout_seconds);
158  exit(1);
159  }
160 
161  /* Verify a query timeout is actually set for this DBPROCESS now */
162  if (!dbisopt(dbproc, DBSETTIME, 0)) {
163  printf("unexpected return code from dbisopt() after calling dbsetopt(..., DBSETTIME, ...)\n");
164  exit(1);
165  }
166 
167  if (FAIL == dbclropt(dbproc, DBSETTIME, 0)) {
168  fprintf(stderr, "Failed: dbclropt(..., DBSETTIME, ...)\n");
169  exit(1);
170  }
171 
172  /* Verify no query timeout remains set for this DBPROCESS */
173  if (dbisopt(dbproc, DBSETTIME, 0)) {
174  printf("unexpected return code from dbisopt() after calling dbclropt(..., DBSETTIME, ...)\n");
175  exit(1);
176  }
177 
178  printf ("using %d %d-second query timeouts\n", max_timeouts, timeout_seconds);
179  if (per_process) {
180  if (FAIL == dbsetopt(dbproc, DBSETTIME, timeout, 0)) {
181  fprintf(stderr, "Failed: dbsetopt(..., DBSETTIME, \"%d\")\n", timeout_seconds);
182  exit(1);
183  }
184 
185  /* Verify setting the global timeout won't override the per-process timeout value */
186  dbsettime(35);
187  } else {
188  if (FAIL == dbsettime(timeout_seconds)) {
189  fprintf(stderr, "Failed: dbsettime\n");
190  exit(1);
191  }
192  }
193 
194  /* send something that will take awhile to execute */
195  printf ("issuing a query that will take 30 seconds\n");
196 
197  if (FAIL == sql_cmd(dbproc)) {
198  fprintf(stderr, "Failed: dbcmd\n");
199  exit(1);
200  }
201 
202  start_time = time(NULL); /* keep track of when we started for reporting purposes */
203  ntimeouts = 0;
206 
207  if (FAIL == dbsqlsend(dbproc)) {
208  fprintf(stderr, "Failed: dbsend\n");
209  exit(1);
210  }
211 
212  /* wait for it to execute */
213  printf("executing dbsqlok\n");
214  erc = dbsqlok(dbproc);
215  if (erc != FAIL) {
216  fprintf(stderr, "dbsqlok should fail for timeout\n");
217  exit(1);
218  }
219 
220  /* retrieve outputs per usual */
221  r = 0;
222  for (i=0; (erc = dbresults(dbproc)) != NO_MORE_RESULTS; i++) {
223  int nrows, ncols;
224  switch (erc) {
225  case SUCCEED:
226  if (DBROWS(dbproc) == FAIL){
227  r++;
228  continue;
229  }
231  printf("dbrows() returned SUCCEED, processing rows\n");
232 
233  ncols = dbnumcols(dbproc);
234  ++num_resultset;
235  printf("bound 1 of %d columns ('%s') in result %d.\n", ncols, dbcolname(dbproc, 1), ++r);
236  dbbind(dbproc, 1, STRINGBIND, 0, (BYTE *) teststr);
237 
238  printf("\t%s\n\t-----------\n", dbcolname(dbproc, 1));
239  while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) {
240  if (row_code == REG_ROW) {
241  printf("\t%s\n", teststr);
242  } else {
243  /* not supporting computed rows in this unit test */
244  failed = 1;
245  fprintf(stderr, "Failed. Expected a row\n");
246  exit(1);
247  }
248  }
249  nrows = (int) dbcount(dbproc);
250  printf("row count %d\n", nrows);
251  if (nrows < 0){
252  failed++;
253  printf("error: dbrows() returned SUCCEED, but dbcount() returned -1\n");
254  }
255 
256  if (FAIL == dbclropt(dbproc, DBSETTIME, 0)) {
257  failed++;
258  printf("error: dbclropt(dbproc, DBSETTIME, ...) failed\n");
259  }
260  break;
261  case FAIL:
262  printf("dbresults returned FAIL\n");
263  exit(1);
264  default:
265  printf("unexpected return code %d from dbresults\n", erc);
266  exit(1);
267  }
268  if (i > 1) {
269  failed++;
270  break;
271  }
272  } /* while dbresults */
273 }
274 
275 int
276 main(int argc, char **argv)
277 {
279 
280  read_login_info(argc, argv);
281 
282  fprintf(stdout, "Starting %s\n", argv[0]);
283 
284  dbinit();
285 
286  test(0);
287  test(1);
288 
289  dbexit();
290 
291  printf("%s %s\n", __FILE__, (failed ? "failed!" : "OK"));
292  return failed ? 1 : 0;
293 }
char PASSWORD[512]
Definition: common.c:31
char DATABASE[512]
Definition: common.c:32
CS_RETCODE read_login_info(void)
Definition: common.c:71
char SERVER[512]
Definition: common.c:30
static TDSLOGIN * login
Definition: dataread.c:31
RETCODE sql_cmd(DBPROCESS *dbproc)
Definition: common.c:280
int syb_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
Definition: common.c:334
void set_malloc_options(void)
Definition: common.c:47
static char teststr[1024]
Definition: t0006.c:10
dbsetinterrupt(DBPROCESS *dbproc, void *hand, void *p)
Definition: timeout.c:23
int main(int argc, char **argv)
Definition: timeout.c:276
#define INT_TIMEOUT
Definition: timeout.c:22
static const int timeout_seconds
Definition: timeout.c:13
static int hndlintr(DBPROCESS *dbproc)
Definition: timeout.c:86
#define SYBETIME
Definition: timeout.c:21
static int ntimeouts
Definition: timeout.c:12
static int timeout_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
Definition: timeout.c:27
static int ncancels
Definition: timeout.c:12
static int chkintr(DBPROCESS *dbproc)
Definition: timeout.c:79
static const int max_timeouts
Definition: timeout.c:13
static void test(int per_process)
Definition: timeout.c:95
static time_t start_time
Definition: timeout.c:14
static int failed
Definition: timeout.c:92
STATUS dbnextrow(DBPROCESS *dbproc)
Definition: dblib.c:2076
#define USER
Definition: fastme_common.h:43
#define NULL
Definition: ncbistd.hpp:225
#define DBSETLPWD(x, y)
Set the password in the login packet.
Definition: sybdb.h:1259
#define DBSETLAPP(x, y)
Set the (client) application name in the login packet.
Definition: sybdb.h:1266
#define DBSETLUSER(x, y)
Set the username in the login packet.
Definition: sybdb.h:1256
LOGINREC * dblogin(void)
Allocate a LOGINREC structure.
Definition: dblib.c:719
#define DBDEAD(x)
Sybase macro mapping to the Microsoft (lower-case) function.
Definition: sybdb.h:762
#define DBROWS(x)
Sybase macro mapping to the Microsoft (lower-case) function.
Definition: sybdb.h:881
RETCODE dbresults(DBPROCESS *dbproc)
Set up query results.
Definition: dblib.c:1706
RETCODE dbinit(void)
Initialize db-lib.
Definition: dblib.c:674
RETCODE dbsetlogintime(int seconds)
Set maximum seconds db-lib waits for a server response to a login attempt.
Definition: dblib.c:4137
RETCODE dbuse(DBPROCESS *dbproc, const char *name)
Change current database.
Definition: dblib.c:1449
RETCODE dbbind(DBPROCESS *dbproc, int column, int vartype, DBINT varlen, BYTE *varaddr)
Tie a host variable to a resultset column.
Definition: dblib.c:2645
RETCODE dbclropt(DBPROCESS *dbproc, int option, const char param[])
Reset an option.
Definition: dblib.c:6008
DBINT dbcount(DBPROCESS *dbproc)
Get count of rows processed.
Definition: dblib.c:2835
RETCODE dbsetopt(DBPROCESS *dbproc, int option, const char *char_param, int int_param)
Set db-lib or server option.
Definition: dblib.c:4383
EHANDLEFUNC dberrhandle(EHANDLEFUNC handler)
Set an error handler, for messages from db-lib.
Definition: dblib.c:5030
void dbloginfree(LOGINREC *login)
free the LOGINREC
Definition: dblib.c:751
DBBOOL dbisopt(DBPROCESS *dbproc, int option, const char param[])
Get value of an option.
Definition: dblib.c:6076
RETCODE dbsqlsend(DBPROCESS *dbproc)
Transmit the command buffer to the server.
Definition: dblib.c:6965
void dbexit()
Close server connections and free all related structures.
Definition: dblib.c:1559
char * dbcolname(DBPROCESS *dbproc, int column)
Return name of a regular result column.
Definition: dblib.c:1884
RETCODE dbsettime(int seconds)
Set maximum seconds db-lib waits for a server response to query.
Definition: dblib.c:4090
int dbnumcols(DBPROCESS *dbproc)
Return number of regular columns in a result set.
Definition: dblib.c:1860
MHANDLEFUNC dbmsghandle(MHANDLEFUNC handler)
Set a message handler, for messages from the server.
Definition: dblib.c:5049
RETCODE dbsqlok(DBPROCESS *dbproc)
Wait for results of a query from the server.
Definition: dblib.c:4722
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
exit(2)
int i
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define assert(x)
Definition: srv_diag.hpp:58
#define dbopen(x, y)
Definition: sybdb.h:855
#define REG_ROW
Definition: sybdb.h:580
int RETCODE
Definition: sybdb.h:121
unsigned char BYTE
Definition: sybdb.h:334
#define NO_MORE_ROWS
Definition: sybdb.h:582
int(* DB_DBCHKINTR_FUNC)(void *dbproc)
Definition: sybdb.h:134
#define SYBECOFL
Definition: sybdb.h:977
#define SUCCEED
Definition: sybdb.h:585
#define DBSETTIME
Definition: sybdb.h:434
#define SYBESMSG
Definition: sybdb.h:946
#define FAIL
Definition: sybdb.h:586
#define INT_CONTINUE
Definition: sybdb.h:61
#define STRINGBIND
Definition: sybdb.h:548
int(* DB_DBHNDLINTR_FUNC)(void *dbproc)
Definition: sybdb.h:135
#define INT_CANCEL
Definition: sybdb.h:62
#define NO_MORE_RESULTS
Definition: sybdb.h:584
DBPROCESS * dbproc
Definition: t0013.c:18
@ FALSE
Definition: testodbc.c:27
Modified on Wed Dec 06 07:15:45 2023 by modify_doxy.py rev. 669887