Skip to Content.
Sympa Menu

freetds - Re: [freetds] timeout

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Frediano Ziglio <freddyz77 AT tin.it>
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] timeout
  • Date: Sat, 05 Jun 2004 11:11:06 +0200

Il mar, 2004-06-01 alle 07:36, James K. Lowden ha scritto:
> I thought I'd try to implement dbsettime(). It's not simple, for a few
> reasons. One, I'm not all that familiar with network programming a la
> Unix. Two, it doesn't take a dbproc as an argument: the documentation
> says
>
> "dbsettime can be called at any time during the application--before or
> after a call to dbopen. It takes effect immediately upon being called."
>
> Because we maintain per-connection timeouts (in TDSSOCKET), that implies
> that dbsettime() has to:
>
> 1. set a new default for future connections.
> 2. iterate over the open connections, adjusting each one's timeout.
>
> (a bit tricky in a multithreaded setting).
>
> That brings me to the third reason it's not simple: the number of timeouts
> in TDSCONNECTION. We have:
>
> $ sed -ne'/tds_connection$/,/TDSCONNECTION/p' include/tds.h |grep timeout
>
> TDS_INT connect_timeout;
> TDS_INT query_timeout;
> TDS_INT longquery_timeout;
> int timeout;
>
> I think longquery_timeout is an ODBC thing that we can ignore for now
> (although I haven't found anything in the ODBC spec about a "longquery"
> timeout, either).
>
> The real confusion is in how the others interact, not least because there
> are 3 variables to control 2 things.
>
> To be absolutely clear, let us define our terms:
>
> 1. Connection timeout. How long we'll wait for the server to acknowledge
> the formation of a connection. E.g, how long dbopen() will wait for an
> answer.
> 2. Query timeout. How long we'll wait for a response to a query.
>
> The code
> --------
>
> For starters, in config.c, the TDSCONNECTION members are set thus:
>
> } else if (!strcmp(option, TDS_STR_TIMEOUT)) {
> if (atoi(value))
> connection->timeout = atoi(value);
> } else if (!strcmp(option, TDS_STR_CONNTIMEOUT)) {
> if (atoi(value))
> connection->connect_timeout = atoi(value);
>
> So, 'query_timeout' is not initialized from freetds.conf, but 'timeout'
> is.
>
> In login.c, we have this weird line:
>
> tds->timeout = (connect_timeout) ? connection->query_timeout : 0;
>
> Weird, first, because nowhere that I know of do we say "if you indicate a
> query timeout, it won't be honored unless you indicate a connection
> timeout, too. But, if you set a timeout in freetds.conf and *don't* set a
> connection timeout, then the query timeout will will work."
>
> Weird, second, because afaict that's the only place TDSSOCKET::timeout is
> set, and that's the value read.c::goodread() relies on.
>
> Weird, third, because again afaict connection->query_timeout is used
> otherwise only in odbc.c::_SQLExecute to set tds->longquery_timeout. I
> don't see it referenced anywhere else in libtds.
>
> Also in login.c, we have a function tds_set_timeouts(). No one calls it.
>
>
> Proposal
> --------
>
> I like the name 'query_timeout' better than 'timeout'. It's pretty clear,
> though, that 'timeout' is older and is used more extensively (but not
> quite correctly). I suggest we:
>
> 1. Delete 'query_timeout' from the structures, shifting all references to
> use 'timeout' instead. It looks to me like that's the intent anyway.
>
> 2. Fix login.c. Use 'connect_timeout' for the initial connection, and
> initialize 'timeout' according to the default from freetds.conf or e.g.
> dbsettime().
>

That's not use connect_timeout to init timeout and query_timeout.
Agreed. connect_timeout it's only used to timeout connect() call. The
only reason to use connect_timeout to init timeout it's to implement a
login_timeout (required by ODBC and dblib...). Was this the original
intent ??

> 3. Rename 'timeout' to 'query_timeout'. Add "query timeout" as a
> freetds.conf entry, while retaining "timeout" as an undocumented (but
> working) alias.
>

?? why delete query_timeout than use timeout than rename timeout to
query_timeout ??

> 4. Delete tds_set_timeouts(). Add dbsettime().
>

Agreed.

> For the record, Microsoft defines DBSETLTIME(), a per-login connect
> timeout. We don't support it, and no one's asked for it. To support it,
> tdsdbopen() would need to know to preserve the TDSLOGIN::timeout when
> reading freetds.conf.
>
> I'm especially interested in any corrections to my understanding. All
> suggestions welcome, naturally.
>

Cfr also same subject thread ("timeout") on ML (January)

Using a grep

$ grep -rw query_timeout *
include/tds.h: TDS_INT query_timeout;
include/tds.h: TDS_INT query_timeout;
include/tdsodbc.h: SQLUINTEGER query_timeout;
src/odbc/odbc.c: stmt->attr.query_timeout = 0;
src/odbc/odbc.c: tds->longquery_timeout =
stmt->attr.query_timeout;
src/odbc/odbc.c: size = sizeof(stmt->attr.query_timeout);
src/odbc/odbc.c: src = &stmt->attr.query_timeout;
src/odbc/odbc.c: stmt->attr.query_timeout = ui;
Il file binario src/dblib/unittests/data.bin corrisponde
src/tds/config.c: connection->query_timeout =
login->query_timeout;
src/tds/login.c: tds->timeout = (connect_timeout) ?
connection->query_timeout : 0;

as you can see query_timeout is not used. Well.. it's used to init
tds->timeout in login.c... Perhaps should longquery_timeout and
query_timeout be the same thing ??

The key in code it's goodread (src/tds/read.c, cfr "goodread... not so
fine" on ML).
connect_timeout behavior it's clear (if we are not able to connect to
server in X seconds return connection fails). I don't understand why in
login.c we set timeout and longquery_timeout based on connect_timeout...
timeout is used in read.c to do polling (using chkintr and hndlintr
fields of TDSSOCKET) and in write.c to check if server it's reading our
data. Perhaps a write_timeout would help making things more clear ??
query_timeout not used :(
longquery_timeout it's used in goodread to break loop. However in
tds_read_packet if we get some bytes from goodread we continue calling
goodread... this IMHO lead to strange behavior and timeouts. Assuming
server returns a row every 10 seconds, timeout = 12 and
longquery_timeout = 120 even if we get 1000000 rows libTDS continue to
get data... Is this expected ?? Also if goodread (in tds_read_packet)
return <1 we close connection... opinable things... perhaps client wants
simply to cancel is a timeout is reached... however how to signal to
client this condition ? Looking at goodread again if timeout it's
reached while loop exit and so longquery_timeout (witch IMHO should be
longer) do not occur; goodread (tds_read_packet) got called again using
timeout. So we exit from main (tds_read_packet) loop if no data arrived
in timeout (even if longquery_timeout it's not reached)... If I'm
confusing somebody let's me say that I'm confused too :)

Another issue concerns no-blocking socket. If we have connect_timeout
socket it's no-blocking otherwise it's blocking; in read.c code works
either in blocking or no-blocking (cause it always use select before
read) however to simplify things it would better to decide blocking
option...

I don't like queryStarttime field name... we never used capitalized word
to compute names... query_starttime would IMHO be better (at least one
easy things to solve :) )

My head is becoming quite hot... I suggests more timeouts:
- read_timeout
- write_timeout
- connect_timeout
- login_timeout
- query_timeout
(I'm kidding :) )

freddy77






Archive powered by MHonArc 2.6.24.

Top of Page