farce 0.1.0-x86_64-linux-gnu → 0.3.0-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 +4 -4
- data/CHANGELOG.md +127 -1
- data/README.md +111 -17
- data/docs/gems/dry-types.md +8 -8
- data/docs/modes.md +75 -15
- data/docs/scopes.md +3 -1
- data/docs/variants.md +18 -0
- data/ext/farce/atom.c +37 -22
- data/ext/farce/bounded_map.c +17 -13
- data/ext/farce/containers.h +15 -0
- data/ext/farce/counter.c +13 -18
- data/ext/farce/exchanger.c +5 -1
- data/ext/farce/farce.c +1 -1
- data/ext/farce/flag.c +39 -3
- data/ext/farce/io.c +3 -3
- data/ext/farce/lock.c +17 -23
- data/ext/farce/map.c +88 -66
- data/ext/farce/priority_queue.c +55 -43
- data/ext/farce/queue.c +10 -4
- data/ext/farce/reactor.c +52 -25
- data/ext/farce/reactor.h +1 -1
- data/ext/farce/signal.c +5 -1
- data/ext/farce/transaction.c +20 -24
- data/ext/farce/tree_map.c +33 -18
- data/ext/farce/trie.c +81 -43
- data/ext/farce/unshareable.c +168 -19
- data/ext/farce/unshared_io_pool.h +21 -12
- data/ext/farce/unshared_signal.c +13 -2
- data/ext/farce/unshared_wait.h +3 -0
- data/ext/farce/vector.c +82 -18
- data/ext/farce/weak_map.c +75 -63
- data/lib/farce/_yard/macros.rb +18 -3
- data/lib/farce/abstract/executor.rb +130 -0
- data/lib/farce/abstract/flag.rb +73 -0
- data/lib/farce/abstract/pool.rb +334 -0
- data/lib/farce/abstract/queue.rb +4 -3
- data/lib/farce/abstract/scheduler.rb +539 -93
- data/lib/farce/abstract/set.rb +17 -5
- data/lib/farce/abstract/sorted_set.rb +2 -2
- data/lib/farce/abstract/timer_queue.rb +49 -10
- data/lib/farce/abstract/vector.rb +510 -28
- data/lib/farce/atom.rb +1 -1
- data/lib/farce/class_mirror.rb +20 -7
- data/lib/farce/config.rb +7 -1
- data/lib/farce/engine/jruby/signal.rb +7 -4
- data/lib/farce/engine/jvm/flag.rb +15 -3
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/main_scheduler.rb +2 -2
- data/lib/farce/engine/shared/parallel_scheduler.rb +1 -1
- data/lib/farce/engine/shared/proxy_owner.rb +1 -1
- data/lib/farce/engine/shared/unshared_atom.rb +9 -8
- data/lib/farce/engine/shared/unshared_vector.rb +31 -4
- data/lib/farce/engine/shared/vector.rb +8 -0
- data/lib/farce/engine/shared/weak_map/index.rb +14 -1
- data/lib/farce/engine/shared.rb +9 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
- data/lib/farce/envelope.rb +54 -7
- data/lib/farce/exchanger.rb +1 -1
- data/lib/farce/flag.rb +2 -0
- data/lib/farce/integrations/active_support.rb +1 -1
- data/lib/farce/integrations/bson.rb +1 -1
- data/lib/farce/integrations/cbor.rb +1 -1
- data/lib/farce/integrations/concurrent.rb +3 -3
- data/lib/farce/integrations/date.rb +8 -0
- data/lib/farce/integrations/dry_types.rb +7 -4
- data/lib/farce/integrations/json.rb +2 -2
- data/lib/farce/integrations/msgpack.rb +1 -1
- data/lib/farce/integrations/oj.rb +3 -4
- data/lib/farce/integrations/psych.rb +1 -1
- data/lib/farce/integrations/ractor_sharing.rb +1 -1
- data/lib/farce/integrations/sorted_set.rb +1 -1
- data/lib/farce/integrations/weakref.rb +9 -1
- data/lib/farce/integrations/yajl.rb +3 -3
- data/lib/farce/integrations.rb +33 -23
- data/lib/farce/internal/flag_waiting.rb +30 -0
- data/lib/farce/internal/freeze.rb +8 -3
- data/lib/farce/internal/lease_initialization.rb +1 -1
- data/lib/farce/internal/local_executor_methods.rb +33 -0
- data/lib/farce/internal/local_scheduled_task.rb +27 -0
- data/lib/farce/internal/map_value_modes.rb +1 -1
- data/lib/farce/internal/scheduled_task.rb +1 -1
- data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
- data/lib/farce/internal/thread_pool_supervisor.rb +45 -0
- data/lib/farce/internal/unshared_pool_worker.rb +14 -0
- data/lib/farce/internal.rb +14 -0
- data/lib/farce/lazy.rb +4 -4
- data/lib/farce/lazy_ref.rb +3 -3
- data/lib/farce/lfu_map.rb +1 -1
- data/lib/farce/local/flag.rb +4 -0
- data/lib/farce/local/pool.rb +111 -0
- data/lib/farce/local/scheduler.rb +219 -0
- data/lib/farce/local/scoped.rb +1 -1
- data/lib/farce/lru_map.rb +1 -1
- data/lib/farce/map.rb +2 -2
- data/lib/farce/mode_manager/smart_rule.rb +138 -0
- data/lib/farce/mode_manager.rb +12 -3
- data/lib/farce/molecule.rb +2 -2
- data/lib/farce/pool.rb +2 -290
- data/lib/farce/port.rb +4 -4
- data/lib/farce/priority_queue.rb +1 -1
- data/lib/farce/proxy/register.rb +6 -0
- data/lib/farce/proxy/supervisor.rb +1 -1
- data/lib/farce/proxy.rb +9 -4
- data/lib/farce/queue.rb +1 -1
- data/lib/farce/scheduler.rb +1 -502
- data/lib/farce/set.rb +1 -1
- data/lib/farce/sorted_set.rb +1 -1
- data/lib/farce/task.rb +285 -0
- data/lib/farce/{thread_scheduler.rb → thread_executor.rb} +7 -7
- data/lib/farce/timer_queue.rb +20 -6
- data/lib/farce/transaction/vector.rb +43 -9
- data/lib/farce/transaction/wrapper.rb +14 -0
- data/lib/farce/tree_map.rb +1 -1
- data/lib/farce/unsafe/lfu_map.rb +2 -0
- data/lib/farce/unsafe/lru_map.rb +2 -0
- data/lib/farce/unsafe/tree_map.rb +2 -0
- data/lib/farce/unshareable.rb +8 -19
- data/lib/farce/unshared/atom.rb +3 -0
- data/lib/farce/unshared/lfu_map.rb +2 -0
- data/lib/farce/unshared/lru_map.rb +2 -0
- data/lib/farce/unshared/map.rb +3 -0
- data/lib/farce/unshared/pool.rb +44 -0
- data/lib/farce/unshared/scheduler.rb +89 -0
- data/lib/farce/unshared/set.rb +1 -0
- data/lib/farce/unshared/sorted_set.rb +1 -0
- data/lib/farce/unshared/tree_map.rb +5 -1
- data/lib/farce/unshared/vector.rb +3 -0
- data/lib/farce/unshared/weak_atom.rb +5 -1
- data/lib/farce/unshared/weak_key_map.rb +3 -0
- data/lib/farce/unshared/weak_map.rb +3 -0
- data/lib/farce/unshared/weak_set.rb +1 -0
- data/lib/farce/unshared/weak_value_map.rb +3 -0
- data/lib/farce/vector.rb +44 -19
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +20 -25
- metadata +17 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Unshared
|
|
7
|
+
# An elastic pool of thread workers within one Ractor.
|
|
8
|
+
#
|
|
9
|
+
# Uses the same scaling and fiber schedulers as {Farce::Pool}. Tasks keep their
|
|
10
|
+
# blocks and argument references. `auto_local: true` ignores `mode`. With
|
|
11
|
+
# `auto_local: false`, only `:local` and smart modes are accepted.
|
|
12
|
+
# The pool cannot be copied or moved to another Ractor.
|
|
13
|
+
# A scheduler constructor may capture objects from this Ractor.
|
|
14
|
+
#
|
|
15
|
+
# @example Submit work using local state
|
|
16
|
+
# results = Farce::Unshared::Queue.new
|
|
17
|
+
# pool = Farce::Unshared::Pool.new(max_size: 2)
|
|
18
|
+
# pool.schedule { results.push(:done) }
|
|
19
|
+
# results.pop # => :done
|
|
20
|
+
# pool.close
|
|
21
|
+
class Pool < Abstract::Pool
|
|
22
|
+
include Unshareable
|
|
23
|
+
include Internal::LocalExecutorMethods
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def publish_pool = pin_unshareable
|
|
28
|
+
def prepare_constructor(constructor) = constructor
|
|
29
|
+
def new_queue(capacity:) = Internal::UnsharedQueue.new(capacity:, track_age: true)
|
|
30
|
+
def new_worker = Internal::UnsharedPoolWorker.new(self)
|
|
31
|
+
def new_scheduler(**, &) = Scheduler.new(**, &)
|
|
32
|
+
def launch_scheduler(scheduler) = scheduler.launch_thread
|
|
33
|
+
|
|
34
|
+
def prepare_task(args, block, mode, auto_local)
|
|
35
|
+
validate_local_mode(mode, auto_local)
|
|
36
|
+
Internal::LocalScheduledTask.new(args, block)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def schedule_scaler(started, delay = @grow_after)
|
|
40
|
+
Internal::ThreadPoolSupervisor.current.schedule(self, started, delay)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Unshared
|
|
7
|
+
# A task scheduler that runs work within its creating Ractor.
|
|
8
|
+
#
|
|
9
|
+
# Use {.create} to start a background thread, or install an instance with
|
|
10
|
+
# `Fiber.set_scheduler` on the current thread. Tasks retain their blocks and
|
|
11
|
+
# argument references. The scheduler cannot be copied or moved to another Ractor.
|
|
12
|
+
#
|
|
13
|
+
# `auto_local: true` ignores `mode`. With `auto_local: false`, only `:local`
|
|
14
|
+
# and smart modes are accepted. All accepted modes keep tasks local.
|
|
15
|
+
#
|
|
16
|
+
# @example Run tasks with captured local state
|
|
17
|
+
# results = Farce::Unshared::Queue.new
|
|
18
|
+
# scheduler = Farce::Unshared::Scheduler.create
|
|
19
|
+
# scheduler.schedule { results.push(:done) }
|
|
20
|
+
# results.pop # => :done
|
|
21
|
+
# scheduler.close
|
|
22
|
+
#
|
|
23
|
+
# @!method schedule(*args, mode: :smart, auto_local: true)
|
|
24
|
+
# Enqueue a task while retaining its block and argument references.
|
|
25
|
+
# `mode` is ignored when `auto_local` is true. Otherwise, only local and
|
|
26
|
+
# smart modes are accepted.
|
|
27
|
+
# @param (see Farce::Abstract::Executor#schedule)
|
|
28
|
+
# @return [self]
|
|
29
|
+
class Scheduler < Abstract::Scheduler
|
|
30
|
+
include Unshareable
|
|
31
|
+
include Internal::LocalExecutorMethods
|
|
32
|
+
|
|
33
|
+
# Start a worker thread in this Ractor. Returns the running scheduler.
|
|
34
|
+
# Additional options and the block are forwarded to {#initialize}.
|
|
35
|
+
# @param executor [Class, nil] Thread or a custom executor that stays in this Ractor.
|
|
36
|
+
# @param name [String, nil] Optional worker name.
|
|
37
|
+
# @param priority [Integer, nil] Optional worker thread priority.
|
|
38
|
+
# @yieldreturn [Object] Fiber scheduler to install in the worker.
|
|
39
|
+
# @return [Scheduler]
|
|
40
|
+
def self.create(executor = Thread, name: nil, priority: nil, **, &) = super
|
|
41
|
+
|
|
42
|
+
# Create a scheduler without starting a worker.
|
|
43
|
+
# A constructor block builds the fiber scheduler when launched or installed.
|
|
44
|
+
# It may capture objects from this Ractor.
|
|
45
|
+
#
|
|
46
|
+
# @overload initialize(capacity: 1024, backend: Farce.config.io_backend, &constructor)
|
|
47
|
+
# @param capacity [Integer, nil] Pending-task capacity, or nil for an unbounded queue.
|
|
48
|
+
# @param backend [Symbol] IO backend for the built-in scheduler.
|
|
49
|
+
# @yieldreturn [Object] Fiber scheduler to install in the worker.
|
|
50
|
+
def initialize(...)
|
|
51
|
+
super
|
|
52
|
+
self.owner = Ractor.current
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Start dispatching tasks in a new thread or a custom executor in this Ractor.
|
|
56
|
+
# Rejects Ractor executors before changing the scheduler's state.
|
|
57
|
+
# @param executor [Class, nil] Thread or a custom executor that stays in this Ractor.
|
|
58
|
+
# @param name [String, nil] Optional worker name.
|
|
59
|
+
# @param priority [Integer, nil] Optional worker thread priority.
|
|
60
|
+
# @return [Thread, Object] The worker.
|
|
61
|
+
# @raise [ArgumentError] If a Ractor executor is supplied.
|
|
62
|
+
def launch(executor = Thread, name: nil, priority: nil)
|
|
63
|
+
raise ArgumentError, "Unshared schedulers cannot launch Ractor workers" if executor && executor <= Ractor
|
|
64
|
+
super(executor || Thread, name:, priority:)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @raise [ArgumentError] Unshared schedulers cannot launch Ractor workers.
|
|
68
|
+
def launch_ractor(...) = launch(Ractor, ...)
|
|
69
|
+
|
|
70
|
+
# @param value [Ractor] The creating Ractor.
|
|
71
|
+
# @raise [ArgumentError] If another Ractor is supplied or the assigned owner changes.
|
|
72
|
+
def owner=(value)
|
|
73
|
+
raise ArgumentError, "owner must be the current Ractor" unless value == Ractor.current
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def prepare_constructor(constructor) = constructor
|
|
80
|
+
def new_queue(capacity:) = Internal::UnsharedQueue.new(capacity:)
|
|
81
|
+
def launch_callback = ->(_scheduler, priority, name) { launch!(name, priority) }
|
|
82
|
+
|
|
83
|
+
def prepare_task(args, block, mode, auto_local)
|
|
84
|
+
validate_local_mode(mode, auto_local)
|
|
85
|
+
Internal::LocalScheduledTask.new(args, block)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/farce/unshared/set.rb
CHANGED
|
@@ -14,8 +14,12 @@ module Farce
|
|
|
14
14
|
# map[2].equal?(value) # => true
|
|
15
15
|
class TreeMap < Abstract::TreeMap
|
|
16
16
|
include Unshareable
|
|
17
|
+
include Internal::Freeze::Delegated
|
|
17
18
|
|
|
18
|
-
private
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def new_tree_map(...) = Internal::TreeMap.new(...)
|
|
22
|
+
def freeze_backend = @map
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
@@ -7,6 +7,7 @@ module Farce
|
|
|
7
7
|
# A thread-safe vector for mutable values used within one Ractor.
|
|
8
8
|
class Vector < Abstract::Vector
|
|
9
9
|
include Unshareable
|
|
10
|
+
include Internal::Freeze::Delegated
|
|
10
11
|
|
|
11
12
|
# @param source [Array, nil] Initial values. Values are retained directly.
|
|
12
13
|
# @param compare_by_identity [Boolean] Whether values are compared by identity.
|
|
@@ -14,6 +15,8 @@ module Farce
|
|
|
14
15
|
@vector = Internal::UnsharedVector.new(source, compare_by_identity:)
|
|
15
16
|
super()
|
|
16
17
|
end
|
|
18
|
+
|
|
19
|
+
private def freeze_backend = @vector
|
|
17
20
|
end
|
|
18
21
|
end
|
|
19
22
|
end
|
|
@@ -24,8 +24,12 @@ module Farce
|
|
|
24
24
|
# atom.value.equal?(replacement) # => true
|
|
25
25
|
class WeakAtom < Abstract::WeakAtom
|
|
26
26
|
include Unshareable
|
|
27
|
+
include Internal::Freeze::Delegated
|
|
27
28
|
|
|
28
|
-
private
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def internal_atom_class = Internal::UnsharedWeakAtom
|
|
32
|
+
def freeze_backend = @atom
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -16,6 +16,7 @@ module Farce
|
|
|
16
16
|
# owner = nil
|
|
17
17
|
class WeakKeyMap < Abstract::WeakKeyMap
|
|
18
18
|
include Unshareable
|
|
19
|
+
include Internal::Freeze::Delegated
|
|
19
20
|
|
|
20
21
|
def initialize(
|
|
21
22
|
initial_mapping = nil,
|
|
@@ -39,6 +40,8 @@ module Farce
|
|
|
39
40
|
Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
|
|
40
41
|
super()
|
|
41
42
|
end
|
|
43
|
+
|
|
44
|
+
private def freeze_backend = @map
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
end
|
|
@@ -16,6 +16,7 @@ module Farce
|
|
|
16
16
|
# value = nil
|
|
17
17
|
class WeakMap < Abstract::WeakMap
|
|
18
18
|
include Unshareable
|
|
19
|
+
include Internal::Freeze::Delegated
|
|
19
20
|
|
|
20
21
|
def initialize(
|
|
21
22
|
initial_mapping = nil,
|
|
@@ -39,6 +40,8 @@ module Farce
|
|
|
39
40
|
Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
|
|
40
41
|
super()
|
|
41
42
|
end
|
|
43
|
+
|
|
44
|
+
private def freeze_backend = @map
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
end
|
|
@@ -7,6 +7,7 @@ module Farce
|
|
|
7
7
|
# A thread-safe set that retains mutable elements weakly within one Ractor.
|
|
8
8
|
class WeakSet < Farce::Abstract::WeakSet
|
|
9
9
|
include Unshareable
|
|
10
|
+
include Internal::Freeze::Delegated
|
|
10
11
|
|
|
11
12
|
private def new_map(...) = Farce::Unshared::WeakMap.new(...)
|
|
12
13
|
end
|
|
@@ -15,6 +15,7 @@ module Farce
|
|
|
15
15
|
# value = nil
|
|
16
16
|
class WeakValueMap < Abstract::WeakValueMap
|
|
17
17
|
include Unshareable
|
|
18
|
+
include Internal::Freeze::Delegated
|
|
18
19
|
|
|
19
20
|
def initialize(
|
|
20
21
|
initial_mapping = nil,
|
|
@@ -38,6 +39,8 @@ module Farce
|
|
|
38
39
|
Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
|
|
39
40
|
super()
|
|
40
41
|
end
|
|
42
|
+
|
|
43
|
+
private def freeze_backend = @map
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
end
|
data/lib/farce/vector.rb
CHANGED
|
@@ -10,9 +10,9 @@ module Farce
|
|
|
10
10
|
# vector = Farce::Vector.new([[]], mode: :make_shareable)
|
|
11
11
|
# vector.update(0) { |jobs| jobs + [:finished] } # => [:finished]
|
|
12
12
|
#
|
|
13
|
-
# @!method append(
|
|
14
|
-
# Append
|
|
15
|
-
# @param
|
|
13
|
+
# @!method append(*values, mode: nil, timeout: nil)
|
|
14
|
+
# Append values using the same options as {#push}.
|
|
15
|
+
# @param values [Array<BasicObject>] The values to append.
|
|
16
16
|
# @param mode [Symbol, nil] The transfer mode, or nil to use the default.
|
|
17
17
|
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
18
18
|
# @return [self, false] Self on success, or false on timeout.
|
|
@@ -23,7 +23,7 @@ module Farce
|
|
|
23
23
|
# @param source [Array, nil] Initial values. The source array is not retained.
|
|
24
24
|
# @param mode [Symbol] The default value transfer mode.
|
|
25
25
|
# @param compare_by_identity [Boolean] Whether values are compared by identity.
|
|
26
|
-
def initialize(source = nil, mode: :
|
|
26
|
+
def initialize(source = nil, mode: :smart, compare_by_identity: false)
|
|
27
27
|
raise TypeError, "source must be an Array" unless source.nil? || source.is_a?(Array)
|
|
28
28
|
unless true.equal?(compare_by_identity) || false.equal?(compare_by_identity)
|
|
29
29
|
raise ArgumentError, "compare_by_identity must be true or false"
|
|
@@ -64,13 +64,20 @@ module Farce
|
|
|
64
64
|
def shareable_values? = true
|
|
65
65
|
|
|
66
66
|
# (see Farce::Abstract::Vector#[])
|
|
67
|
-
def [](index
|
|
67
|
+
def [](index, length = UNDEFINED)
|
|
68
|
+
return @manager.unwrap(@vector[index]) if length.equal?(UNDEFINED) && !index.is_a?(Range)
|
|
69
|
+
slice(index, length)
|
|
70
|
+
end
|
|
68
71
|
|
|
69
72
|
# (see Farce::Abstract::Vector#[]=)
|
|
70
|
-
def []=(index, value)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
def []=(index, value, replacement = UNDEFINED)
|
|
74
|
+
if replacement.equal?(UNDEFINED) && !index.is_a?(Range)
|
|
75
|
+
check_frozen!
|
|
76
|
+
@vector[index] = @manager.wrap(value)
|
|
77
|
+
value
|
|
78
|
+
else
|
|
79
|
+
assign_vector_slice(index, value, replacement)
|
|
80
|
+
end
|
|
74
81
|
end
|
|
75
82
|
|
|
76
83
|
# (see Farce::Abstract::Vector#get)
|
|
@@ -85,13 +92,21 @@ module Farce
|
|
|
85
92
|
|
|
86
93
|
# (see Farce::Abstract::Vector#push)
|
|
87
94
|
# @param mode [Symbol, nil] The transfer mode, or nil to use the default.
|
|
88
|
-
def push(value, mode: nil, timeout: nil)
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
def push(value = UNDEFINED, *rest, mode: nil, timeout: nil)
|
|
96
|
+
if rest.empty? && !value.equal?(UNDEFINED)
|
|
97
|
+
check_frozen!
|
|
98
|
+
stored = mode.nil? ? @manager.wrap(value) : @manager.wrap(value, mode:)
|
|
99
|
+
completed = timeout.nil? ? @vector.push(stored) : @vector.push(stored, timeout:)
|
|
100
|
+
return completed ? self : false
|
|
101
|
+
end
|
|
102
|
+
push_values(value.equal?(UNDEFINED) ? rest : [value, *rest], mode:, timeout:)
|
|
91
103
|
end
|
|
92
104
|
|
|
93
105
|
# (see Farce::Abstract::Vector#pop)
|
|
94
|
-
def pop(
|
|
106
|
+
def pop(count = UNDEFINED, timeout: nil)
|
|
107
|
+
return @manager.unwrap(timeout.nil? ? @vector.pop : @vector.pop(timeout:)) if count.equal?(UNDEFINED)
|
|
108
|
+
pop_values(count, timeout:)
|
|
109
|
+
end
|
|
95
110
|
|
|
96
111
|
# (see Farce::Abstract::Vector#swap)
|
|
97
112
|
# @!macro modes
|
|
@@ -183,7 +198,9 @@ module Farce
|
|
|
183
198
|
|
|
184
199
|
protected
|
|
185
200
|
|
|
186
|
-
def logical_value(value)
|
|
201
|
+
def logical_value(value) = @manager.unwrap(value)
|
|
202
|
+
def deletion_comparison(value) = wrap_comparison(value)
|
|
203
|
+
def deletion_match?(stored, expected) = values_equal?(stored, expected)
|
|
187
204
|
|
|
188
205
|
def build_derived_vector(values)
|
|
189
206
|
self.class.allocate.initialize_derived_vector(values, @manager, @compare_by_identity)
|
|
@@ -206,11 +223,19 @@ module Farce
|
|
|
206
223
|
|
|
207
224
|
private
|
|
208
225
|
|
|
209
|
-
def inspect_value(inspector, value)
|
|
210
|
-
def derived_storage(value)
|
|
211
|
-
def
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
def inspect_value(inspector, value) = super(inspector, value, @manager)
|
|
227
|
+
def derived_storage(value) = @manager.wrap(value)
|
|
228
|
+
def prepare_vector_value(value, mode: nil) = @manager.wrap(value, mode:)
|
|
229
|
+
|
|
230
|
+
# Expanded descendants have no independent envelope to reuse. Copy them rather than
|
|
231
|
+
# moving them out of a retained parent Array or another sequence's storage.
|
|
232
|
+
def prepare_sequence_value(value)
|
|
233
|
+
@manager.wrap(value, mode: mode == :move ? :copy : nil)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def freeze_backend = @vector
|
|
237
|
+
def wrap_comparison(value) = @manager.wrap(value, mode: compare_by_identity? ? :local : :copy)
|
|
238
|
+
def values_equal?(left, right) = @manager.same_value?(left, right, identity: compare_by_identity?)
|
|
214
239
|
|
|
215
240
|
def timeout_deadline(timeout)
|
|
216
241
|
return if timeout.nil?
|
data/lib/farce/version.rb
CHANGED
data/lib/farce.rb
CHANGED
|
@@ -54,7 +54,10 @@ module Farce
|
|
|
54
54
|
|
|
55
55
|
# The valid transfer modes for values that are not Ractor-shareable.
|
|
56
56
|
# @return [::Set<Symbol>]
|
|
57
|
-
MODES = ::Set[
|
|
57
|
+
MODES = ::Set[
|
|
58
|
+
:copy, :marshal, :move, :local, :make_shareable, :mutable, :raise, :shareable_copy, :dedup, :proxy,
|
|
59
|
+
:smart, :smart_raise, :smart_move, :smart_copy,
|
|
60
|
+
].freeze
|
|
58
61
|
|
|
59
62
|
UNDEFINED = Internal::Undefined.new("UNDEFINED")
|
|
60
63
|
|
|
@@ -171,7 +174,7 @@ module Farce
|
|
|
171
174
|
DEDUPER.dedup(object, **)
|
|
172
175
|
end
|
|
173
176
|
|
|
174
|
-
# @overload enfarce(object, freeze: nil, mode: :
|
|
177
|
+
# @overload enfarce(object, freeze: nil, mode: :smart)
|
|
175
178
|
# Converts vanilla Ruby objects into their {Farce} equivalents.
|
|
176
179
|
#
|
|
177
180
|
# @!macro modes
|
|
@@ -357,7 +360,7 @@ module Farce
|
|
|
357
360
|
# This allows scheduling without blocking the current thread.
|
|
358
361
|
#
|
|
359
362
|
# On JRuby and TruffleRuby, blocks run inline because there is no native Ractor isolation.
|
|
360
|
-
# The returned {
|
|
363
|
+
# The returned {ThreadExecutor} starts a new thread for each scheduled task.
|
|
361
364
|
#
|
|
362
365
|
# @example
|
|
363
366
|
# $results = []
|
|
@@ -396,7 +399,7 @@ module Farce
|
|
|
396
399
|
# # Hi from the current ractor!
|
|
397
400
|
# # Hi again from the main ractor!
|
|
398
401
|
#
|
|
399
|
-
# @overload on_main(*args, mode: :
|
|
402
|
+
# @overload on_main(*args, mode: :smart)
|
|
400
403
|
# @param args [Array] The arguments to be passed to the block.
|
|
401
404
|
# @param mode [Symbol] The argument transfer mode when called from another ractor.
|
|
402
405
|
# @yield [*args] The block to be executed on the main ractor.
|
|
@@ -405,9 +408,9 @@ module Farce
|
|
|
405
408
|
#
|
|
406
409
|
# @overload on_main
|
|
407
410
|
# Returns a scheduler that executes tasks on the main ractor.
|
|
408
|
-
# @return [Abstract::
|
|
411
|
+
# @return [Abstract::Executor]
|
|
409
412
|
#
|
|
410
|
-
# @return [Abstract::
|
|
413
|
+
# @return [Abstract::Executor, nil]
|
|
411
414
|
# @see .in_parallel
|
|
412
415
|
def self.on_main(*args, mode: UNDEFINED, &)
|
|
413
416
|
unless block_given?
|
|
@@ -418,7 +421,7 @@ module Farce
|
|
|
418
421
|
if Ractor.main?
|
|
419
422
|
yield(*args)
|
|
420
423
|
else
|
|
421
|
-
mode = :
|
|
424
|
+
mode = :smart if UNDEFINED.equal?(mode)
|
|
422
425
|
Internal::MainScheduler.execute(*args, mode:, auto_local: false, &)
|
|
423
426
|
end
|
|
424
427
|
|
|
@@ -438,16 +441,16 @@ module Farce
|
|
|
438
441
|
# Farce.in_parallel("hello") { |message| puts message.upcase }
|
|
439
442
|
# Farce.in_parallel.schedule { puts "another task" }
|
|
440
443
|
#
|
|
441
|
-
# @overload in_parallel(*args, mode: :
|
|
444
|
+
# @overload in_parallel(*args, mode: :smart)
|
|
442
445
|
# @param args [Array<Object>] Arguments passed to the block.
|
|
443
446
|
# @param mode [Symbol] Argument transfer mode. Ignored on JRuby and TruffleRuby.
|
|
444
447
|
# @yield [*args] The task to schedule.
|
|
445
448
|
# @return [nil]
|
|
446
449
|
#
|
|
447
450
|
# @overload in_parallel
|
|
448
|
-
# @return [Abstract::
|
|
451
|
+
# @return [Abstract::Executor] The shared scheduler.
|
|
449
452
|
#
|
|
450
|
-
# @return [Abstract::
|
|
453
|
+
# @return [Abstract::Executor, nil]
|
|
451
454
|
# @see .on_main
|
|
452
455
|
def self.in_parallel(*args, mode: UNDEFINED, &)
|
|
453
456
|
unless block_given?
|
|
@@ -455,12 +458,12 @@ module Farce
|
|
|
455
458
|
return Internal::ParallelScheduler
|
|
456
459
|
end
|
|
457
460
|
|
|
458
|
-
mode = :
|
|
461
|
+
mode = :smart if UNDEFINED.equal?(mode)
|
|
459
462
|
Internal::ParallelScheduler.schedule(*args, mode:, &)
|
|
460
463
|
nil
|
|
461
464
|
end
|
|
462
465
|
|
|
463
|
-
# @overload schedule(*args, mode: :
|
|
466
|
+
# @overload schedule(*args, mode: :smart, auto_local: true, **kwargs)
|
|
464
467
|
# Schedules work to be executed out of band.
|
|
465
468
|
#
|
|
466
469
|
# If the `mode` is set to `:local`, it will use the current thread's fiber scheduler to schedule the task.
|
|
@@ -486,26 +489,18 @@ module Farce
|
|
|
486
489
|
# @param kwargs [Hash] Additional keyword arguments passed to the scheduler.
|
|
487
490
|
# @yield [*args] The task to schedule.
|
|
488
491
|
# @return [nil]
|
|
489
|
-
def self.schedule(*, mode: :
|
|
492
|
+
def self.schedule(*, mode: :smart, auto_local: true, **, &)
|
|
490
493
|
raise LocalJumpError, "no block given" unless block_given?
|
|
491
494
|
|
|
492
495
|
if auto_local || mode == :local
|
|
493
|
-
|
|
494
|
-
|
|
496
|
+
scheduler = Internal.local_scheduler(create: mode == :local)
|
|
497
|
+
if scheduler && !scheduler.is_a?(Abstract::Executor)
|
|
498
|
+
scheduler.fiber(**) { yield(*) }
|
|
495
499
|
return
|
|
496
500
|
end
|
|
497
|
-
scheduler = Ractor.main? ? Internal::MainScheduler : Internal::Storage[:local_scheduler]
|
|
498
501
|
end
|
|
499
502
|
|
|
500
|
-
scheduler ||=
|
|
501
|
-
if mode == :local
|
|
502
|
-
Internal::Storage.store_if_absent(:local_scheduler) do
|
|
503
|
-
Internal.native_ractors? ? Scheduler.create(Thread) : ThreadScheduler.new
|
|
504
|
-
end
|
|
505
|
-
else
|
|
506
|
-
Internal::ParallelScheduler
|
|
507
|
-
end
|
|
508
|
-
|
|
503
|
+
scheduler ||= Internal::ParallelScheduler
|
|
509
504
|
scheduler.schedule(*, mode:, auto_local:, **, &)
|
|
510
505
|
nil
|
|
511
506
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: farce
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: x86_64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Haase
|
|
@@ -83,6 +83,7 @@ files:
|
|
|
83
83
|
- lib/farce/abstract/counter.rb
|
|
84
84
|
- lib/farce/abstract/duplicable_map.rb
|
|
85
85
|
- lib/farce/abstract/exchanger.rb
|
|
86
|
+
- lib/farce/abstract/executor.rb
|
|
86
87
|
- lib/farce/abstract/flag.rb
|
|
87
88
|
- lib/farce/abstract/lazy.rb
|
|
88
89
|
- lib/farce/abstract/lease.rb
|
|
@@ -92,6 +93,7 @@ files:
|
|
|
92
93
|
- lib/farce/abstract/lru_map.rb
|
|
93
94
|
- lib/farce/abstract/map.rb
|
|
94
95
|
- lib/farce/abstract/molecule.rb
|
|
96
|
+
- lib/farce/abstract/pool.rb
|
|
95
97
|
- lib/farce/abstract/port.rb
|
|
96
98
|
- lib/farce/abstract/priority_queue.rb
|
|
97
99
|
- lib/farce/abstract/queue.rb
|
|
@@ -157,6 +159,7 @@ files:
|
|
|
157
159
|
- lib/farce/engine/ruby/shared/proxy_owner.rb
|
|
158
160
|
- lib/farce/engine/ruby/shared/ractor_methods.rb
|
|
159
161
|
- lib/farce/engine/ruby/shared/ractor_selector.rb
|
|
162
|
+
- lib/farce/engine/ruby/shared/require_hook.rb
|
|
160
163
|
- lib/farce/engine/ruby/shared/strict_map.rb
|
|
161
164
|
- lib/farce/engine/ruby/shared/unshared_vector.rb
|
|
162
165
|
- lib/farce/engine/ruby/shared/vault.rb
|
|
@@ -229,6 +232,7 @@ files:
|
|
|
229
232
|
- lib/farce/integrations/bson.rb
|
|
230
233
|
- lib/farce/integrations/cbor.rb
|
|
231
234
|
- lib/farce/integrations/concurrent.rb
|
|
235
|
+
- lib/farce/integrations/date.rb
|
|
232
236
|
- lib/farce/integrations/dry-types.rb
|
|
233
237
|
- lib/farce/integrations/dry_types.rb
|
|
234
238
|
- lib/farce/integrations/json.rb
|
|
@@ -252,6 +256,7 @@ files:
|
|
|
252
256
|
- lib/farce/internal/delegation.rb
|
|
253
257
|
- lib/farce/internal/external_transaction.rb
|
|
254
258
|
- lib/farce/internal/fake_ractor.rb
|
|
259
|
+
- lib/farce/internal/flag_waiting.rb
|
|
255
260
|
- lib/farce/internal/freeze.rb
|
|
256
261
|
- lib/farce/internal/inspect.rb
|
|
257
262
|
- lib/farce/internal/key_lock_map.rb
|
|
@@ -261,6 +266,8 @@ files:
|
|
|
261
266
|
- lib/farce/internal/lease_pool_state.rb
|
|
262
267
|
- lib/farce/internal/lease_state.rb
|
|
263
268
|
- lib/farce/internal/lease_waiting.rb
|
|
269
|
+
- lib/farce/internal/local_executor_methods.rb
|
|
270
|
+
- lib/farce/internal/local_scheduled_task.rb
|
|
264
271
|
- lib/farce/internal/managed_queue.rb
|
|
265
272
|
- lib/farce/internal/map_value_modes.rb
|
|
266
273
|
- lib/farce/internal/marshal_support.rb
|
|
@@ -286,12 +293,14 @@ files:
|
|
|
286
293
|
- lib/farce/internal/strict_lease_map.rb
|
|
287
294
|
- lib/farce/internal/strict_lease_pool.rb
|
|
288
295
|
- lib/farce/internal/thread_pool.rb
|
|
296
|
+
- lib/farce/internal/thread_pool_supervisor.rb
|
|
289
297
|
- lib/farce/internal/transaction_conflict.rb
|
|
290
298
|
- lib/farce/internal/transaction_freeze_guard.rb
|
|
291
299
|
- lib/farce/internal/transaction_map_snapshot.rb
|
|
292
300
|
- lib/farce/internal/undefined.rb
|
|
293
301
|
- lib/farce/internal/unshared_lease.rb
|
|
294
302
|
- lib/farce/internal/unshared_lease_pool.rb
|
|
303
|
+
- lib/farce/internal/unshared_pool_worker.rb
|
|
295
304
|
- lib/farce/internal/unshared_queue_waiting.rb
|
|
296
305
|
- lib/farce/internal/value_serialization.rb
|
|
297
306
|
- lib/farce/internal/weak_map_value_modes.rb
|
|
@@ -315,8 +324,10 @@ files:
|
|
|
315
324
|
- lib/farce/local/lru_map.rb
|
|
316
325
|
- lib/farce/local/map.rb
|
|
317
326
|
- lib/farce/local/molecule.rb
|
|
327
|
+
- lib/farce/local/pool.rb
|
|
318
328
|
- lib/farce/local/priority_queue.rb
|
|
319
329
|
- lib/farce/local/queue.rb
|
|
330
|
+
- lib/farce/local/scheduler.rb
|
|
320
331
|
- lib/farce/local/scoped.rb
|
|
321
332
|
- lib/farce/local/set.rb
|
|
322
333
|
- lib/farce/local/sorted_set.rb
|
|
@@ -332,6 +343,7 @@ files:
|
|
|
332
343
|
- lib/farce/lru_map.rb
|
|
333
344
|
- lib/farce/map.rb
|
|
334
345
|
- lib/farce/mode_manager.rb
|
|
346
|
+
- lib/farce/mode_manager/smart_rule.rb
|
|
335
347
|
- lib/farce/molecule.rb
|
|
336
348
|
- lib/farce/mutable.rb
|
|
337
349
|
- lib/farce/pool.rb
|
|
@@ -380,7 +392,8 @@ files:
|
|
|
380
392
|
- lib/farce/strict/weak_set.rb
|
|
381
393
|
- lib/farce/strict/weak_value_map.rb
|
|
382
394
|
- lib/farce/system.rb
|
|
383
|
-
- lib/farce/
|
|
395
|
+
- lib/farce/task.rb
|
|
396
|
+
- lib/farce/thread_executor.rb
|
|
384
397
|
- lib/farce/timer_queue.rb
|
|
385
398
|
- lib/farce/transaction.rb
|
|
386
399
|
- lib/farce/transaction/atom.rb
|
|
@@ -413,8 +426,10 @@ files:
|
|
|
413
426
|
- lib/farce/unshared/lru_map.rb
|
|
414
427
|
- lib/farce/unshared/map.rb
|
|
415
428
|
- lib/farce/unshared/molecule.rb
|
|
429
|
+
- lib/farce/unshared/pool.rb
|
|
416
430
|
- lib/farce/unshared/priority_queue.rb
|
|
417
431
|
- lib/farce/unshared/queue.rb
|
|
432
|
+
- lib/farce/unshared/scheduler.rb
|
|
418
433
|
- lib/farce/unshared/set.rb
|
|
419
434
|
- lib/farce/unshared/sorted_set.rb
|
|
420
435
|
- lib/farce/unshared/timer_queue.rb
|