Re: infinite loop in dbcancel
Frediano Ziglio <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <CAHt6W4eNuYcr5rhNHBi7Kq9LPbbc1R4T114qihxWsV+7H0Vg8Q@mail.gmail.com> |
2016-03-16 19:23 GMT+00:00 Joshua Lang <[email protected]>: > FreeTDS version: 0.95.79 > OS: Debian 7.9 (wheezy) > > Here's the scenario: > > Application has a long-running (pooled) connection to a database. > The database is restarted. > The application then consumes as much of one CPU as it can. > > Unfortunately I have yet to find a simple repro for this issue locally, but > here is what I've found debugging the live application: > > strace shows a constant stream of the following call: > > poll([{fd=150, events=POLLOUT}, {fd=98, events=POLLIN}], 2, 1000) = 1 > ([{fd=150, revents=POLLOUT|POLLERR|POLLHUP}]) > > The (relevant) stack trace from gdb: > > (gdb) bt > #0 0x00007f1fae4d16b3 in *__GI___poll (fds=<optimized out>, > nfds=<optimized out>, timeout=1000) > at ../sysdeps/unix/sysv/linux/poll.c:87 > #1 0x00007f1fa50ff883 in tds_select () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > #2 0x00007f1fa50ffe70 in tds_goodwrite () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > #3 0x00007f1fa5100062 in tds_connection_write () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > #4 0x00007f1fa51046f7 in tds_put_cancel () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > #5 0x00007f1fa50f574b in tds_send_cancel () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > #6 0x00007f1fa50c3560 in dbcancel () from > /opt/zillow/services/mortgage-api-external/zpr/lib/libsybdb.so.5 > > > I've stepped through this with gdb and here are the results: > 1. tds_select is called, returning -1 (verified in gdb) > 2. errno returns to 11 (EAGAIN) (verified in gdb, by stepping through the > c-lib function call to return it) > 3. TDSSOCK_WOULDBLOCK therefore causes the loop to repeat: > https://github.com/FreeTDS/freetds/blob/master/src/tds/net.c#L803 and we're > back to step 1 and an infinite loop > > The TDSSOCK_WOULDBLOCK seems strange to me, and the comment after it > agrees. I wouldn't expect the socket read to block if the poll call just > indicated it was ready for read. I think the problem is in tds_select. After poll returns 1 we check for error and return correctly -1 as failure however errno is not set so it's still the old value. I would try to set to something like EPIPE before returning -1. Frediano