require 'sequel' require 'logger' require 'sinatra/base' DB = Sequel.sqlite("test.db") DB.sql_log_level = :debug DB.loggers << Logger.new($stdout) DB.extension :async_thread_pool Sequel::Model.plugin :concurrent_eager_loading # create/recreate tables. DESTROYS ALL DATA. DB.create_table! :foos do primary_key :id String :name end DB.create_table! :bars do primary_key :id foreign_key :foo_id, :foos, on_delete: :cascade String :description end DB.create_table! :fizzes do primary_key :id foreign_key :foo_id, :foos, on_delete: :cascade Integer :counter end DB.create_table! :buzzes do primary_key :id foreign_key :fizz_id, :fizzes, on_delete: :cascade TrueClass :match end # Model definitions class Foo < Sequel::Model (:foos) one_to_many :bars, class: "Bar" one_to_many :fizzes, class: "Fizz" end class Bar < Sequel::Model (:bars) many_to_one :foo, class: "Foo" end class Fizz < Sequel::Model (:fizzes) many_to_one :foo, class: "Foo" one_to_many :buzzes, class: "Buzz" end class Buzz < Sequel::Model (:buzzes) many_to_one :fizz, class: "Fizz" end # plug in some data. foos = ['Andy', 'Jim', 'Tony'].map{|name| Foo.new(name: name).save } bars = [['T1', 'T2'], ['E1', 'E2', 'E3'], ['A', 'B']].each_with_index.map{|for_foo, idx| for_foo.map{|desc| Bar.new(description: desc, foo_id: foos[idx].id).save } } fizzes = [ [11, 12], [21, 22, 23], [31] ].each_with_index.map{|for_foo, idx| foo_id = foos[idx].id for_foo.map{|count| Fizz.new(counter: count, foo_id: foo_id).save } } buzzes = [ [[true, false], [true]], [[], [true], [false]], [[false, false]] ].each_with_index.map{|for_foo, idx| for_foo.each_with_index{|for_fizz, jdx| fizz_id = fizzes[idx][jdx].id for_fizz.map{|matchval| Buzz.new(match: matchval, fizz_id: fizz_id).save } } } # create some sinatra endpoints for testing class ConcApp < Sinatra::Base # this will succeed, and print out data. get '/eager' do foo = Foo.eager(:bars, fizzes: :buzzes).all.first p_foo = CGI.escapeHTML(foo.inspect) p_bars = CGI.escapeHTML(foo.bars.inspect) p_fizzes = CGI.escapeHTML(foo.fizzes.inspect) p_buzzes = CGI.escapeHTML(foo.fizzes.map{|f| f.buzzes}.inspect) "Hello world
#{p_foo}
#{p_bars}
#{p_fizzes}
#{p_buzzes}" end # this will hang after fetching from the :foos table. get '/eager-concurrent' do foo = Foo.eager_load_concurrently.eager(:bars, fizzes: :buzzes).all.first p_foo = CGI.escapeHTML(foo.inspect) p_bars = CGI.escapeHTML(foo.bars.inspect) p_fizzes = CGI.escapeHTML(foo.fizzes.inspect) p_buzzes = CGI.escapeHTML(foo.fizzes.map{|f| f.buzzes}.inspect) "Hello world
#{p_foo}
#{p_bars}
#{p_fizzes}
#{p_buzzes}" end get '/' do foo = Foo.first p_foo = CGI.escapeHTML(foo.inspect) "Hello world\n#{p_foo}" end end run Rack::Cascade.new [ConcApp] if defined?(PhusionPassenger) PhusionPassenger.on_event(:starting_worker_process) do |forked| if forked # We're in smart spawning mode; behave nice. puts "DEBUG: Passenger forked spawning" DB.disconnect else # We're in conservative spawning mode. We don't need to do anything. end end end