pools: lock pool when adding/removing posts (fixes #3091).
Adding a post id to a pool's post_ids string is non-atomic, hence we must lock the pool to avoid a race condition. Adding a pool to a post's pool_string is likewise non-atomic, hence we must lock the post as well.
This commit is contained in:
@@ -246,9 +246,11 @@ class Pool < ActiveRecord::Base
|
|||||||
return if contains?(post.id)
|
return if contains?(post.id)
|
||||||
return if is_deleted?
|
return if is_deleted?
|
||||||
|
|
||||||
update_attributes(:post_ids => add_number_to_string(post.id, post_ids), :post_count => post_count + 1)
|
with_lock do
|
||||||
post.add_pool!(self, true)
|
update_attributes(:post_ids => add_number_to_string(post.id, post_ids), :post_count => post_count + 1)
|
||||||
clear_post_id_array
|
post.add_pool!(self, true)
|
||||||
|
clear_post_id_array
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove!(post)
|
def remove!(post)
|
||||||
@@ -256,9 +258,11 @@ class Pool < ActiveRecord::Base
|
|||||||
return unless CurrentUser.user.can_remove_from_pools?
|
return unless CurrentUser.user.can_remove_from_pools?
|
||||||
return if is_deleted?
|
return if is_deleted?
|
||||||
|
|
||||||
update_attributes(:post_ids => remove_number_from_string(post.id, post_ids), :post_count => post_count - 1)
|
with_lock do
|
||||||
post.remove_pool!(self, true)
|
update_attributes(:post_ids => remove_number_from_string(post.id, post_ids), :post_count => post_count - 1)
|
||||||
clear_post_id_array
|
post.remove_pool!(self, true)
|
||||||
|
clear_post_id_array
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_number_to_string(number, string)
|
def add_number_to_string(number, string)
|
||||||
|
|||||||
@@ -1042,22 +1042,26 @@ class Post < ActiveRecord::Base
|
|||||||
def add_pool!(pool, force = false)
|
def add_pool!(pool, force = false)
|
||||||
return if belongs_to_pool?(pool)
|
return if belongs_to_pool?(pool)
|
||||||
return if pool.is_deleted? && !force
|
return if pool.is_deleted? && !force
|
||||||
reload
|
|
||||||
self.pool_string = "#{pool_string} pool:#{pool.id}".strip
|
with_lock do
|
||||||
set_pool_category_pseudo_tags
|
self.pool_string = "#{pool_string} pool:#{pool.id}".strip
|
||||||
update_column(:pool_string, pool_string) unless new_record?
|
set_pool_category_pseudo_tags
|
||||||
pool.add!(self)
|
update_column(:pool_string, pool_string) unless new_record?
|
||||||
|
pool.add!(self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_pool!(pool, force = false)
|
def remove_pool!(pool, force = false)
|
||||||
return unless belongs_to_pool?(pool)
|
return unless belongs_to_pool?(pool)
|
||||||
return unless CurrentUser.user.can_remove_from_pools?
|
return unless CurrentUser.user.can_remove_from_pools?
|
||||||
return if pool.is_deleted? && !force
|
return if pool.is_deleted? && !force
|
||||||
reload
|
|
||||||
self.pool_string = pool_string.gsub(/(?:\A| )pool:#{pool.id}(?:\Z| )/, " ").strip
|
with_lock do
|
||||||
set_pool_category_pseudo_tags
|
self.pool_string = pool_string.gsub(/(?:\A| )pool:#{pool.id}(?:\Z| )/, " ").strip
|
||||||
update_column(:pool_string, pool_string) unless new_record?
|
set_pool_category_pseudo_tags
|
||||||
pool.remove!(self)
|
update_column(:pool_string, pool_string) unless new_record?
|
||||||
|
pool.remove!(self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_from_all_pools
|
def remove_from_all_pools
|
||||||
|
|||||||
Reference in New Issue
Block a user