Project

General

Profile

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 
 ``` 

Back