On Thursday, January 29, 2015 at 11:38:35 AM UTC-8, Nels Nelson wrote:
>
> I have a relationship on a model class defined in this way:
>
> create_table :tag do
> primary_key :id
> index :name
> String :name, :unique => true, :null => false
> end
>
> class Tag < Sequel::Model
> end
>
> create_table :tagged do
> primary_key :id
> foreign_key :thing_id, :thing, :on_delete => :cascade
> foreign_key :tag_id, :tag, :on_delete => :cascade
> end
>
> class Tagged < Sequel::Model
> end
>
> create_table :thing do
> primary_key :id
> foreign_key :parent_id, : thing, :on_delete => :set_null
> index :name
> String :name, :text => true
> String :thing_type, :null => false
> end
>
> class Thing < Sequel::Model
> plugin :rcte_tree
> plugin :single_table_inheritance, :thing_type
> one_to_many :tagged, :key => :thing_id
> many_to_many :tags, :class => 'Tag', :join_table => :tagged, :left_key
> => :thing_id, :right_key => :tag_id
> end
>
>
> My environment looks like this:
>
> $ java -version
> java version "1.6.0_65"
> Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462)
> Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)
> $ uname -a
> Darwin sol.local 14.0.0 Darwin Kernel Version 14.0.0: Fri Sep 19 00:26:44
> PDT 2014; root:xnu-2782.1.97~2/RELEASE_X86_64 x86_64
> $ jruby --version
> jruby 1.7.16 (1.9.3p392) 2014-09-25 575b395 on Java HotSpot(TM) 64-Bit
> Server VM 1.6.0_65-b14-462 +jit [darwin-x86_64]
> $ jgem list sequel
>
>
> *** LOCAL GEMS ***
>
>
> sequel (4.15.0)
>
>
> When running in a multi-threaded environment, occasionally, this happens:
>
> o = Thing.new(name: 'test')
> o.tags << Tag.new(name: 'alpha')
> o.tags << Tag.new(name: 'beta')
>
> 10000.times do
> # This is dumb, and probably wouldn't actually work, it's just an
> illustration
> Thread.new do
> thing = Thing.find(id: 1)
>
> # Almost always:
> some_tags = thing.tags #=> [ #<Tag:0x1c:14>, #<Tag:0x1d:15> ]
>
> # But every once in a while:
> some_tags = thing.tags #=> nil
> end
> end
>
This sounds like a race condition. Unfortunately, I'm unable to replicate.
Here's the code I used:
DB.create_table :tags do
primary_key :id
index :name
String :name, :unique => true, :null => false
end
DB.create_table :things do
primary_key :id
foreign_key :parent_id, :things, :on_delete => :set_null
index :name
String :name, :text => true
String :thing_type, :null => false
end
DB.create_table :taggings do
primary_key :id
foreign_key :thing_id, :things, :on_delete => :cascade
foreign_key :tag_id, :tags, :on_delete => :cascade
end
class Tag < Sequel::Model
end
class Tagging < Sequel::Model
end
class Thing < Sequel::Model
plugin :rcte_tree
plugin :single_table_inheritance, :thing_type
one_to_many :tagged, :key => :thing_id
many_to_many :tags, :class => 'Tag', :join_table => :taggings, :left_key
=> :thing_id, :right_key => :tag_id
end
o = Thing.create(name: 'test')
o.add_tag(Tag.create(name: 'alpha'))
o.add_tag(Tag.create(name: 'beta'))
100.times do |i|
puts "starting pass #{i+1}"
threads = []
1000.times do
threads << Thread.new do
raise unless Thing.find(id: 1).tags
end
end
threads.each{|t| t.join}
end
This doesn't create 10,000 threads at the same time, as I ran into pool
timeouts with the default settings when trying that in my environment,
which is:
jruby 1.7.6 (1.9.3p392) 2013-10-22 6004147 on Java HotSpot(TM) 64-Bit
Server VM 1.7.0_07-b10 [Windows 7-amd64]
With max_connections at 50 and pool_timeout at 120, I was able to get 10000
threads working, and still was not able to reproduce, using the following
loop:
10.times do |i|
puts "starting pass #{i+1}"
threads = []
10000.times do
threads << Thread.new do
raise unless Thing.find(id: 1).tags
end
end
threads.each{|t| t.join}
end
That's not to say there isn't a race condition, but it must be very hard to
hit. Could you try adding the :instance_specific => true option when
defining the tags association and see if the problem still occurs? If the
problem goes away, I can better focus the search for the underlying issue.
Note that I could easily see this issue happening if you have multiple
threads operating on the same model instance. That's not what your example
code shows, though, since it is returning a new instance inside each
thread. But if you have multiple threads operating on a single model
instance, all bets are off, as mentioned
in
http://sequel.jeremyevans.net/rdoc/files/doc/thread_safety_rdoc.html#label-Exceptions.
Thanks,
Jeremy
--
You received this message because you are subscribed to the Google Groups
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.