Bug #19638
Updated by leonard100 (Leo Camp) over 1 year ago
Hi, Im currently working on a ruby application that uses Ruby 2.7, ActiveRecord 7 and IBM_DB gem 5.4.0(with the fix https://bugs.ruby-lang.org/issues/19527)
The application requires using ActiveRecord::Base for the connection_pool, Threads and the IBM_DB gem as an adapter to connect to the database but using ActiveRecord.
The application requires running multiple queries at the same time, limited by the pool size. Previously using activerecord-jdbc-adapter and Jruby 1.7 which could run multiple connections and for each connection run a query using the pool and threads, that means 5 queries = 5 connections = 5 threads running them
Now using the IBM_DB gem, you can execute the connections and queries with different ones completing the process, the problem is that it does it one by one instead of several at the same time, being the same code as before, it hangs just at the moment the one that executes the query in the thread, waits until it ends to go to the next one, this means 5 queries = 1 connection (different in each query) = 1 thread executing it (different in each query)
We used the fixed version with the GC issue mentioned in this post https://bugs.ruby-lang.org/issues/19527 where we changed and recompiled the gem as follows:
``` ruby
Before
/IBM_DB_Adapter/ibm_db/ext/ibm_db.c
_ruby_ibm_db_mark_stmt_struct(stmt_handle *handle)
static inline
VALUE ibm_Ruby_Thread_Call(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
{
void *(*f)(void*) = (void *(*)(void*))func;
return (VALUE)rb_thread_call_without_gvl(f, data1, ubf, data2);
}
After
static inline
VALUE ibm_Ruby_Thread_Call(rb_blocking_function_t *func, void *data1, rb_unblock_function_t *ubf, void *data2)
{
+ return func(data1);
}
```
This solved the GC problem, but since it is a method that handles the Threads when it is executed, it makes me believe that this Fix that was made to the method may be causing that when a query is executed it hangs there until that query ends and proceed with another thread/connection/query instead of executing it and leaving it running in the background while it goes to do another thread/connection/query
I made this test code where I do the same as the application on a smaller scale, but the exact same case mentioned above happens, my doubt is the problem will be in this code or in the previous fix:
``` ruby
require 'ibm_db'
require 'active_record'
$control_tables_schema = ""
$db_config = {
adapter: 'ibm_db',
schema: $control_tables_schema,
database: '',
username: '',
password: '',
checkout_timeout: 20,
pool: 20 # number of simultaneous connections
}
conn = nil
condsql = nil
condsql = ["SQL COMMAND",
"SQL COMMAND",
"SQL COMMAND"]
condsql.each do |auxsql|
threads = Thread.new(auxsql) do |command|
conn = ActiveRecord::Base.establish_connection($db_config)
res = nil
conn.with_connection do |connection_cond|
res = connection_cond.execute(auxsql)
end
#puts "************************************"
puts conn.stat
puts conn.connections()
puts owner_thread = Thread.current
puts res
puts "************************************"
#Output looks like this, no errors, just one by one instead of all at the same time
#{:size=>20, :connections=>1, :busy=>0, :dead=>0, :idle=>1, :waiting=>0, :checkout_timeout=>20.0}
#<ActiveRecord::ConnectionAdapters::IBM_DBAdapter:0x00007faf2852d150>
#<Thread:0x00007faf44248b80 test.rb:26 run>
end
threads.join
if conn then
conn.release_connection(owner_thread = Thread.current)
conn.clear_active_connections! rescue nil
conn.clear_stale_cached_connections! rescue nil
end
end
```