farce 0 → 0.1.0
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1525 -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/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/vault.rb +56 -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/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 +435 -8
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Shared priority ordering and blocking behavior.
|
|
8
|
+
class PriorityQueue < Queue
|
|
9
|
+
include Internal::BlockingPriorityQueue
|
|
10
|
+
|
|
11
|
+
# @return [BasicObject] the priority used when none is passed to push
|
|
12
|
+
attr_reader :default_priority
|
|
13
|
+
|
|
14
|
+
# @return [:ascending, :descending] the priority order
|
|
15
|
+
attr_reader :order
|
|
16
|
+
|
|
17
|
+
# @param capacity [Integer, nil] the maximum number of values, or nil for
|
|
18
|
+
# an unbounded queue
|
|
19
|
+
# @param default_priority [BasicObject] the priority used when push or
|
|
20
|
+
# try_push is called without an explicit priority
|
|
21
|
+
# @param order [:ascending, :descending] the priority order
|
|
22
|
+
def initialize(capacity: nil, default_priority: 0, order: :ascending, track_age: false)
|
|
23
|
+
@order = normalize_order(order)
|
|
24
|
+
@default_priority = default_priority
|
|
25
|
+
super(capacity:, reverse_order: @order == :descending, track_age:)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Return the next value without removing it.
|
|
29
|
+
# @yield called when the queue is empty
|
|
30
|
+
# @return [BasicObject, nil] the next value or the fallback result
|
|
31
|
+
def peek(&) = internal_reverse_order? ? internal_queue.peek_last(&) : internal_queue.peek(&)
|
|
32
|
+
|
|
33
|
+
# Remove the oldest value at the lowest or highest priority, depending on {#order}, waiting when empty.
|
|
34
|
+
def pop(non_block = false, timeout: nil) # rubocop:disable Style/OptionalBooleanParameter
|
|
35
|
+
return try_pop { raise ThreadError, "queue empty" } if non_block
|
|
36
|
+
deadline = timeout_at(timeout) unless timeout.nil?
|
|
37
|
+
|
|
38
|
+
while true
|
|
39
|
+
empty = false
|
|
40
|
+
result = if internal_reverse_order?
|
|
41
|
+
internal_queue.pop_last { empty = true }
|
|
42
|
+
else
|
|
43
|
+
internal_queue.pop { empty = true }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
return result unless empty
|
|
47
|
+
remaining = remaining_timeout(deadline)
|
|
48
|
+
return block_given? ? yield : nil unless wait_pop(timeout: remaining)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add a value, waiting for capacity when the queue is bounded and full.
|
|
53
|
+
# @param value [BasicObject] the value to add
|
|
54
|
+
# @param non_block [Boolean] whether to raise an exception when the queue is at capacity
|
|
55
|
+
# @param priority [BasicObject] the value used to order the entry
|
|
56
|
+
# @param timeout [Numeric, nil] maximum number of seconds to wait
|
|
57
|
+
# @raise [ThreadError] when the queue is at capacity and non_block is true
|
|
58
|
+
# @return [Boolean] whether the value was added
|
|
59
|
+
def push(value, non_block = false, priority: default_priority, timeout: nil) # rubocop:disable Style/OptionalBooleanParameter
|
|
60
|
+
push_to_storage(priority, non_block, value, timeout:)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Try to remove the oldest value at the lowest priority without waiting.
|
|
64
|
+
# @yield called when the queue is empty
|
|
65
|
+
# @return [BasicObject, nil] the next value or the fallback result
|
|
66
|
+
def try_pop(&) = internal_reverse_order? ? internal_queue.pop_last(&) : internal_queue.pop(&)
|
|
67
|
+
|
|
68
|
+
# Try to add a value without waiting.
|
|
69
|
+
# @param value [BasicObject] the value to add
|
|
70
|
+
# @param priority [BasicObject] the value used to order the entry
|
|
71
|
+
# @yield called when the queue is at capacity
|
|
72
|
+
# @return [Boolean, BasicObject] true, or the fallback result when full
|
|
73
|
+
def try_push(value, priority: default_priority)
|
|
74
|
+
return true if internal_queue.push(priority, value)
|
|
75
|
+
|
|
76
|
+
block_given? ? yield : false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Return the next priority without removing it.
|
|
80
|
+
# @yield called when the queue is empty
|
|
81
|
+
# @return [BasicObject, nil] the priority or the fallback result
|
|
82
|
+
def first_priority(&)
|
|
83
|
+
internal_reverse_order? ? internal_queue.peek_last_priority(&) : internal_queue.peek_priority(&)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Return the last priority without removing it.
|
|
87
|
+
# @yield called when the queue is empty
|
|
88
|
+
# @return [BasicObject, nil] the priority or the fallback result
|
|
89
|
+
def last_priority(&)
|
|
90
|
+
internal_reverse_order? ? internal_queue.peek_priority(&) : internal_queue.peek_last_priority(&)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Delete the oldest matching value at the exact priority.
|
|
94
|
+
# @param value [BasicObject] the value to delete
|
|
95
|
+
# @param priority [BasicObject] the exact priority to search
|
|
96
|
+
# @param compare_by_identity [Boolean] compare values by identity instead of equality
|
|
97
|
+
# @return [Boolean] whether a value was deleted
|
|
98
|
+
def delete(value, priority:, compare_by_identity: false)
|
|
99
|
+
delete_from_storage(priority, value, compare_by_identity:)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Wait until a value is available without removing it.
|
|
103
|
+
def wait_pop(timeout: nil) = wait(timeout) { size.positive? }
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def internal_reverse_order? = @reverse_order
|
|
108
|
+
|
|
109
|
+
def normalize_order(order)
|
|
110
|
+
return :ascending if :ascending.equal?(order)
|
|
111
|
+
return :descending if :descending.equal?(order)
|
|
112
|
+
|
|
113
|
+
raise ArgumentError, "order must be :ascending or :descending"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract A shared super class for all queues defined by Farce.
|
|
8
|
+
#
|
|
9
|
+
# A queue is a collection of items that can be added to and removed from in a thread-safe manner.
|
|
10
|
+
# The order is typically FIFO (first-in, first-out), but other orderings may be applied on top.
|
|
11
|
+
#
|
|
12
|
+
# Queues have a blocking and non-blocking interface.
|
|
13
|
+
#
|
|
14
|
+
# @!attribute [r] capacity
|
|
15
|
+
# @abstract
|
|
16
|
+
# @return [Integer, nil] The maximum number of items the queue can hold.
|
|
17
|
+
#
|
|
18
|
+
# @!attribute [r] num_waiting
|
|
19
|
+
# @abstract
|
|
20
|
+
# The number of threads/fibers currently waiting on the queue. This is a momentary snapshot and may be an
|
|
21
|
+
# approximation. The number may also include threads waiting for a push to succeed, as well as threads waiting
|
|
22
|
+
# without modifying the queue.
|
|
23
|
+
# @return [Integer] Number of threads/fibers waiting on the queue.
|
|
24
|
+
#
|
|
25
|
+
# @!attribute [r] mode
|
|
26
|
+
# @return [Symbol] The default mode used to transfer values between Ractors.
|
|
27
|
+
#
|
|
28
|
+
# @!attribute [r] size
|
|
29
|
+
# @abstract
|
|
30
|
+
# @return [Integer] The current number of items in the queue.
|
|
31
|
+
#
|
|
32
|
+
# @!method initialize(capacity: 1024, track_age: false)
|
|
33
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
34
|
+
# @param capacity [Integer, nil]
|
|
35
|
+
# The maximum number of items the queue can hold.
|
|
36
|
+
# If `nil`, the queue is unbounded.
|
|
37
|
+
#
|
|
38
|
+
# The default may vary for subclasses.
|
|
39
|
+
# Most notably, priority and timer queues default to `nil`.
|
|
40
|
+
# @param track_age [Boolean] Whether to track enqueue age and queue generations.
|
|
41
|
+
#
|
|
42
|
+
# @!method clear
|
|
43
|
+
# @abstract
|
|
44
|
+
# Removes all items from the queue.
|
|
45
|
+
# @return [self]
|
|
46
|
+
#
|
|
47
|
+
# @!method close
|
|
48
|
+
# @abstract
|
|
49
|
+
# Closes the queue, preventing any further items from being added.
|
|
50
|
+
# @return [self]
|
|
51
|
+
#
|
|
52
|
+
# @!method closed?
|
|
53
|
+
# @abstract
|
|
54
|
+
# Checks whether the queue is closed.
|
|
55
|
+
# @return [Boolean] `true` if the queue is closed, `false` otherwise.
|
|
56
|
+
#
|
|
57
|
+
# @!method seal
|
|
58
|
+
# Stops new pushes while allowing queued items to be removed.
|
|
59
|
+
# The queue closes automatically when it becomes empty.
|
|
60
|
+
# @return [self]
|
|
61
|
+
#
|
|
62
|
+
# @!method sealed?
|
|
63
|
+
# @return [Boolean] Whether the queue rejects new pushes.
|
|
64
|
+
#
|
|
65
|
+
# @!method empty?
|
|
66
|
+
# @abstract
|
|
67
|
+
# Checks whether the queue is empty.
|
|
68
|
+
# @return [Boolean] `true` if the queue is empty, `false` otherwise.
|
|
69
|
+
#
|
|
70
|
+
# @!method pop(non_block = false, timeout: nil)
|
|
71
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
72
|
+
# Takes an item from the queue, blocking until one is available or the timeout expires.
|
|
73
|
+
# @yield Block called if the timeout expires before an item is available.
|
|
74
|
+
# @param non_block [Boolean] whether to raise an exception when the queue is empty
|
|
75
|
+
# @param timeout [Numeric, nil]
|
|
76
|
+
# The maximum time to wait for an item to be available.
|
|
77
|
+
# If `nil`, the method will wait indefinitely.
|
|
78
|
+
# If `0`, the method will not wait at all.
|
|
79
|
+
# @raise [Farce::ClosedQueueError] when the queue is closed
|
|
80
|
+
# @raise [ThreadError] when the queue is empty and non_block is true
|
|
81
|
+
# @return [BasicObject, nil]
|
|
82
|
+
# The item taken from the queue, or the return value of the block or `nil` if the timeout expired.
|
|
83
|
+
#
|
|
84
|
+
# @!method push(value, non_block = false, timeout: nil)
|
|
85
|
+
# @abstract
|
|
86
|
+
# Subclasses may add additional parameters to this method.
|
|
87
|
+
# They may also restrict what types of values can be pushed onto the queue.
|
|
88
|
+
# In particular, some queues may only accept Ractor-shareable values.
|
|
89
|
+
# Pushes an item onto the queue. May block if the queue is at capacity.
|
|
90
|
+
# If the queue is unbounded, this method will never block.
|
|
91
|
+
# If a timeout is specified, the method will block until the item is added or the timeout expires.
|
|
92
|
+
# @param value [BasicObject] The item to add to the queue.
|
|
93
|
+
# @param non_block [Boolean] whether to raise an exception when the queue is full
|
|
94
|
+
# @param timeout [Numeric, nil]
|
|
95
|
+
# The maximum time to wait for the item to be added.
|
|
96
|
+
# If `nil`, the method will wait indefinitely.
|
|
97
|
+
# If `0`, the method will not wait at all.
|
|
98
|
+
# @raise [Farce::ClosedQueueError] when the queue is closed
|
|
99
|
+
# @raise [Farce::SealedQueueError] when the queue is sealed but not yet closed
|
|
100
|
+
# @raise [ThreadError] when the queue is full and non_block is true
|
|
101
|
+
# @return [Boolean] `true` if the item was added to the queue
|
|
102
|
+
#
|
|
103
|
+
# @!method try_pop
|
|
104
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
105
|
+
# Tries to take an item from the queue without blocking.
|
|
106
|
+
# If no item is available, the method will call the block if given, or return `nil` if no block is given.
|
|
107
|
+
# @yield Block called if no item is available.
|
|
108
|
+
# @return [BasicObject, nil]
|
|
109
|
+
# The item taken from the queue, or the return value of the block or `nil` if no item was available.
|
|
110
|
+
#
|
|
111
|
+
# @!method try_push(value)
|
|
112
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
113
|
+
# Tries to push an item onto the queue without blocking.
|
|
114
|
+
# If the queue is at capacity, the method will call the block if given, or return `false` if no block is given.
|
|
115
|
+
# @param value [BasicObject] The item to add to the queue.
|
|
116
|
+
# @yield Block called if the queue is at capacity.
|
|
117
|
+
# @raise [Farce::ClosedQueueError] when the queue is closed
|
|
118
|
+
# @raise [Farce::SealedQueueError] when the queue is sealed but not yet closed
|
|
119
|
+
# @return [Boolean]
|
|
120
|
+
# `true` if the item was added to the queue, `false` if the queue was at capacity and no block was given.
|
|
121
|
+
#
|
|
122
|
+
# @!method wait_pop(timeout: nil)
|
|
123
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
124
|
+
# Waits until an item is available to pop from the queue, or the timeout expires.
|
|
125
|
+
# Does not remove the item from the queue.
|
|
126
|
+
# Note that this method does not guarantee a subsequent call to {#pop} or {#try_pop} will succeed,
|
|
127
|
+
# as another thread may remove the item first.
|
|
128
|
+
# @param timeout [Numeric, nil]
|
|
129
|
+
# The maximum time to wait for an item to be available.
|
|
130
|
+
# If `nil`, the method will wait indefinitely.
|
|
131
|
+
# If `0`, the method will not wait at all.
|
|
132
|
+
# @raise [Farce::ClosedQueueError] when the queue is closed
|
|
133
|
+
# @return [Boolean] `true` if an item is available, `false` if the timeout expired.
|
|
134
|
+
#
|
|
135
|
+
# @!method wait_push(timeout: nil)
|
|
136
|
+
# @abstract Subclasses may add additional parameters to this method.
|
|
137
|
+
# Waits until there is space to push an item onto the queue, or the timeout expires.
|
|
138
|
+
# Note that this method does not guarantee a subsequent call to {#push} or {#try_push} will succeed,
|
|
139
|
+
# as another thread may add an item first.
|
|
140
|
+
# @param timeout [Numeric, nil]
|
|
141
|
+
# The maximum time to wait for space to be available.
|
|
142
|
+
# If `nil`, the method will wait indefinitely.
|
|
143
|
+
# If `0`, the method will not wait at all.
|
|
144
|
+
# @raise [Farce::ClosedQueueError] when the queue is closed
|
|
145
|
+
# @raise [Farce::SealedQueueError] when the queue is sealed but not yet closed
|
|
146
|
+
# @return [Boolean] `true` if space is available, `false` if the timeout expired.
|
|
147
|
+
class Queue
|
|
148
|
+
include Internal::MarshalSupport::Reject
|
|
149
|
+
include Internal::Inspect
|
|
150
|
+
|
|
151
|
+
# The default mode used to transfer values between Ractors.
|
|
152
|
+
# @return [Symbol]
|
|
153
|
+
def mode = :raise
|
|
154
|
+
|
|
155
|
+
# Alias for {#pop} to match the interface of Ruby's Queue class.
|
|
156
|
+
# @return (see #pop)
|
|
157
|
+
def deq(...) = pop(...)
|
|
158
|
+
alias shift deq
|
|
159
|
+
|
|
160
|
+
# Alias for {#push} to match the interface of Ruby's Queue class.
|
|
161
|
+
# @return (see #push)
|
|
162
|
+
def enq(...) = push(...)
|
|
163
|
+
alias << enq
|
|
164
|
+
|
|
165
|
+
# Alias for {#size} to match the interface of Ruby's Queue class.
|
|
166
|
+
# @return (see #size)
|
|
167
|
+
def length = size
|
|
168
|
+
|
|
169
|
+
# The maximum number of items the queue can hold.
|
|
170
|
+
# @return [Integer, Float] the maximum number of items, or `Float::INFINITY` if the queue is unbounded.
|
|
171
|
+
def max = capacity || Float::INFINITY
|
|
172
|
+
|
|
173
|
+
# Whether the queue is at capacity.
|
|
174
|
+
# @return [Boolean] `true` if the queue is at capacity, `false` otherwise.
|
|
175
|
+
def full? = capacity && size >= capacity
|
|
176
|
+
|
|
177
|
+
def capacity = internal_queue.capacity
|
|
178
|
+
|
|
179
|
+
def clear
|
|
180
|
+
internal_queue.clear
|
|
181
|
+
self
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def close
|
|
185
|
+
internal_queue.close
|
|
186
|
+
self
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Stop new pushes and close after the final queued item is removed.
|
|
190
|
+
# @return [self]
|
|
191
|
+
def seal
|
|
192
|
+
internal_queue.seal
|
|
193
|
+
self
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def closed? = internal_queue.closed?
|
|
197
|
+
def sealed? = internal_queue.sealed?
|
|
198
|
+
|
|
199
|
+
# @return [Boolean] Whether enqueue-age tracking is enabled.
|
|
200
|
+
def age_tracking? = internal_queue.age_tracking?
|
|
201
|
+
|
|
202
|
+
# @return [Integer, nil] The mutation generation, or `nil` when tracking is disabled.
|
|
203
|
+
def generation = internal_queue.generation
|
|
204
|
+
|
|
205
|
+
# The timestamp is monotonic. Its origin is runtime-specific.
|
|
206
|
+
# @return [Float, nil] The monotonic enqueue time of the oldest item.
|
|
207
|
+
def oldest_enqueued_at = internal_queue.oldest_enqueued_at
|
|
208
|
+
|
|
209
|
+
# @return [Float, nil] Seconds since the oldest item was enqueued.
|
|
210
|
+
def oldest_age = internal_queue.oldest_age
|
|
211
|
+
|
|
212
|
+
def empty? = size.zero?
|
|
213
|
+
|
|
214
|
+
def num_waiting = internal_queue.num_waiting
|
|
215
|
+
|
|
216
|
+
def pop(non_block = false, timeout: nil, &) # rubocop:disable Style/OptionalBooleanParameter
|
|
217
|
+
return internal_queue.try_pop { raise ThreadError, "queue empty" } if non_block
|
|
218
|
+
timeout.nil? ? internal_queue.pop(&) : internal_queue.pop(timeout:, &)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def push(value, non_block = false, timeout: nil) # rubocop:disable Style/OptionalBooleanParameter
|
|
222
|
+
if non_block
|
|
223
|
+
return true if internal_queue.try_push(value)
|
|
224
|
+
raise ThreadError, "queue full"
|
|
225
|
+
end
|
|
226
|
+
timeout.nil? ? internal_queue.push(value) : internal_queue.push(value, timeout:)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def try_pop(&) = internal_queue.try_pop(&)
|
|
230
|
+
|
|
231
|
+
def try_push(value)
|
|
232
|
+
return true if internal_queue.try_push(value)
|
|
233
|
+
block_given? ? yield : false
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def size = internal_queue.size
|
|
237
|
+
|
|
238
|
+
def wait_pop(timeout: nil) = internal_queue.wait_pop(timeout:)
|
|
239
|
+
|
|
240
|
+
def wait_push(timeout: nil) = internal_queue.wait_push(timeout:)
|
|
241
|
+
|
|
242
|
+
# @api private
|
|
243
|
+
def inspect_with(inspector)
|
|
244
|
+
super do
|
|
245
|
+
if closed?
|
|
246
|
+
inspector.breakable " "
|
|
247
|
+
inspector.text "closed"
|
|
248
|
+
else
|
|
249
|
+
inspector.attributes(inspect_info)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
private
|
|
255
|
+
|
|
256
|
+
def initialize_copy(_other)
|
|
257
|
+
raise TypeError, "queues cannot be copied"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def inspect_info
|
|
261
|
+
info = { size:, capacity: }.compact
|
|
262
|
+
info[:num_waiting] = num_waiting if num_waiting.positive?
|
|
263
|
+
info
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
private def internal_queue = @queue
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract A shared super class for all scheduler implementations.
|
|
8
|
+
#
|
|
9
|
+
# @!method schedule(*args, mode: :copy, auto_local: true)
|
|
10
|
+
# @abstract This method must be implemented by concrete scheduler subclasses.
|
|
11
|
+
#
|
|
12
|
+
# Schedules a block for execution.
|
|
13
|
+
# What actually happens depends on the concrete scheduler implementation.
|
|
14
|
+
# Some schedulers may ignore the `auto_local` option. Some might treat every mode as `:local`.
|
|
15
|
+
#
|
|
16
|
+
# The scheduler may choose to block until the task has been executed, but most will add it to a queue of pending
|
|
17
|
+
# tasks, only blocking when that queue's capacity has been reached.
|
|
18
|
+
#
|
|
19
|
+
# @!macro modes
|
|
20
|
+
#
|
|
21
|
+
# @param args [Array]
|
|
22
|
+
# Arguments to pass to the scheduled block.
|
|
23
|
+
# May be handled according to `mode`.
|
|
24
|
+
#
|
|
25
|
+
# @param mode [Symbol]
|
|
26
|
+
# The mode in which to schedule the task. Defaults to `:copy`.
|
|
27
|
+
# May be ignored by some schedulers.
|
|
28
|
+
#
|
|
29
|
+
# @param auto_local [Boolean]
|
|
30
|
+
# Whether to automatically use a local mode when possible. Defaults to `true`.
|
|
31
|
+
# May be ignored by some schedulers.
|
|
32
|
+
#
|
|
33
|
+
# @yield [*args] The block to be executed by the scheduler.
|
|
34
|
+
# @yieldparam args [Array] The arguments passed to the block.
|
|
35
|
+
# @yieldreceiver [BasicObject, nil]
|
|
36
|
+
# Local mode will not touch the block's binding (self stays the same), but other modes may change it to `nil`.
|
|
37
|
+
#
|
|
38
|
+
# @return [self]
|
|
39
|
+
#
|
|
40
|
+
# @!method close
|
|
41
|
+
# @abstract This method must be implemented by concrete scheduler subclasses.
|
|
42
|
+
# Closes the scheduler, releasing any resources it holds.
|
|
43
|
+
# Once closed, the scheduler cannot be used to schedule new tasks.
|
|
44
|
+
# Will drain any pending tasks before fully closing. If tasks are running indefinitely, it may block.
|
|
45
|
+
# @return [self]
|
|
46
|
+
#
|
|
47
|
+
# @!method closed?
|
|
48
|
+
# @abstract This method must be implemented by concrete scheduler subclasses.
|
|
49
|
+
# @return [Boolean] Whether the scheduler is closed.
|
|
50
|
+
#
|
|
51
|
+
# @!method state
|
|
52
|
+
# @abstract This method must be implemented by concrete scheduler subclasses.
|
|
53
|
+
# @return [Symbol]
|
|
54
|
+
# The current state of the scheduler.
|
|
55
|
+
#
|
|
56
|
+
# Common states include:
|
|
57
|
+
# * `:initialized`, `:launching` and `:setup` for the setup phase.
|
|
58
|
+
# * `:running` for the execution phase.
|
|
59
|
+
# * `:closing`, `:closed`, and `:error` for the termination phase.
|
|
60
|
+
#
|
|
61
|
+
# Not all schedulers will implement every state.
|
|
62
|
+
#
|
|
63
|
+
# @!method ractor_safe?
|
|
64
|
+
# @abstract Schedulers should include {Shareable} or {Unshareable}, which implement this method.
|
|
65
|
+
# @return [Boolean] Whether the scheduler is safe to use across Ractors.
|
|
66
|
+
class Scheduler
|
|
67
|
+
include Internal::Noncopyable
|
|
68
|
+
|
|
69
|
+
# An error that occurred during the scheduler's operation, if any.
|
|
70
|
+
# This is primarily for scheduling errors, not execution errors.
|
|
71
|
+
# You can check this if the {#state} is `:error`.
|
|
72
|
+
def error = nil
|
|
73
|
+
|
|
74
|
+
# @param wait [Boolean] Whether to wait for the owner to be non-nil before checking if the scheduler is local.
|
|
75
|
+
# @return [Boolean] Whether the scheduler is local for the current Ractor.
|
|
76
|
+
def local?(wait: true) = false # rubocop:disable Lint/UnusedMethodArgument
|
|
77
|
+
|
|
78
|
+
# Like {#schedule}, with two differences:
|
|
79
|
+
# 1. If {#local?} returns true, and it would run in local mode (either due to `auto_local` or explicitly set
|
|
80
|
+
# `mode: :local`), it executes the block directly without enqueuing it.
|
|
81
|
+
# 2. It blocks until the block has been executed, either immediately in local mode or after being scheduled.
|
|
82
|
+
#
|
|
83
|
+
# @param (see #schedule)
|
|
84
|
+
# @return [self]
|
|
85
|
+
def execute(*, mode: :copy, auto_local: true, &callback)
|
|
86
|
+
raise LocalJumpError, "Cannot yield without a block" unless block_given?
|
|
87
|
+
raise SchedulerClosedError, "cannot execute task on a closed scheduler" if closed?
|
|
88
|
+
|
|
89
|
+
if (auto_local || mode == :local) && local?
|
|
90
|
+
raise SchedulerClosedError, "cannot execute task on a closed scheduler" if closed?
|
|
91
|
+
yield(*)
|
|
92
|
+
return self
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
ran = Farce::Flag.new(false)
|
|
96
|
+
signal = Signal.new
|
|
97
|
+
callback = Ractor.shareable_proc(&callback) unless Ractor.shareable?(callback)
|
|
98
|
+
|
|
99
|
+
schedule(callback, ran, signal, *, mode:, auto_local:) do |callback, ran, signal, *args|
|
|
100
|
+
callback.call(*args)
|
|
101
|
+
ensure
|
|
102
|
+
ran.set
|
|
103
|
+
signal.broadcast
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
signal.wait_until { ran.value }
|
|
107
|
+
self
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|