Make Cequel.uuid thread safe and fork safe #422
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Cequel.uuid
uses a memoized instance ofCassandra::TimeUuid::Generator
which means it will be shared between threads, butCassandra::TimeUuid::Generator
is not thread safe. This could lead to duplicate UUIDs under a race condition. Cassandra's "upsert" behavior would mean duplicates would likely go undetected, and could lead to things like separate users sharing a record in the database. This race condition was difficult to reproduce on MRI, so it may be fairly rare, but is nevertheless possible.A similar issue exists between a parent process and forked child processes, which would have different generator instances, but sharing the same internal state, so duplicate UUIDs are also possible. These race conditions are easy to reproduce, but would only arise if the parent process called
Cequel.uuid
before forking.This PR addresses the thread safety issue by storing thread local instances of
Cassandra::TimeUuid::Generator
and addresses the fork safety issue by clearing the thread local instance when a PID change is detected. Note that on Linux detecting forking by checkingProcess.pid
carries some overhead, but seems worth it to ensure safety.Included below are some scripts to demonstrate the issues and benchmark the proposed solution.
threaded_cequel_uuid_tester.rb
forking_cequel_uuid_tester.rb
benchmark_uuid_generation.rb
Results: