kubo / ruby-oci8

Ruby-oci8 - Oracle interface for ruby
Other
169 stars 75 forks source link

Question regarding a thread issue that was potentially fixed #244

Closed poblouin closed 11 months ago

poblouin commented 2 years ago

Hello! I have a question that would be for you @kubo.

We have a production application using this gem, here are the specs:

ruby v2.7.5 rails v5.2.6.3 ruby-oci8 v2.2.9 oracle db v12

We tried upgrading to rails 6 (6.0.4.7) 2 weeks ago and we started having a lot of errors like this: executing in another thread which is raised by the C code of this gem.

We spent a lot of time trying to understand why (we still don't, up to this day), but we did find that a specific commit that solves the issue. That would be this commit: https://github.com/kubo/ruby-oci8/commit/031cab52f95e9d3ea5229ed0e465c95a7e94dcaa.

We were wondering if you would have an explanation of what could have happened here? We were wondering if the changes in ext/oci8/apiwrap.c.tmpl in that commit would be the fix?

Without the full context of how our application if configured, I guess you might not have an answer, but I was curious to ask anyway.

Thank you!

kubo commented 2 years ago

I'm not sure but it may be fixed by inserting write barriers. (https://bugs.ruby-lang.org/projects/ruby-master/wiki/RGenGC)

before https://github.com/kubo/ruby-oci8/commit/031cab52f95e9d3ea5229ed0e465c95a7e94dcaa:

  1. Set svcctx->executing_thread with write barrier. RB_OBJ_WRITE(parg->svcctx->base.self, &parg->svcctx->executing_thread, rb_thread_current()) in oci8lib.c
  2. Enter a blocking region. (It releases a global VM lock to allow other ruby threads run.)
  3. Execute an OCI function which may take a long time.
  4. Unset svcctx->executing_thread without write barrier. (svcctx)->executing_thread = Qnil in apiwrap.c.tmpl
  5. Leave the blocking region.

after https://github.com/kubo/ruby-oci8/commit/031cab52f95e9d3ea5229ed0e465c95a7e94dcaa:

  1. Set svcctx->executing_thread with write barrier. RB_OBJ_WRITE(parg->svcctx->base.self, &parg->svcctx->executing_thread, rb_thread_current()) in oci8lib.c
  2. Enter a blocking region.
  3. Execute an OCI function which may take a long time.
  4. Leave the blocking region.
  5. Unset svcctx->executing_thread with write barrier. RB_OBJ_WRITE(svcctx->base.self, &svcctx->executing_thread, Qnil) in oci8lib.c