Skip to content

Reactor dies unexpectedly #22

@avalanche123

Description

@avalanche123

after modifying io_reactor.rb by adding the following on line 136:

rescue => e
  puts "#{e.class.name}: #{e.message}\n" + Array(e.backtrace).join("\n")

I get the following error:

TypeError: can't convert Ione::Io::Connection to IO (Ione::Io::Connection#to_io gives NilClass)
/home/kishan/.rvm/gems/ruby-1.9.3-p547@global/gems/ione-1.2.0/lib/ione/io/io_reactor.rb:396:in `select'
/home/kishan/.rvm/gems/ruby-1.9.3-p547@global/gems/ione-1.2.0/lib/ione/io/io_reactor.rb:396:in `tick'
/home/kishan/.rvm/gems/ruby-1.9.3-p547@global/gems/ione-1.2.0/lib/ione/io/io_reactor.rb:133:in `block in start'
integration/test.rb:38:in `join': deadlock detected (fatal)
    from integration/test.rb:38:in `block in create_sessions_concurrently2'
    from integration/test.rb:38:in `each'
    from integration/test.rb:38:in `create_sessions_concurrently2'
    from integration/test.rb:15:in `run_test'
    from integration/test.rb:61:in `<main>'

The issue is that the connections are created and closed from different threads, here is a trimmed down sample that consistently fails on linux, while passing on OS X:

require 'bundler/setup'
require 'cassandra'
require 'cassandra/version'

puts Cassandra::VERSION

class Test
  def run_test
    cluster_list = []
    cluster_list << Cassandra.cluster

    session_list = create_sessions_concurrently2(cluster_list[0], 1)
    p session_list
    session_list = close_sessions_concurrently2(session_list, 1)
    p session_list

    session_list2 = create_sessions_concurrently2(cluster_list[0], 1) # DEADLOCK HERE
    p session_list2

    session_list = close_sessions_concurrently2(session_list2, 1)
    p session_list
    cluster_list[0].close
  end

  def create_sessions_concurrently2(cluster, num_sessions)
    sessions = []
    threads = (1..num_sessions).map do
      Thread.new do
        begin
          session = cluster.connect
          sessions << session
        rescue Exception => e
          # session.close
          raise RuntimeError.new("Error while creating a session. #{e.class.name}: #{e.message}
                                          Backtrace: #{e.backtrace.inspect}")
        end
      end
    end

    threads.each {|th| th.join} # DEADLOCK HERE
    sessions
  end

  def close_sessions_concurrently2(session_list, num_sessions)
    session_list2 = session_list[0...num_sessions]
    threads = session_list2.map do |session|
      Thread.new do
        begin
          session.close
          session_list.delete(session)
        rescue Exception => e
          raise RuntimeError.new("Error while closing a session. #{e.class.name}: #{e.message}
                                  Backtrace: #{e.backtrace.inspect}")
        end
      end
    end

    threads.each {|th| th.join}
    session_list
  end
end

Test.new.run_test

I believe there is a race between close and connected? that causes a closing socket to be added to the poll list.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions