farce 0.1.0-java → 0.2.0-java

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -1
  3. data/README.md +72 -16
  4. data/docs/gems/dry-types.md +8 -8
  5. data/docs/modes.md +67 -10
  6. data/lib/farce/_yard/macros.rb +18 -3
  7. data/lib/farce/abstract/flag.rb +73 -0
  8. data/lib/farce/abstract/queue.rb +4 -3
  9. data/lib/farce/abstract/scheduler.rb +3 -3
  10. data/lib/farce/abstract/set.rb +17 -5
  11. data/lib/farce/abstract/sorted_set.rb +2 -2
  12. data/lib/farce/abstract/timer_queue.rb +49 -10
  13. data/lib/farce/abstract/vector.rb +510 -28
  14. data/lib/farce/atom.rb +1 -1
  15. data/lib/farce/class_mirror.rb +20 -7
  16. data/lib/farce/config.rb +7 -1
  17. data/lib/farce/engine/jvm/flag.rb +15 -3
  18. data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
  19. data/lib/farce/engine/ruby.rb +7 -0
  20. data/lib/farce/engine/shared/unshared_vector.rb +31 -4
  21. data/lib/farce/engine/shared/vector.rb +8 -0
  22. data/lib/farce/engine/shared/weak_map/index.rb +14 -1
  23. data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
  24. data/lib/farce/envelope.rb +54 -7
  25. data/lib/farce/exchanger.rb +1 -1
  26. data/lib/farce/flag.rb +2 -0
  27. data/lib/farce/integrations/active_support.rb +1 -1
  28. data/lib/farce/integrations/bson.rb +1 -1
  29. data/lib/farce/integrations/cbor.rb +1 -1
  30. data/lib/farce/integrations/concurrent.rb +3 -3
  31. data/lib/farce/integrations/date.rb +8 -0
  32. data/lib/farce/integrations/dry_types.rb +7 -4
  33. data/lib/farce/integrations/json.rb +2 -2
  34. data/lib/farce/integrations/msgpack.rb +1 -1
  35. data/lib/farce/integrations/oj.rb +3 -4
  36. data/lib/farce/integrations/psych.rb +1 -1
  37. data/lib/farce/integrations/ractor_sharing.rb +1 -1
  38. data/lib/farce/integrations/sorted_set.rb +1 -1
  39. data/lib/farce/integrations/weakref.rb +9 -1
  40. data/lib/farce/integrations/yajl.rb +3 -3
  41. data/lib/farce/integrations.rb +33 -23
  42. data/lib/farce/internal/flag_waiting.rb +30 -0
  43. data/lib/farce/internal/freeze.rb +8 -3
  44. data/lib/farce/internal/map_value_modes.rb +1 -1
  45. data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
  46. data/lib/farce/lazy.rb +4 -4
  47. data/lib/farce/lazy_ref.rb +3 -3
  48. data/lib/farce/lfu_map.rb +1 -1
  49. data/lib/farce/local/flag.rb +4 -0
  50. data/lib/farce/local/scoped.rb +1 -1
  51. data/lib/farce/lru_map.rb +1 -1
  52. data/lib/farce/map.rb +2 -2
  53. data/lib/farce/mode_manager/smart_rule.rb +138 -0
  54. data/lib/farce/mode_manager.rb +12 -3
  55. data/lib/farce/molecule.rb +2 -2
  56. data/lib/farce/pool.rb +1 -1
  57. data/lib/farce/port.rb +4 -4
  58. data/lib/farce/priority_queue.rb +1 -1
  59. data/lib/farce/proxy/register.rb +6 -0
  60. data/lib/farce/proxy/supervisor.rb +1 -1
  61. data/lib/farce/proxy.rb +7 -2
  62. data/lib/farce/queue.rb +1 -1
  63. data/lib/farce/scheduler.rb +2 -2
  64. data/lib/farce/set.rb +1 -1
  65. data/lib/farce/sorted_set.rb +1 -1
  66. data/lib/farce/timer_queue.rb +20 -6
  67. data/lib/farce/transaction/vector.rb +43 -9
  68. data/lib/farce/transaction/wrapper.rb +14 -0
  69. data/lib/farce/tree_map.rb +1 -1
  70. data/lib/farce/unsafe/lfu_map.rb +2 -0
  71. data/lib/farce/unsafe/lru_map.rb +2 -0
  72. data/lib/farce/unsafe/tree_map.rb +2 -0
  73. data/lib/farce/unshareable.rb +8 -19
  74. data/lib/farce/unshared/atom.rb +3 -0
  75. data/lib/farce/unshared/lfu_map.rb +2 -0
  76. data/lib/farce/unshared/lru_map.rb +2 -0
  77. data/lib/farce/unshared/map.rb +3 -0
  78. data/lib/farce/unshared/set.rb +1 -0
  79. data/lib/farce/unshared/sorted_set.rb +1 -0
  80. data/lib/farce/unshared/tree_map.rb +5 -1
  81. data/lib/farce/unshared/vector.rb +3 -0
  82. data/lib/farce/unshared/weak_atom.rb +5 -1
  83. data/lib/farce/unshared/weak_key_map.rb +3 -0
  84. data/lib/farce/unshared/weak_map.rb +3 -0
  85. data/lib/farce/unshared/weak_set.rb +1 -0
  86. data/lib/farce/unshared/weak_value_map.rb +3 -0
  87. data/lib/farce/vector.rb +44 -19
  88. data/lib/farce/version.rb +1 -1
  89. data/lib/farce.rb +11 -8
  90. metadata +6 -2
