farce 0.0.1.alpha2-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1524 -0
- data/SECURITY.md +10 -0
- data/docs/benchmarks.md +185 -0
- data/docs/gems/dry-types.md +290 -0
- data/docs/gems/msgpack.md +70 -0
- data/docs/gems/ractor-shim.md +63 -0
- data/docs/modes.md +628 -0
- data/docs/scopes.md +649 -0
- data/docs/variants.md +346 -0
- data/ext/ext_helper.rb +20 -0
- data/ext/farce/README.md +21 -0
- data/ext/farce/atom.c +1023 -0
- data/ext/farce/bounded_map.c +1683 -0
- data/ext/farce/containers.h +77 -0
- data/ext/farce/counter.c +399 -0
- data/ext/farce/darwin.c +100 -0
- data/ext/farce/depend +12 -0
- data/ext/farce/dict.c +1523 -0
- data/ext/farce/dict.h +152 -0
- data/ext/farce/drivers.c +237 -0
- data/ext/farce/exchanger.c +299 -0
- data/ext/farce/extconf.rb +99 -0
- data/ext/farce/farce.c +359 -0
- data/ext/farce/flag.c +288 -0
- data/ext/farce/io.c +338 -0
- data/ext/farce/lock.c +510 -0
- data/ext/farce/map.c +2240 -0
- data/ext/farce/priority_queue.c +2056 -0
- data/ext/farce/queue.c +1059 -0
- data/ext/farce/reactor.c +820 -0
- data/ext/farce/reactor.h +103 -0
- data/ext/farce/shareable.h +31 -0
- data/ext/farce/signal.c +350 -0
- data/ext/farce/transaction.c +354 -0
- data/ext/farce/transaction.h +40 -0
- data/ext/farce/tree_map.c +1953 -0
- data/ext/farce/trie.c +2020 -0
- data/ext/farce/unshareable.c +155 -0
- data/ext/farce/unshared_io_pool.h +234 -0
- data/ext/farce/unshared_signal.c +263 -0
- data/ext/farce/unshared_wait.h +193 -0
- data/ext/farce/unsupported.c +6 -0
- data/ext/farce/vector.c +1195 -0
- data/ext/farce/weak_map.c +1714 -0
- data/ext/java/org/farce/BoundedMap.java +394 -0
- data/ext/java/org/farce/FiberScheduler.java +141 -0
- data/ext/java/org/farce/PriorityKey.java +45 -0
- data/ext/java/org/farce/PriorityQueue.java +373 -0
- data/ext/java/org/farce/QueueSignal.java +28 -0
- data/ext/rebind/README.md +14 -0
- data/ext/rebind/extconf.rb +10 -0
- data/ext/rebind/rebind.c +186 -0
- data/lib/farce/_yard/internal.rb +13 -0
- data/lib/farce/_yard/macros.rb +61 -0
- data/lib/farce/_yard/ractor.rb +46 -0
- data/lib/farce/abstract/atom.rb +186 -0
- data/lib/farce/abstract/bounded_map.rb +232 -0
- data/lib/farce/abstract/collection.rb +151 -0
- data/lib/farce/abstract/concurrent_map.rb +381 -0
- data/lib/farce/abstract/counter.rb +193 -0
- data/lib/farce/abstract/duplicable_map.rb +229 -0
- data/lib/farce/abstract/exchanger.rb +26 -0
- data/lib/farce/abstract/flag.rb +71 -0
- data/lib/farce/abstract/lazy.rb +115 -0
- data/lib/farce/abstract/lease.rb +104 -0
- data/lib/farce/abstract/lease_map.rb +261 -0
- data/lib/farce/abstract/lease_pool.rb +91 -0
- data/lib/farce/abstract/lfu_map.rb +20 -0
- data/lib/farce/abstract/lru_map.rb +25 -0
- data/lib/farce/abstract/map.rb +345 -0
- data/lib/farce/abstract/molecule.rb +245 -0
- data/lib/farce/abstract/port.rb +74 -0
- data/lib/farce/abstract/priority_queue.rb +117 -0
- data/lib/farce/abstract/queue.rb +269 -0
- data/lib/farce/abstract/scheduler.rb +111 -0
- data/lib/farce/abstract/set.rb +910 -0
- data/lib/farce/abstract/sorted_set.rb +172 -0
- data/lib/farce/abstract/timer_queue.rb +136 -0
- data/lib/farce/abstract/tree_map.rb +269 -0
- data/lib/farce/abstract/value.rb +68 -0
- data/lib/farce/abstract/vector.rb +1126 -0
- data/lib/farce/abstract/weak_atom.rb +32 -0
- data/lib/farce/abstract/weak_key_map.rb +12 -0
- data/lib/farce/abstract/weak_map.rb +13 -0
- data/lib/farce/abstract/weak_set.rb +12 -0
- data/lib/farce/abstract/weak_value_map.rb +12 -0
- data/lib/farce/abstract.rb +17 -0
- data/lib/farce/atom.rb +293 -0
- data/lib/farce/class_mirror.rb +87 -0
- data/lib/farce/clock.rb +121 -0
- data/lib/farce/config.rb +229 -0
- data/lib/farce/counter.rb +71 -0
- data/lib/farce/deduper.rb +122 -0
- data/lib/farce/engine/jruby/bounded_map.rb +314 -0
- data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
- data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
- data/lib/farce/engine/jruby/map.rb +505 -0
- data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
- data/lib/farce/engine/jruby/signal.rb +147 -0
- data/lib/farce/engine/jruby.rb +63 -0
- data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
- data/lib/farce/engine/jvm/counter.rb +102 -0
- data/lib/farce/engine/jvm/extension.rb +32 -0
- data/lib/farce/engine/jvm/farce.jar +0 -0
- data/lib/farce/engine/jvm/flag.rb +79 -0
- data/lib/farce/engine/jvm/priority_queue.rb +217 -0
- data/lib/farce/engine/jvm/tree_map.rb +350 -0
- data/lib/farce/engine/jvm/types.rb +180 -0
- data/lib/farce/engine/jvm.rb +19 -0
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
- data/lib/farce/engine/ruby/3.4/port.rb +186 -0
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
- data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
- data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/port.rb +19 -0
- data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
- data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
- data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
- data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
- data/lib/farce/engine/ruby/4.1/port.rb +21 -0
- data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
- data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
- data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
- data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
- data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
- data/lib/farce/engine/ruby/shared/lease.rb +26 -0
- data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
- data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
- data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
- data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
- data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
- data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
- data/lib/farce/engine/ruby/shared/vault.rb +144 -0
- data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
- data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
- data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
- data/lib/farce/engine/ruby.rb +130 -0
- data/lib/farce/engine/shared/atom.rb +10 -0
- data/lib/farce/engine/shared/exchanger.rb +130 -0
- data/lib/farce/engine/shared/identity_key.rb +22 -0
- data/lib/farce/engine/shared/lease.rb +10 -0
- data/lib/farce/engine/shared/lease_pool.rb +10 -0
- data/lib/farce/engine/shared/main_scheduler.rb +20 -0
- data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
- data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/shared/port.rb +44 -0
- data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
- data/lib/farce/engine/shared/proxy_owner.rb +43 -0
- data/lib/farce/engine/shared/queue.rb +233 -0
- data/lib/farce/engine/shared/ractor_methods.rb +73 -0
- data/lib/farce/engine/shared/rebindable.rb +15 -0
- data/lib/farce/engine/shared/strict_atom.rb +73 -0
- data/lib/farce/engine/shared/strict_map.rb +117 -0
- data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
- data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
- data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
- data/lib/farce/engine/shared/trie.rb +317 -0
- data/lib/farce/engine/shared/trie_builder.rb +199 -0
- data/lib/farce/engine/shared/unshareable.rb +14 -0
- data/lib/farce/engine/shared/unshared_atom.rb +256 -0
- data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
- data/lib/farce/engine/shared/unshared_queue.rb +18 -0
- data/lib/farce/engine/shared/unshared_signal.rb +21 -0
- data/lib/farce/engine/shared/unshared_vector.rb +377 -0
- data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
- data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
- data/lib/farce/engine/shared/vault.rb +31 -0
- data/lib/farce/engine/shared/vector.rb +83 -0
- data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
- data/lib/farce/engine/shared/weak_atom.rb +20 -0
- data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
- data/lib/farce/engine/shared/weak_map/index.rb +249 -0
- data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
- data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
- data/lib/farce/engine/shared.rb +63 -0
- data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
- data/lib/farce/engine/truffleruby/lock.rb +121 -0
- data/lib/farce/engine/truffleruby/map.rb +656 -0
- data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
- data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
- data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
- data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
- data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
- data/lib/farce/engine/truffleruby/signal.rb +77 -0
- data/lib/farce/engine/truffleruby.rb +148 -0
- data/lib/farce/envelope.rb +335 -0
- data/lib/farce/error.rb +35 -0
- data/lib/farce/exchanger.rb +41 -0
- data/lib/farce/flag.rb +27 -0
- data/lib/farce/integrations/active_support/blank.rb +68 -0
- data/lib/farce/integrations/active_support/clock.rb +17 -0
- data/lib/farce/integrations/active_support/duplicable.rb +78 -0
- data/lib/farce/integrations/active_support/map.rb +175 -0
- data/lib/farce/integrations/active_support/set.rb +60 -0
- data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
- data/lib/farce/integrations/active_support/vector.rb +231 -0
- data/lib/farce/integrations/active_support.rb +9 -0
- data/lib/farce/integrations/activesupport.rb +5 -0
- data/lib/farce/integrations/bson.rb +108 -0
- data/lib/farce/integrations/cbor.rb +51 -0
- data/lib/farce/integrations/concurrent.rb +112 -0
- data/lib/farce/integrations/dry-types.rb +5 -0
- data/lib/farce/integrations/dry_types.rb +694 -0
- data/lib/farce/integrations/json.rb +7 -0
- data/lib/farce/integrations/msgpack.rb +112 -0
- data/lib/farce/integrations/oj.rb +69 -0
- data/lib/farce/integrations/psych.rb +191 -0
- data/lib/farce/integrations/ractor-sharing.rb +5 -0
- data/lib/farce/integrations/ractor-tmvar.rb +5 -0
- data/lib/farce/integrations/ractor_sharing.rb +172 -0
- data/lib/farce/integrations/ractor_tmvar.rb +64 -0
- data/lib/farce/integrations/shared/to_json.rb +42 -0
- data/lib/farce/integrations/sorted_set.rb +11 -0
- data/lib/farce/integrations/weakref.rb +38 -0
- data/lib/farce/integrations/yajl.rb +10 -0
- data/lib/farce/integrations.rb +156 -0
- data/lib/farce/internal/_frozen_config.rb +11 -0
- data/lib/farce/internal/autoloads.rb +47 -0
- data/lib/farce/internal/blocking_priority_queue.rb +122 -0
- data/lib/farce/internal/converter.rb +106 -0
- data/lib/farce/internal/copyable.rb +31 -0
- data/lib/farce/internal/delegation.rb +20 -0
- data/lib/farce/internal/external_transaction.rb +59 -0
- data/lib/farce/internal/fake_ractor.rb +179 -0
- data/lib/farce/internal/freeze.rb +118 -0
- data/lib/farce/internal/inspect.rb +157 -0
- data/lib/farce/internal/key_lock_map.rb +29 -0
- data/lib/farce/internal/key_normalizer.rb +289 -0
- data/lib/farce/internal/lease_initialization.rb +115 -0
- data/lib/farce/internal/lease_map.rb +441 -0
- data/lib/farce/internal/lease_pool_state.rb +228 -0
- data/lib/farce/internal/lease_state.rb +342 -0
- data/lib/farce/internal/lease_waiting.rb +13 -0
- data/lib/farce/internal/managed_queue.rb +26 -0
- data/lib/farce/internal/map_value_modes.rb +227 -0
- data/lib/farce/internal/marshal_support.rb +227 -0
- data/lib/farce/internal/mixin.rb +20 -0
- data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
- data/lib/farce/internal/noncopyable.rb +17 -0
- data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
- data/lib/farce/internal/pool_supervisor.rb +41 -0
- data/lib/farce/internal/pool_worker.rb +61 -0
- data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
- data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
- data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
- data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
- data/lib/farce/internal/portable_transaction.rb +164 -0
- data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
- data/lib/farce/internal/reservation_waiting.rb +24 -0
- data/lib/farce/internal/scheduled_task.rb +48 -0
- data/lib/farce/internal/scheduler_io.rb +171 -0
- data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
- data/lib/farce/internal/select_scheduler.rb +235 -0
- data/lib/farce/internal/storage.rb +162 -0
- data/lib/farce/internal/strict_lease.rb +30 -0
- data/lib/farce/internal/strict_lease_map.rb +20 -0
- data/lib/farce/internal/strict_lease_pool.rb +29 -0
- data/lib/farce/internal/thread_pool.rb +166 -0
- data/lib/farce/internal/transaction_conflict.rb +9 -0
- data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
- data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
- data/lib/farce/internal/undefined.rb +22 -0
- data/lib/farce/internal/unshared_lease.rb +29 -0
- data/lib/farce/internal/unshared_lease_pool.rb +34 -0
- data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
- data/lib/farce/internal/value_serialization.rb +13 -0
- data/lib/farce/internal/weak_map_value_modes.rb +58 -0
- data/lib/farce/internal/weak_mode_manager.rb +26 -0
- data/lib/farce/internal.rb +129 -0
- data/lib/farce/lazy.rb +100 -0
- data/lib/farce/lazy_ref.rb +40 -0
- data/lib/farce/lease.rb +28 -0
- data/lib/farce/lease_map.rb +34 -0
- data/lib/farce/lease_pool.rb +29 -0
- data/lib/farce/lfu_map.rb +53 -0
- data/lib/farce/local/atom.rb +23 -0
- data/lib/farce/local/counter.rb +88 -0
- data/lib/farce/local/flag.rb +65 -0
- data/lib/farce/local/lazy.rb +38 -0
- data/lib/farce/local/lazy_ref.rb +36 -0
- data/lib/farce/local/lease.rb +77 -0
- data/lib/farce/local/lease_map.rb +80 -0
- data/lib/farce/local/lease_pool.rb +38 -0
- data/lib/farce/local/lfu_map.rb +55 -0
- data/lib/farce/local/lru_map.rb +62 -0
- data/lib/farce/local/map.rb +47 -0
- data/lib/farce/local/molecule.rb +45 -0
- data/lib/farce/local/priority_queue.rb +53 -0
- data/lib/farce/local/queue.rb +32 -0
- data/lib/farce/local/scoped.rb +166 -0
- data/lib/farce/local/set.rb +18 -0
- data/lib/farce/local/sorted_set.rb +50 -0
- data/lib/farce/local/timer_queue.rb +41 -0
- data/lib/farce/local/tree_map.rb +47 -0
- data/lib/farce/local/vector.rb +30 -0
- data/lib/farce/local/weak_atom.rb +23 -0
- data/lib/farce/local/weak_key_map.rb +39 -0
- data/lib/farce/local/weak_map.rb +39 -0
- data/lib/farce/local/weak_set.rb +18 -0
- data/lib/farce/local/weak_value_map.rb +39 -0
- data/lib/farce/local.rb +35 -0
- data/lib/farce/lock.rb +54 -0
- data/lib/farce/lru_map.rb +63 -0
- data/lib/farce/map.rb +58 -0
- data/lib/farce/mode_manager.rb +142 -0
- data/lib/farce/molecule.rb +60 -0
- data/lib/farce/mutable.rb +171 -0
- data/lib/farce/pool.rb +332 -0
- data/lib/farce/port.rb +134 -0
- data/lib/farce/priority_queue.rb +70 -0
- data/lib/farce/proxy/register.rb +101 -0
- data/lib/farce/proxy/supervisor.rb +137 -0
- data/lib/farce/proxy/wrapper.rb +49 -0
- data/lib/farce/proxy.rb +291 -0
- data/lib/farce/queue.rb +60 -0
- data/lib/farce/ractor.rb +269 -0
- data/lib/farce/read_write_lock.rb +256 -0
- data/lib/farce/reference.rb +158 -0
- data/lib/farce/resolv/dns.rb +42 -0
- data/lib/farce/resolv.rb +85 -0
- data/lib/farce/scheduler.rb +536 -0
- data/lib/farce/set.rb +39 -0
- data/lib/farce/shareable.rb +150 -0
- data/lib/farce/signal.rb +97 -0
- data/lib/farce/sorted_set.rb +36 -0
- data/lib/farce/strict/atom.rb +34 -0
- data/lib/farce/strict/counter.rb +10 -0
- data/lib/farce/strict/exchanger.rb +25 -0
- data/lib/farce/strict/flag.rb +10 -0
- data/lib/farce/strict/lazy.rb +26 -0
- data/lib/farce/strict/lazy_ref.rb +26 -0
- data/lib/farce/strict/lease.rb +27 -0
- data/lib/farce/strict/lease_map.rb +33 -0
- data/lib/farce/strict/lease_pool.rb +28 -0
- data/lib/farce/strict/lfu_map.rb +27 -0
- data/lib/farce/strict/lru_map.rb +28 -0
- data/lib/farce/strict/map.rb +54 -0
- data/lib/farce/strict/molecule.rb +16 -0
- data/lib/farce/strict/port.rb +40 -0
- data/lib/farce/strict/priority_queue.rb +20 -0
- data/lib/farce/strict/queue.rb +17 -0
- data/lib/farce/strict/set.rb +14 -0
- data/lib/farce/strict/sorted_set.rb +19 -0
- data/lib/farce/strict/timer_queue.rb +13 -0
- data/lib/farce/strict/tree_map.rb +27 -0
- data/lib/farce/strict/vector.rb +24 -0
- data/lib/farce/strict/weak_atom.rb +31 -0
- data/lib/farce/strict/weak_key_map.rb +49 -0
- data/lib/farce/strict/weak_map.rb +49 -0
- data/lib/farce/strict/weak_set.rb +14 -0
- data/lib/farce/strict/weak_value_map.rb +48 -0
- data/lib/farce/strict.rb +28 -0
- data/lib/farce/system.rb +40 -0
- data/lib/farce/thread_scheduler.rb +70 -0
- data/lib/farce/timer_queue.rb +66 -0
- data/lib/farce/transaction/atom.rb +73 -0
- data/lib/farce/transaction/map.rb +25 -0
- data/lib/farce/transaction/map_operations.rb +143 -0
- data/lib/farce/transaction/molecule.rb +90 -0
- data/lib/farce/transaction/mutable.rb +61 -0
- data/lib/farce/transaction/set.rb +17 -0
- data/lib/farce/transaction/set_operations.rb +48 -0
- data/lib/farce/transaction/sorted_set.rb +18 -0
- data/lib/farce/transaction/tree_map.rb +78 -0
- data/lib/farce/transaction/vector.rb +139 -0
- data/lib/farce/transaction/wrapper.rb +202 -0
- data/lib/farce/transaction.rb +343 -0
- data/lib/farce/tree_map.rb +56 -0
- data/lib/farce/unsafe/lfu_map.rb +36 -0
- data/lib/farce/unsafe/lru_map.rb +36 -0
- data/lib/farce/unsafe/tree_map.rb +21 -0
- data/lib/farce/unsafe.rb +29 -0
- data/lib/farce/unshareable.rb +67 -0
- data/lib/farce/unshared/atom.rb +24 -0
- data/lib/farce/unshared/counter.rb +10 -0
- data/lib/farce/unshared/flag.rb +10 -0
- data/lib/farce/unshared/lazy.rb +38 -0
- data/lib/farce/unshared/lazy_ref.rb +26 -0
- data/lib/farce/unshared/lease.rb +27 -0
- data/lib/farce/unshared/lease_map.rb +26 -0
- data/lib/farce/unshared/lease_pool.rb +25 -0
- data/lib/farce/unshared/lfu_map.rb +20 -0
- data/lib/farce/unshared/lru_map.rb +20 -0
- data/lib/farce/unshared/map.rb +49 -0
- data/lib/farce/unshared/molecule.rb +16 -0
- data/lib/farce/unshared/priority_queue.rb +16 -0
- data/lib/farce/unshared/queue.rb +27 -0
- data/lib/farce/unshared/set.rb +14 -0
- data/lib/farce/unshared/sorted_set.rb +28 -0
- data/lib/farce/unshared/timer_queue.rb +16 -0
- data/lib/farce/unshared/tree_map.rb +21 -0
- data/lib/farce/unshared/vector.rb +19 -0
- data/lib/farce/unshared/weak_atom.rb +31 -0
- data/lib/farce/unshared/weak_key_map.rb +44 -0
- data/lib/farce/unshared/weak_map.rb +44 -0
- data/lib/farce/unshared/weak_set.rb +14 -0
- data/lib/farce/unshared/weak_value_map.rb +43 -0
- data/lib/farce/unshared.rb +28 -0
- data/lib/farce/vector.rb +228 -0
- data/lib/farce/version.rb +8 -0
- data/lib/farce/walker/definitions.rb +186 -0
- data/lib/farce/walker/modification.rb +355 -0
- data/lib/farce/walker.rb +319 -0
- data/lib/farce/weak_atom.rb +121 -0
- data/lib/farce/weak_key_map.rb +31 -0
- data/lib/farce/weak_map.rb +33 -0
- data/lib/farce/weak_ref.rb +67 -0
- data/lib/farce/weak_set.rb +82 -0
- data/lib/farce/weak_value.rb +195 -0
- data/lib/farce/weak_value_map.rb +32 -0
- data/lib/farce.rb +519 -0
- metadata +468 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal
|
|
7
|
+
case FROZEN_CONFIG.fiber_scheduler_implementation
|
|
8
|
+
when :native
|
|
9
|
+
load_native_fiber_scheduler
|
|
10
|
+
when :select
|
|
11
|
+
class FiberScheduler
|
|
12
|
+
include SelectScheduler
|
|
13
|
+
end
|
|
14
|
+
when :jvm
|
|
15
|
+
raise LoadError, "the JVM fiber scheduler requires JRuby"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
unless FiberScheduler.private_method_defined?(:scheduler_ready_count)
|
|
19
|
+
class FiberScheduler
|
|
20
|
+
private def scheduler_ready_count = ready? ? 1 : 0
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class FiberScheduler
|
|
25
|
+
# Opt into native wait hooks when a Ractor operation needs the shared selector.
|
|
26
|
+
def ractor_selector = RactorSelector.current
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
FiberScheduler.prepend(SchedulerLifecycle)
|
|
30
|
+
require "farce/engine/ruby/3.4/fiber_scheduler" unless Internal.native_ports?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/unshareable"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
# @!visibility private
|
|
9
|
+
module Internal # :nodoc: all
|
|
10
|
+
class UnsharedKeyLockMap
|
|
11
|
+
include Farce::Unshareable
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class KeyLockMap
|
|
15
|
+
def self.new(registry_class:, **comparison_options)
|
|
16
|
+
return super unless equal?(KeyLockMap)
|
|
17
|
+
|
|
18
|
+
if registry_class.equal?(Farce::Unshared::Map)
|
|
19
|
+
UnsharedKeyLockMap.new(**comparison_options)
|
|
20
|
+
elsif registry_class.equal?(Farce::Strict::Map) || registry_class.equal?(Farce::Map)
|
|
21
|
+
SharedKeyLockMap.new(**comparison_options)
|
|
22
|
+
else
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
# Lease storage that moves its resource through the engine Vault.
|
|
9
|
+
class Lease < LeaseState
|
|
10
|
+
include Freeze::Unfreezable
|
|
11
|
+
|
|
12
|
+
VAULT = Vault.new
|
|
13
|
+
private_constant :VAULT
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def initialize_resource(resource)
|
|
18
|
+
Freeze.publish(self)
|
|
19
|
+
VAULT.move_in(self, resource)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def take_resource = VAULT.move_out(self)
|
|
23
|
+
def return_resource(resource) = VAULT.move_in(self, resource)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
# Lease pool storage that moves resources through the CRuby Vault.
|
|
9
|
+
class LeasePool < LeasePoolState
|
|
10
|
+
include Freeze::Unfreezable
|
|
11
|
+
|
|
12
|
+
VAULT = Vault.new
|
|
13
|
+
private_constant :VAULT
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def finalize_initialization = Freeze.publish(self)
|
|
18
|
+
def store_resource(token, resource) = VAULT.move_in(token, resource)
|
|
19
|
+
def take_resource(token) = VAULT.move_out(token)
|
|
20
|
+
def return_resource(token, resource) = VAULT.move_in(token, resource)
|
|
21
|
+
def discard_resource(token) = VAULT.delete(token)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal
|
|
7
|
+
# Observe termination without consuming the Ractor's return value.
|
|
8
|
+
class ProxyOwner
|
|
9
|
+
include ProxyOwnerNotifications
|
|
10
|
+
|
|
11
|
+
def self.current = Storage.store_if_absent(self) { new }
|
|
12
|
+
|
|
13
|
+
def self.create_scheduler
|
|
14
|
+
scheduler = Farce::Scheduler.new
|
|
15
|
+
Fiber.set_scheduler(scheduler)
|
|
16
|
+
scheduler
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.drain_scheduler(scheduler) = scheduler.close
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
super
|
|
23
|
+
TracePoint.new(:thread_end) do |trace|
|
|
24
|
+
stop
|
|
25
|
+
trace.disable
|
|
26
|
+
end.enable(target_thread: Ractor.main_thread)
|
|
27
|
+
freeze
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
module RactorMethods
|
|
9
|
+
Internal.delegate(self, ::Ractor, :[], :[]=, :count, :main?, :make_shareable, :shareable?,
|
|
10
|
+
:store_if_absent)
|
|
11
|
+
|
|
12
|
+
if ::Ractor.method(:receive!).parameters.include?(%i[key timeout])
|
|
13
|
+
def receive(timeout: nil)
|
|
14
|
+
if selector = RactorSelector.for_call(::Ractor.current)
|
|
15
|
+
selector.ractor_receive(::Ractor.current, timeout:)
|
|
16
|
+
else
|
|
17
|
+
timeout.nil? ? ::Ractor.receive : ::Ractor.receive(timeout:)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
def receive(timeout: nil)
|
|
22
|
+
selector = RactorSelector.for_call(::Ractor.current)
|
|
23
|
+
selector ||= RactorSelector.current unless timeout.nil?
|
|
24
|
+
selector ? selector.ractor_receive(::Ractor.current, timeout:) : ::Ractor.receive
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def builtin? = true
|
|
29
|
+
def main_thread = Thread.main
|
|
30
|
+
def shim? = false
|
|
31
|
+
def threads = Thread.list
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/clock"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
module Internal
|
|
9
|
+
# Multiplex native Ractor waits on one thread in the receiving Ractor.
|
|
10
|
+
# Native ports must be received in their owning Ractor. A helper thread can
|
|
11
|
+
# block there while the calling fiber waits on a local reply queue. Results
|
|
12
|
+
# stay in the same Ractor, without another copy or ownership transfer.
|
|
13
|
+
# Cancelled deliveries are retained for the next receiver.
|
|
14
|
+
class RactorSelector
|
|
15
|
+
Request = Struct.new(:sources, :ready, :reply, :delivery, :yield_options)
|
|
16
|
+
private_constant :Request
|
|
17
|
+
|
|
18
|
+
# Storage owns one selector per Ractor and serializes its first construction.
|
|
19
|
+
def self.current = Storage.store_if_absent(self) { new }
|
|
20
|
+
|
|
21
|
+
# Farce APIs opt into cooperative waits even on third-party schedulers.
|
|
22
|
+
# Native hooks never call this method. They only use the scheduler's opt-in getter.
|
|
23
|
+
def self.for_call(source)
|
|
24
|
+
return current if Fiber.scheduler && !Fiber.blocking?
|
|
25
|
+
# Synchronous Farce calls only reuse the helper for sources it still handles.
|
|
26
|
+
# Cancellation may have left a message here after removing it from the
|
|
27
|
+
# native port. Receiving directly from that port would miss the message.
|
|
28
|
+
existing = Storage[self]
|
|
29
|
+
existing if existing&.routes?(source)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
@commands = Thread::Queue.new
|
|
34
|
+
@wakeup = Atom.new(false)
|
|
35
|
+
@pending = []
|
|
36
|
+
@buffer = {}.compare_by_identity
|
|
37
|
+
@routing_lock = Thread::Mutex.new
|
|
38
|
+
@routed = {}.compare_by_identity
|
|
39
|
+
@sequence = 0
|
|
40
|
+
@failure = nil
|
|
41
|
+
@closed = @selecting = false
|
|
42
|
+
@owner = ::Ractor.current
|
|
43
|
+
@control = build_control
|
|
44
|
+
@thread = Thread.new { run }
|
|
45
|
+
@thread.name = "farce-ractor-selector"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# An idle selector does not change synchronous receive/select dispatch.
|
|
49
|
+
# Active registrations keep concurrent waits on the same source coordinated.
|
|
50
|
+
def routes?(source)
|
|
51
|
+
return false if @routed.empty? && @buffer.empty?
|
|
52
|
+
return source.any? { |entry| routes?(entry) } if source.is_a?(Array)
|
|
53
|
+
source = receive_source(source)
|
|
54
|
+
@routing_lock.synchronize { @routed.key?(source) || @buffer.key?(source) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def closed? = @closed
|
|
58
|
+
|
|
59
|
+
def close
|
|
60
|
+
return if @closed && !@failure
|
|
61
|
+
@closed = true
|
|
62
|
+
begin
|
|
63
|
+
acknowledge(:close) unless @failure
|
|
64
|
+
@thread.join
|
|
65
|
+
ensure
|
|
66
|
+
close_control
|
|
67
|
+
end
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
# Retrieve an already-ready native result without re-entering the scheduler hook.
|
|
74
|
+
def native(&)
|
|
75
|
+
Fiber.blocking(&)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def duration(value)
|
|
79
|
+
return if value.nil?
|
|
80
|
+
raise TypeError, "cannot convert String into time interval" if value.is_a?(String)
|
|
81
|
+
value = Float(value)
|
|
82
|
+
raise RangeError, "timeout out of range" unless value.finite?
|
|
83
|
+
raise ArgumentError, "time interval must not be negative" if value.negative?
|
|
84
|
+
value
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def wait(sources, timeout, options = nil)
|
|
88
|
+
raise ::Ractor::IsolationError, "selector belongs to another Ractor" unless @owner == ::Ractor.current
|
|
89
|
+
raise @failure if @failure
|
|
90
|
+
raise IOError, "Ractor selector is closed" if @closed
|
|
91
|
+
|
|
92
|
+
timeout = duration(timeout)
|
|
93
|
+
deadline = Clock.now + timeout if timeout
|
|
94
|
+
sources = sources.uniq
|
|
95
|
+
|
|
96
|
+
sources.each { |source| validate_source(source) }
|
|
97
|
+
|
|
98
|
+
originals = {}.compare_by_identity
|
|
99
|
+
registered = false
|
|
100
|
+
sources = sources.map do |source|
|
|
101
|
+
actual = source.selector_source if fallback_port?(source)
|
|
102
|
+
actual ||= source
|
|
103
|
+
originals[actual] = source
|
|
104
|
+
actual
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Register before sending the request so concurrent receivers use the
|
|
108
|
+
# same helper. Counts cover overlapping select calls and multiple threads.
|
|
109
|
+
Thread.handle_interrupt(INTERRUPT_MASK) do
|
|
110
|
+
@routing_lock.synchronize do
|
|
111
|
+
sources.each { |source| @routed[source] = @routed.fetch(source, 0) + 1 }
|
|
112
|
+
registered = true
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
# A zero timeout still needs one readiness poll. Positive deadlines
|
|
116
|
+
# include time spent waiting for the helper to accept the request.
|
|
117
|
+
request = Request.new(sources, timeout&.zero? ? Thread::Queue.new : nil, Thread::Queue.new)
|
|
118
|
+
if options&.key?(:yield_value)
|
|
119
|
+
# Ruby 3.4's outgoing yield competes with incoming sources. The request
|
|
120
|
+
# itself identifies that outcome without colliding with a real source.
|
|
121
|
+
request.yield_options = options
|
|
122
|
+
sources << request
|
|
123
|
+
originals[request] = :yield
|
|
124
|
+
end
|
|
125
|
+
command(:add, request)
|
|
126
|
+
request.ready&.pop
|
|
127
|
+
|
|
128
|
+
if deadline
|
|
129
|
+
remaining = deadline - Clock.now
|
|
130
|
+
remaining = 0 if remaining.negative?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
delivery = request.reply.pop(timeout: remaining)
|
|
134
|
+
if delivery
|
|
135
|
+
_, source, value, error = delivery
|
|
136
|
+
# A delivered error is accepted too, even though it unwinds this wait.
|
|
137
|
+
accepted = true
|
|
138
|
+
raise error if error
|
|
139
|
+
[originals.fetch(source, source), value]
|
|
140
|
+
end
|
|
141
|
+
ensure
|
|
142
|
+
# Finish cancellation before dropping routing ownership. The helper may
|
|
143
|
+
# already have consumed a message that must be retained for another call.
|
|
144
|
+
acknowledge(:cancel, request) if request && !accepted
|
|
145
|
+
if registered
|
|
146
|
+
@routing_lock.synchronize do
|
|
147
|
+
sources.each do |source|
|
|
148
|
+
next unless count = @routed[source]
|
|
149
|
+
count == 1 ? @routed.delete(source) : @routed[source] = count - 1
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def command(action, payload = nil, ack = nil)
|
|
156
|
+
Thread.handle_interrupt(INTERRUPT_MASK) do
|
|
157
|
+
@commands << [action, payload, ack]
|
|
158
|
+
wake if @selecting
|
|
159
|
+
end
|
|
160
|
+
rescue ::ClosedQueueError
|
|
161
|
+
# A caller may have passed the closed check before the helper stopped.
|
|
162
|
+
fail_request(payload, @failure || IOError.new("Ractor selector is closed")) if action == :add
|
|
163
|
+
ack << true if ack
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Coalesce command and shim-port notifications into one control message.
|
|
167
|
+
# Mask interruption so setting the flag cannot leave an unsent wakeup.
|
|
168
|
+
def wake
|
|
169
|
+
Thread.handle_interrupt(INTERRUPT_MASK) do
|
|
170
|
+
@control.send(nil) if @wakeup.compare_and_set(false, true)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def acknowledge(action, payload = nil)
|
|
175
|
+
return if @closed && action != :close
|
|
176
|
+
ack = Thread::Queue.new
|
|
177
|
+
Thread.handle_interrupt(INTERRUPT_MASK) do
|
|
178
|
+
command(action, payload, ack)
|
|
179
|
+
# Cleanup must finish even while the scheduler is unwinding a cancelled
|
|
180
|
+
# fiber or shutting down. The helper acknowledges independently of it.
|
|
181
|
+
Fiber.blocking { ack.pop }
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def forget(port)
|
|
186
|
+
acknowledge(:forget, port) unless @closed
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def run
|
|
190
|
+
Internal.prepare_thread if defined?(Internal.prepare_thread)
|
|
191
|
+
loop do
|
|
192
|
+
# A data source may win select while a control notification is pending.
|
|
193
|
+
# Consume that notification before parking or starting another select.
|
|
194
|
+
if @wakeup.value
|
|
195
|
+
receive_control
|
|
196
|
+
@wakeup.value = false
|
|
197
|
+
end
|
|
198
|
+
# Park on the command queue when idle. Native select is only needed
|
|
199
|
+
# while there are application sources to watch.
|
|
200
|
+
first = @pending.empty? ? @commands.pop : nil
|
|
201
|
+
break unless process_commands(first)
|
|
202
|
+
dispatch_buffer
|
|
203
|
+
sources = @pending.flat_map(&:sources).uniq
|
|
204
|
+
sources.each { |source| poll(source) if fallback_port?(source) }
|
|
205
|
+
dispatch_buffer
|
|
206
|
+
next if @pending.empty? || !@commands.empty?
|
|
207
|
+
native_sources = @pending.flat_map(&:sources).uniq.reject do |source|
|
|
208
|
+
source.is_a?(Request) || fallback_port?(source)
|
|
209
|
+
end
|
|
210
|
+
yielding = @pending.find(&:yield_options)
|
|
211
|
+
begin
|
|
212
|
+
# Publish the selecting state before rechecking commands. A concurrent
|
|
213
|
+
# sender then either reaches this check or wakes the native select.
|
|
214
|
+
@selecting = true
|
|
215
|
+
next unless @commands.empty?
|
|
216
|
+
source, value = ::Ractor.select(*native_sources, @control, **(yielding&.yield_options || {}))
|
|
217
|
+
ensure
|
|
218
|
+
@selecting = false
|
|
219
|
+
end
|
|
220
|
+
source = yielding if source == :yield
|
|
221
|
+
if source.equal?(@control)
|
|
222
|
+
@wakeup.value = false
|
|
223
|
+
else
|
|
224
|
+
record(source == :receive ? @owner : source, value)
|
|
225
|
+
end
|
|
226
|
+
rescue ::Ractor::ClosedError
|
|
227
|
+
# Isolate a closed or foreign port instead of failing unrelated waits.
|
|
228
|
+
sources.each { |source| poll(source) }
|
|
229
|
+
end
|
|
230
|
+
rescue Exception => e # rubocop:disable Lint/RescueException -- Preserve helper failures for callers and close.
|
|
231
|
+
@failure = e
|
|
232
|
+
raise
|
|
233
|
+
ensure
|
|
234
|
+
# Stop accepting commands before draining them, including late registrations.
|
|
235
|
+
@commands.close
|
|
236
|
+
@closed = true
|
|
237
|
+
error = @failure || IOError.new("Ractor selector stopped")
|
|
238
|
+
@pending.each { |request| fail_request(request, error) }
|
|
239
|
+
until @commands.empty?
|
|
240
|
+
action, payload, ack = @commands.pop(true)
|
|
241
|
+
fail_request(payload, error) if action == :add
|
|
242
|
+
ack << true if ack
|
|
243
|
+
end
|
|
244
|
+
cleanup_control
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def process_commands(first = nil) # rubocop:disable Naming/PredicateMethod
|
|
248
|
+
while first || !@commands.empty?
|
|
249
|
+
action, payload, ack = first || @commands.pop(true)
|
|
250
|
+
first = nil
|
|
251
|
+
case action
|
|
252
|
+
when :add
|
|
253
|
+
@pending << payload
|
|
254
|
+
payload.sources.each do |source|
|
|
255
|
+
source.selector_watch(@control, @wakeup) if fallback_port?(source)
|
|
256
|
+
poll(source) if payload.ready && !@buffer.key?(source)
|
|
257
|
+
end
|
|
258
|
+
dispatch_buffer
|
|
259
|
+
payload.ready&.push(true)
|
|
260
|
+
when :cancel
|
|
261
|
+
@pending.delete(payload)
|
|
262
|
+
if payload.delivery && !payload.delivery[3] && !payload.delivery[1].is_a?(Request)
|
|
263
|
+
# Queuing a reply does not mean the caller accepted it. Restore
|
|
264
|
+
# unclaimed messages in receive order, even if cancellations arrive
|
|
265
|
+
# out of order. Errors and completed outgoing yields cannot be replayed.
|
|
266
|
+
source = payload.delivery[1]
|
|
267
|
+
(@buffer[source] ||= []) << payload.delivery
|
|
268
|
+
@buffer[source].sort_by!(&:first)
|
|
269
|
+
end
|
|
270
|
+
when :forget
|
|
271
|
+
# Temporary monitor ports may have retained readiness notifications.
|
|
272
|
+
@buffer.delete(payload)
|
|
273
|
+
when :close
|
|
274
|
+
@pending.each { |request| fail_request(request, IOError.new("Ractor selector is closed")) }
|
|
275
|
+
@pending.clear
|
|
276
|
+
ack << true
|
|
277
|
+
return false
|
|
278
|
+
end
|
|
279
|
+
ack << true if ack
|
|
280
|
+
end
|
|
281
|
+
true
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def poll(source)
|
|
285
|
+
return if source.is_a?(Request)
|
|
286
|
+
if fallback_port?(source)
|
|
287
|
+
source.selector_poll { |value| record(source, value) }
|
|
288
|
+
else
|
|
289
|
+
# A ready control message lets select return when the source has no
|
|
290
|
+
# value, providing a readiness poll on Rubies without native timeouts.
|
|
291
|
+
wake
|
|
292
|
+
selected, value = ::Ractor.select(source, @control)
|
|
293
|
+
if selected.equal?(@control)
|
|
294
|
+
@wakeup.value = false
|
|
295
|
+
check_closed(source)
|
|
296
|
+
else
|
|
297
|
+
record(selected == :receive ? @owner : selected, value)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
rescue StandardError => e
|
|
301
|
+
record(source, nil, e)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def record(source, value, error = nil)
|
|
305
|
+
@sequence += 1
|
|
306
|
+
(@buffer[source] ||= []) << [@sequence, source, value, error]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def dispatch_buffer
|
|
310
|
+
@pending.dup.each do |request|
|
|
311
|
+
source = request.sources.find { |candidate| @buffer.key?(candidate) }
|
|
312
|
+
next unless source
|
|
313
|
+
delivery = @buffer[source].shift
|
|
314
|
+
@buffer.delete(source) if @buffer[source].empty?
|
|
315
|
+
@pending.delete(request)
|
|
316
|
+
# Keep the delivery attached until the caller accepts it or cancels.
|
|
317
|
+
request.delivery = delivery
|
|
318
|
+
request.reply << delivery
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def fail_request(request, error)
|
|
323
|
+
request.reply << [nil, nil, nil, error]
|
|
324
|
+
request.ready&.push(true)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
StrictMap = Map
|
|
9
|
+
StrictWeakKeyMap = WeakKeyMap
|
|
10
|
+
StrictWeakMap = WeakMap
|
|
11
|
+
StrictWeakValueMap = WeakValueMap
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/engine/shared/unshared_vector"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
# @!visibility private
|
|
9
|
+
module Internal # :nodoc: all
|
|
10
|
+
class UnsharedVector
|
|
11
|
+
prepend UnsharedVectorIteration
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|