-
Notifications
You must be signed in to change notification settings - Fork 15.4k
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
Ruby: Refactor the object cache to better account for race conditions #13075
Conversation
e127b5b
to
bd19a22
Compare
74dd06f
to
bcd2cfd
Compare
How do we validate that there is no performance regression? I think the relevant benchmark would be something like: msg = FooMessage()
# Read benchmark
msg.submsg = BarMessage()
1000000.times {
msg.submsg
}
# Write benchmark
1000000.times {
msg.submsg = BarMessage()
msg.submsg
} |
Superseeds: protocolbuffers#13054 The object cache is fundamentally subject to race conditions. Objects must be created before they are registered into the cache, so if two threads try to create the same object, we'll inevitably end up with two instances mapping to the same underlying memory. To entirely prevent that we'd need a lot of extra locking which I don't think is really worth it compared to a few useless allocations. Instead we can replace `ObjectCache_Add` by a `getset` type of operation, the extra instance is still created, but the later threads will receive the "canonical" instance and will be able to abandon their duplicated instance. Additionally, this PR moves the ObjectCache implementation in Ruby, as it's much easier to debug there, and the performance difference is negligible. The `ObjectCache` instance is also exposed as `Google::Protobuf::OBJECT_CACHE` to better allow to debug potential memory issues.
bcd2cfd
to
cf2bbc3
Compare
So, note that there will necessarily be one. We're adding an extra method call on the fast path, and extra locking on the slow path. That said I'm extremely unfamiliar with protobuf, and I never used it (it's a transitive dependency of various Google Cloud gems), so I'd appreciate if one of you could take this over, as it would be faster than doing back and forth. I mostly opened this PR as to show a proof of concept. |
Casper, thanks for providing it! I will take this over. |
Superseeds: #13054
The object cache is fundamentally subject to race conditions. Objects must be created before they are registered into the cache, so if two threads try to create the same object, we'll inevitably end up with two instances mapping to the same underlying memory.
To entirely prevent that we'd need a lot of extra locking which I don't think is really worth it compared to a few useless allocations.
Instead we can replace
ObjectCache_Add
by agetset
type of operation, the extra instance is still created, but the later threads will receive the "canonical" instance and will be able to abandon their duplicated instance.Additionally, this PR moves the ObjectCache implementation in Ruby, as it's much easier to debug there, and the performance difference is negligible. The
ObjectCache
instance is also exposed asGoogle::Protobuf::OBJECT_CACHE
to better allow to debug potential memory issues.cc @haberman @fowles