@@ -6,7 +6,7 @@ module Farce
6
6
  module Abstract
7
7
  # @abstract A shared super class for all scheduler implementations.
8
8
  #
9
- # @!method schedule(*args, mode: :copy, auto_local: true)
9
+ # @!method schedule(*args, mode: :smart, auto_local: true)
10
10
  # @abstract This method must be implemented by concrete scheduler subclasses.
11
11
  #
12
12
  # Schedules a block for execution.
@@ -23,7 +23,7 @@ module Farce
23
23
  # May be handled according to `mode`.
24
24
  #
25
25
  # @param mode [Symbol]
26
- # The mode in which to schedule the task. Defaults to `:copy`.
26
+ # The mode in which to schedule the task. Defaults to `:smart`.
27
27
  # May be ignored by some schedulers.
28
28
  #
29
29
  # @param auto_local [Boolean]
@@ -82,7 +82,7 @@ module Farce
82
82
  #
83
83
  # @param (see #schedule)
84
84
  # @return [self]
85
- def execute(*, mode: :copy, auto_local: true, &callback)
85
+ def execute(*, mode: :smart, auto_local: true, &callback)
86
86
  raise LocalJumpError, "Cannot yield without a block" unless block_given?
87
87
  raise SchedulerClosedError, "cannot execute task on a closed scheduler" if closed?
88
88
 
@@ -61,7 +61,7 @@ module Farce
61
61
  # @param normalize [Symbol, Proc, Hash, Farce::Abstract::Map, nil] The element normalizer.
62
62
  # @param compare_by_identity [Boolean] Whether membership uses object identity.
63
63
  # @param mode [Symbol] The default transfer mode for Farce::Set, Farce::SortedSet,
64
- # and Farce::WeakSet. Defaults to :copy for strong sets and :raise for WeakSet.
64
+ # and Farce::WeakSet. Defaults to :smart for strong sets and :raise for WeakSet.
65
65
  # @param options [Hash] Additional options for the selected variant.
66
66
  # @option options [Symbol] scope (:ractor) The scope used by Farce::Local variants.
67
67
  # @yield [element] Optionally transform each initial element before storage.
@@ -753,11 +753,22 @@ module Farce
753
753
  def prepare_mode_entry(element, requested_mode)
754
754
  if identity_membership?(element) && !Ractor.shareable?(element)
755
755
  case requested_mode
756
- when :copy
756
+ when :copy, :marshal
757
757
  raise ArgumentError, "identity comparison cannot copy a non-shareable element"
758
758
  when :shareable_copy, :make_shareable
759
759
  payload = @manager.wrap(element, mode: requested_mode)
760
760
  return [insertion_key(payload), payload]
761
+ when :smart, :smart_raise, :smart_copy, :smart_move
762
+ token = IDENTITY_TOKENS[element]
763
+ payload = @manager.wrap(element, mode: requested_mode)
764
+ case payload
765
+ when Envelope::Copy, Envelope::Marshal
766
+ raise ArgumentError, "identity comparison cannot copy a non-shareable element"
767
+ when Envelope::Move
768
+ return [MembershipKey.new(token || Object.new.freeze, identity: true), payload]
769
+ end
770
+ key = @manager.managed_envelope?(payload) ? insertion_key(element) : insertion_key(payload)
771
+ return [key, payload]
761
772
  end
762
773
  end
763
774
 
@@ -812,9 +823,10 @@ module Farce
812
823
 
813
824
  def stored_mode(entry)
814
825
  case entry.payload
815
- when Envelope::Copy then :copy
816
- when Envelope::Local then :local
817
- when Envelope::Move then :move
826
+ when Envelope::Copy then :copy
827
+ when Envelope::Marshal then :marshal
828
+ when Envelope::Local then :local
829
+ when Envelope::Move then :move
818
830
  else @manager.mode
819
831
  end
820
832
  end
@@ -11,12 +11,12 @@ module Farce
11
11
  # elements raise during insertion or lookup.
12
12
  class SortedSet < Set
13
13
  # Construct a set in ascending comparator order.
14
- # @overload initialize(enumerable = nil, normalize: nil, compare_by_identity: false, mode: :copy, **options)
14
+ # @overload initialize(enumerable = nil, normalize: nil, compare_by_identity: false, mode: :smart, **options)
15
15
  # @param enumerable [#each, nil] The initial elements, or nil for an empty set.
16
16
  # @param normalize [Symbol, Proc, Hash, Farce::Abstract::Map, nil] The element normalizer.
17
17
  # @param compare_by_identity [Boolean] Must be false. Membership uses <=>.
18
18
  # @param mode [Symbol] The default transfer mode. Only Farce::SortedSet accepts
