pstore icon indicating copy to clipboard operation
pstore copied to clipboard

Fix Ractor IsolationError with file and thread safety enabled

Open bkuhlmann opened this issue 8 months ago • 1 comments

Why

Hello. :wave: With the release of Version 0.2.0, especially this commit, you'll now get a Ractor::IsolationError when writing data.

How

Here's the quickest way I could reproduce this:

#! /usr/bin/env ruby
# frozen_string_literal: true

# Save as `demo`, then `chmod 755 demo`, and run as `./demo`.

require "bundler/inline"

gemfile true do
  source "https://rubygems.org"

  gem "amazing_print"
  gem "debug"
  gem "lode"
  gem "milestoner"
end

client = Lode.new "demo.store" do |config|
  config.mode = :max
  config.table = Lode::Tables::Value
  config.register :users, model: Milestoner::Models::User, primary_key: :name
end

creator = Milestoner::CLI::Actions::Cache::Create.new(client:)
creator.call "1,zoe,Zoë Washburne"

The above will produce this error:

Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
<internal:ractor>:832:in 'Ractor.make_shareable': Proc's self is not shareable: #<Proc:0x0000000160ea17d8 /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/pstore-0.2.0/lib/pstore.rb:673> (Ractor::IsolationError)
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/pstore-0.2.0/lib/pstore.rb:676:in 'PStore#on_windows?'
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/pstore-0.2.0/lib/pstore.rb:685:in 'PStore#save_data'
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/pstore-0.2.0/lib/pstore.rb:575:in 'PStore#transaction'
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/lode-2.2.0/lib/lode/client.rb:34:in 'Lode::Client#transact'
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/lode-2.2.0/lib/lode/client.rb:27:in 'Lode::Client#write'
	from /Users/bkuhlmann/.cache/frum/versions/3.4.2/lib/ruby/gems/3.4.0/gems/milestoner-19.3.0/lib/milestoner/cli/actions/cache/create.rb:23:in 'Milestoner::CLI::Actions::Cache::Create#call'
	from /Users/bkuhlmann/Engineering/Misc/demo:23:in '<main>'

The Lode gem is monadic wrapper around PStore so if you remove config.mode = :max. The issue goes away. The max mode simply wraps PStore's native functionality of ultra_safe = true. In other words, this is equivalent to:

PStore.new("demo.store", true).tap { it.ultra_safe = true }

So you can't use PStore with thread and file safety at the same time anymore?

Notes

If this line is removed, the issue goes away.

bkuhlmann avatar Apr 12 '25 18:04 bkuhlmann

I'm having this same exact issue. I'm also literally on linux, so getting this error is especially weird.

I'd be happy to submit a PR to fix this, but I'm not sure if I'm missing something because I have no idea why this change was made.. I haven't really used ractors personally, so I'm hoping someone could clarify how the function previously had a ractor compliance issue and why it was implemented this way.

In particular, I'm wondering how thread-safety was a concern on value that can never change. After all, the constant RUBY_PLATFORM is compiled into ruby and is pre-frozen. And the boolean result of the comparison is immutable.

Wouldn't it make more sense to get rid of the instance method and define this as a (perhaps memoized) class method? I imagine its being defined dynamically at runtime for performance reasons, but if performance is the issue, perhaps it'd be best to get rid of the method altogether and simply define the value as a constant (or instance variable, computed once in the initializer, if there's a desire to not evaluate the condition until it is needed)?

Anyway, I'm happy to help if someone can point me in the right direction.

Thanks in advance!

Note: Updated because I initially misread #on_windows? as defining a singleton method.

mvastola avatar Sep 15 '25 05:09 mvastola