ruby/bootstraptest
John Hawthorn 57b6a7503f Lock-free hash set for fstrings [Feature #21268]
This implements a hash set which is wait-free for lookup and lock-free
for insert (unless resizing) to use for fstring de-duplication.

As highlighted in https://bugs.ruby-lang.org/issues/19288, heavy use of
fstrings (frozen interned strings) can significantly reduce the
parallelism of Ractors.

I tried a few other approaches first: using an RWLock, striping a series
of RWlocks (partitioning the hash N-ways to reduce lock contention), and
putting a cache in front of it. All of these improved the situation, but
were unsatisfying as all still required locks for writes (and granular
locks are awkward, since we run the risk of needing to reach a vm
barrier) and this table is somewhat write-heavy.

My main reference for this was Cliff Click's talk on a lock free
hash-table for java https://www.youtube.com/watch?v=HJ-719EGIts. It
turns out this lock-free hash set is made easier to implement by a few
properties:

 * We only need a hash set rather than a hash table (we only need keys,
   not values), and so the full entry can be written as a single VALUE
 * As a set we only need lookup/insert/delete, no update
 * Delete is only run inside GC so does not need to be atomic (It could
   be made concurrent)
 * I use rb_vm_barrier for the (rare) table rebuilds (It could be made
   concurrent) We VM lock (but don't require other threads to stop) for
   table rebuilds, as those are rare
 * The conservative garbage collector makes deferred replication easy,
   using a T_DATA object

Another benefits of having a table specific to fstrings is that we
compare by value on lookup/insert, but by identity on delete, as we only
want to remove the exact string which is being freed. This is faster and
provides a second way to avoid the race condition in
https://bugs.ruby-lang.org/issues/21172.

This is a pretty standard open-addressing hash table with quadratic
probing. Similar to our existing st_table or id_table. Deletes (which
happen on GC) replace existing keys with a tombstone, which is the only
type of update which can occur. Tombstones are only cleared out on
resize.

Unlike st_table, the VALUEs are stored in the hash table itself
(st_table's bins) rather than as a compact index. This avoids an extra
pointer dereference and is possible because we don't need to preserve
insertion order. The table targets a load factor of 2 (it is enlarged
once it is half full).
2025-04-18 13:03:54 +09:00
..
pending.rb Moved already resolved test 2020-04-27 10:39:07 +09:00
runner.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_attr.rb Revert "Revert "This commit implements the Object Shapes technique in CRuby."" 2022-10-11 08:40:56 -07:00
test_autoload.rb Use File.write instead of Kernel#open 2024-07-09 13:01:44 +09:00
test_block.rb
test_class.rb
test_constant_cache.rb Finer-grained constant cache invalidation (take 2) 2022-04-01 14:48:22 -04:00
test_env.rb fallback env encoding to ASCII-8BIT 2018-09-26 17:24:00 +00:00
test_eval.rb Raise a compile error for break/next/redo inside eval in cases where it is optimized away 2024-09-18 16:54:56 -07:00
test_exception.rb Do not include a backtick in error messages and backtraces 2024-02-15 18:42:31 +09:00
test_fiber.rb support concurrent btest execution 2022-02-06 03:05:47 +09:00
test_finalizer.rb Test finalizer is ran in bootstraptest 2024-04-01 10:26:16 -04:00
test_flip.rb
test_flow.rb Ensure test suite is compatible with --frozen-string-literal 2024-03-14 17:56:15 +01:00
test_fork.rb Fail test if child process exists non-zero 2025-03-25 19:14:26 -07:00
test_gc.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_insns.rb Optimize instructions when creating an array just to call include? (#12123) 2024-11-26 14:31:08 -05:00
test_io.rb Use File.write instead of Kernel#open 2024-07-09 13:01:44 +09:00
test_jump.rb Ensure test suite is compatible with --frozen-string-literal 2024-03-14 17:56:15 +01:00
test_literal.rb Avoid array allocation for *nil, by not calling nil.to_a 2025-03-27 11:17:40 -07:00
test_literal_suffix.rb [PRISM] Enhance syntax error message extraction in test_literal_suffix btest 2024-04-03 17:34:12 -04:00
test_load.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_marshal.rb
test_massign.rb
test_method.rb Fix assertion failure with anonymous splats 2025-04-02 19:31:05 -07:00
test_objectspace.rb Use a monotonically increasing number for object_id 2019-11-07 09:31:07 -08:00
test_proc.rb Make proc/Proc.new without block an error instead of warning 2020-06-10 17:49:54 -07:00
test_ractor.rb Lock-free hash set for fstrings [Feature #21268] 2025-04-18 13:03:54 +09:00
test_string.rb
test_struct.rb
test_syntax.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_thread.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_yjit.rb [Feature #21116] Extract RJIT as a third-party gem 2025-02-13 18:01:03 +09:00
test_yjit_30k_ifelse.rb * append newline at EOF. [ci skip] 2021-10-21 08:12:53 +09:00
test_yjit_30k_methods.rb * append newline at EOF. [ci skip] 2021-10-21 08:12:53 +09:00
test_yjit_rust_port.rb Rust YJIT 2022-04-27 11:00:22 -04:00