19
- # this option, which defaults to :copy.
19
+ # this option, which defaults to :smart.
20
20
  # @param options [Hash] Additional options for the selected variant.
21
21
  # @option options [Symbol] scope (:ractor) The scope used by Farce::Local::SortedSet.
22
22
  # @yield [element] Optionally transform each initial element before normalization.
@@ -8,6 +8,37 @@ module Farce
8
8
  class TimerQueue < Queue
9
9
  include Internal::BlockingPriorityQueue
10
10
 
11
+ # A handle for canceling a scheduled value.
12
+ # Entries keep the stored value private, so canceling a moved value does not claim it.
13
+ # With local queues, cancellation uses the current scope.
14
+ #
15
+ # @example Cancel a delayed value
16
+ # queue = Farce::TimerQueue.new
17
+ # entry = queue.push(:work, delay: 60)
18
+ # entry.delete # => true
19
+ class Entry
20
+ # @return [Float] the scheduled monotonic clock time
21
+ attr_reader :clock
22
+
23
+ # @return [Farce::Abstract::TimerQueue] the queue that created this entry
24
+ attr_reader :queue
25
+
26
+ # @api private
27
+ def initialize(value, clock, queue)
28
+ @value = value
29
+ @clock = clock
30
+ @queue = queue
31
+ freeze
32
+ end
33
+
34
+ # Cancel the scheduled value by identity at its exact timestamp.
35
+ # If the same value was queued more than once at that timestamp, delete the oldest match.
36
+ # @return [Boolean] whether a value was deleted
37
+ # @raise [Farce::ClosedQueueError] when the queue is closed
38
+ def delete = queue.delete(@value, at: clock, compare_by_identity: true)
39
+ alias cancel delete
40
+ end
41
+
11
42
  # @param capacity [Integer, nil] the maximum number of values, or nil for an unbounded queue
12
43
  def initialize(capacity: nil, track_age: false)
13
44
  super
@@ -22,10 +53,11 @@ module Farce
22
53
  # With no scheduling option, the value is available immediately. Since `timeout:` controls the capacity wait,
23
54
  # use `delay:` or `wait:` to schedule a relative offset.
24
55
  # @raise [ThreadError] when the queue is at capacity and non_block is true
25
- # @return [Boolean] whether the value was added
56
+ # @return [Entry, false] the cancellation handle, or false if the capacity wait expires
26
57
  def push(value, non_block = false, timeout: nil, **time_options) # rubocop:disable Style/OptionalBooleanParameter
27
58
  at = Clock.parse(time_options)
28
- push_to_storage(at, non_block, value, timeout:)
59
+ entry = Entry.new(value, at, self)
60
+ push_to_storage(at, non_block, value, timeout:) && entry
29
61
  end
30
62
 
31
63
  # Remove the earliest value, waiting until its timestamp is reached.
@@ -50,10 +82,11 @@ module Farce
50
82
  # `at:`, `time:`, `timeout_at:`, `delay:`, `in:`, `offset:`, `timeout:`, `wait:`, or `clock:`.
51
83
  # With no scheduling option, the value is available immediately.
52
84
  # @yield called when the queue is at capacity
53
- # @return [Boolean, BasicObject] true, or the fallback result when full
85
+ # @return [Entry, BasicObject] the cancellation handle, or the fallback result when full
54
86
  def try_push(value, **time_options)
55
87
  at = Clock.parse(time_options)
56
- return true if internal_queue.push(at, value)
88
+ entry = Entry.new(value, at, self)
89
+ return entry if internal_queue.push(at, value)
57
90
  block_given? ? yield : false
58
91
  end
59
92
 
@@ -100,12 +133,18 @@ module Farce
100
133
  !UNDEFINED.equal?(wait_for_timestamp(timeout_at(timeout)))
101
134
  end
102
135
 
103
- # Delete the oldest matching value at the exact time.
104
- # @param value [BasicObject] the value to delete
105
- # @param at [Numeric, Time] the exact time to search
106
- # @param compare_by_identity [Boolean] compare values by identity instead of equality
107
- # @return [Boolean] whether a value was deleted
108
- def delete(value, at:, compare_by_identity: false)
136
+ # Cancel an entry, or delete the oldest matching value at the exact time.
137
+ # Pass `at:` to delete an Entry that was itself queued as a value.
138
+ # @param value [Entry, BasicObject] the cancellation handle or value to delete
139
+ # @param at [Numeric, Time] the exact time to search, required when deleting a value
140
+ # @param compare_by_identity [Boolean] compare values by identity instead of equality when `at:` is given
141
+ # @return [Boolean] whether a value was deleted, or false if the entry belongs to another queue
142
+ # @raise [ArgumentError] when deleting a value without `at:`
143
+ def delete(value, at: UNDEFINED, compare_by_identity: false)
144
+ if UNDEFINED.equal?(at)
145
+ raise ArgumentError, "at: is required when deleting a value" unless Entry === value
146
+ return value.queue.equal?(self) && value.delete
147
+ end
109
148
  delete_from_storage(Clock.at(at), value, compare_by_identity:)
110
149
  end
111
150