-
Notifications
You must be signed in to change notification settings - Fork 367
Make database cleaner active record seeded deletion start/clean more threadsafe #9672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,12 +1,18 @@ | ||||||||
| require 'database_cleaner-active_record' | ||||||||
| require 'thread' | ||||||||
|
|
||||||||
| module DatabaseCleaner | ||||||||
| module ActiveRecord | ||||||||
| # SeededDeletion is a strategy that deletes all records from tables except those that existed before it was instantiated | ||||||||
| # This is useful for tests that need the seeded data to be present. | ||||||||
| class SeededDeletion < Deletion | ||||||||
| # Class level mutex for thread safety around start/clean actions. | ||||||||
| @mutex = Mutex.new | ||||||||
|
|
||||||||
| def clean | ||||||||
| connection.transaction(:requires_new => true) do | ||||||||
| # Use a transaction isolation to prevent other threads | ||||||||
| # from modifying the tables during deletion | ||||||||
| connection.transaction(:requires_new => true, :isolation => :read_committed) do | ||||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Switched to read_committed... it seems to prevent the errors we were seeing locally. |
||||||||
| super | ||||||||
| end | ||||||||
| end | ||||||||
|
|
@@ -17,12 +23,14 @@ def start | |||||||
| end | ||||||||
|
|
||||||||
| def self.table_max_id_cache | ||||||||
| @table_max_id_cache ||= {} | ||||||||
| # wrap the cache initialization in a mutex to ensure thread safety | ||||||||
| @mutex.synchronize { @table_max_id_cache ||= {} } | ||||||||
| end | ||||||||
|
|
||||||||
| # Memoize the maximum ID for each class table with non-zero number of rows | ||||||||
| def self.table_max_id_cache=(table_id_hash) | ||||||||
| @table_max_id_cache ||= table_id_hash | ||||||||
| @mutex.synchronize do | ||||||||
| @table_max_id_cache = table_id_hash | ||||||||
Fryguy marked this conversation as resolved.
Show resolved
Hide resolved
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be cleaner as
Suggested change
The reason is that if anyone has a reference to the "old" hash from the getter, then this would update that existing reference instead of creating a new one. Not a huge deal, but is a little safer. |
||||||||
| end | ||||||||
| end | ||||||||
|
|
||||||||
| delegate :table_max_id_cache, to: :class | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in is this file are reverts of #9684