-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release lock during io #29
Release lock during io #29
Conversation
I'm not sure why it wouldn't let me re-open #27 but this is the same thing but with code to track whether or not we have the runtime lock, which makes it much easier to verify that we're doing things right in the callbacks. This passes the tests in this repo and also my company's tests (which are unfortunately based on a higher-level library so I can't easily merge them into this repo), so I think it's ready to merge if you're happy with it. Let me know if you want any changes. |
Actually one more issue.. the error and message handlers can be called by dbopen, which is before we have our lock tracker setup. |
d071311
to
ea0878a
Compare
Ok it should be good now. I added special handling for the dbopen case and a new |
if (had_lock) { | ||
release_lock(dbproc); | ||
} | ||
CAMLreturn(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This used to have a comment /* should not return */
, but this function will return as long as the callback doesn't throw an exception. Also the Sybase docs for dbmsghandle
say:
The message handler must return a value of 0 to DB-Library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and it's not entirely clear to me if it's safe to call CAMLreturn without the lock, but i don't know how to trigger CAMLreturn's cleanups otherwise?
if (had_lock) { | ||
release_lock(dbproc); | ||
} | ||
CAMLreturn(INT_CANCEL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another case where this can return if the error handle doesn't throw an exception.
Makefile
Outdated
@@ -1,7 +1,7 @@ | |||
all: build | |||
|
|||
build: | |||
@jbuilder build @install @test --dev | |||
@jbuilder build @install @test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--dev
is now implicit in dune
. Will make the explicit switch to dune so you can rebase on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was getting this error with the --dev:
dune: --dev is no longer accepted as it is now the default.
Usage: dune build [OPTION]... [TARGET]...
Try `dune build --help' or `dune --help' for more information.
make: *** [Makefile:4: build] Error 1
I added this as pull request #28 if you want to review that on its own.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just pushed a full port to Dune (and the included configurator). Could you rebase on top if it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Remove your changes to the Makefile and use dune
instead of jbuild
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just rebased it
ea0878a
to
7f8dfd0
Compare
May you remind me: the library does not accept several concurrent calls in the same program? |
http://www.freetds.org/faq.html#thread.safe
So we can use multiple FreeTDS connections in different threads, we just can't use the same connection in multiple threads. |
Hm I don't understand the new build failures.. Maybe it's related to the Dune change? |
Ah yeah, the CI build failures seem to be from the previous commit, not this one. It does build and pass tests locally so I think there's just something wrong with the CI builds. |
0135dd7
to
aa28e2b
Compare
Travis is fixed. For AppVeyor, there remains a bug in opam. |
May you please rebase? |
7f8dfd0
to
3f37311
Compare
Rebased |
Hm just ran into a segfault in code that seems possibly related to this.. I'm going to check into it more. This is really complex to get right :( |
src/dblib_stubs.c
Outdated
|
||
/* OCaml severity. Keep in sync with OCaml [Dblib]. */ | ||
#define SEVERITY_PROGRAM Val_int(6) | ||
#define SEVERITY_RESOURCE Val_int(7) | ||
#define SEVERITY_FATAL Val_int(9) | ||
#define SEVERITY_CONSISTENCY Val_int(10) | ||
|
||
static int release_lock(DBPROCESS *dbproc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't freetds_release_runtime_system
be clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
int *have_lock = (int*)dbgetuserdata(dbproc); | ||
|
||
// If have_lock wasn't setup, then we're in the msg/error callback for dbopen | ||
if (have_lock == NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the lock be allocated & initialized when the dbproc value is created (and released by its finalizer)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what this pull request does. The problem is that dbopen
both allocates a dbproc and attempts to connect to the remote server, so if the connection fails, we'll have the exception handler called before we have a chance to call dbsetuserdata
.
server = String_val(vserver); | ||
caml_release_runtime_system(); | ||
dbproc = dbopen(login, server); | ||
caml_acquire_runtime_system(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Chris00 This is the case where we need to handle have_runtime_lock
being null, since we don't want to hold the lock while we're making the initial connection to the server, but we don't have a (non-null) dbproc until line 302.
3f37311
to
0be4014
Compare
This releases OCaml's runtime lock whenever we call C functions that do IO. It should allow users of this to run ocaml-freetds in parallel, or when using Async/Lwt. I had to re-arrange some code to avoid calling any OCaml functions while the lock was released. We use wrappers around the release/acquire functions to ensure that we don't try to acquire or release the lock twice, which could potentially happen in the msg/error callbacks.
0be4014
to
d18f320
Compare
Ok I figured out what I was causing problems in our system. I had the check at the end of the message handler backwards:
Should have been:
That's fixed and now it's working well in our systems, so this can be merged if you're happy with it. I also renamed the functions as requested. Note that I added another commit to add (name) to the dune-project file, which was necessary to make |
Thanks fort working on this. Unfortunately, I won't have time to do a thorough review until next Tuesday. I'll merge or make additional comments then. |
We're seeing some random inexplicable syntax errors that may be related to this change (syntax error on character not in the query), although it's hard to tell since it occurs at random. Our guess right now is that either FreeTDS is not as thread-safe as it claims to be (supposedly it should be safe to use different connections concurrently, it's just that individual connection handles aren't thread safe), or the way we throw exceptions out of C code in the callbacks is doing bad things to FreeTDS's internals. I'd like to fix this library to never throw exeptions in C callbacks but it's kind of hard. I'm also looking into re-implementing TDS from scratch in https://github.com/brendanlong/ocaml-tds |
Did you ask on the freeTDS mailing list? |
We're investigating a different approach, trying to use the Ctlib backend instead since it doesn't have callbacks. |
No description provided.