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.
Files changed (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. metadata +468 -0
@@ -0,0 +1,413 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/vault_weak_map"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class VaultWeakMapBase < Abstract::ConcurrentMap
11
+ OWNER = Atom.new
12
+ CLAIM_OWNERS = Object.new.freeze
13
+ TIMED_OUT = Object.new.freeze
14
+ private_constant :OWNER, :CLAIM_OWNERS, :TIMED_OUT
15
+
16
+ def initialize(
17
+ initial_mapping = nil,
18
+ compare_by_identity: false,
19
+ compare_keys_by_identity: compare_by_identity,
20
+ compare_values_by_identity: compare_by_identity
21
+ )
22
+ validate_boolean(compare_by_identity, "compare_by_identity")
23
+ validate_boolean(compare_keys_by_identity, "compare_keys_by_identity")
24
+ validate_boolean(compare_values_by_identity, "compare_values_by_identity")
25
+ raise TypeError, "initial mapping must be a Hash" unless initial_mapping.nil? || initial_mapping.is_a?(Hash)
26
+
27
+ super()
28
+
29
+ @compare_keys_by_identity = compare_keys_by_identity
30
+ @compare_values_by_identity = compare_values_by_identity
31
+ @token = Object.new.freeze
32
+ @vault = OWNER.store_if_absent { Vault.new }
33
+ @freeze_state = Flag.new(false)
34
+ request(:create, {
35
+ weak_keys: weak_keys?,
36
+ weak_values: weak_values?,
37
+ compare_keys_by_identity: compare_keys_by_identity?,
38
+ }.freeze)
39
+ initial_mapping&.each { self[it.first] = it.last }
40
+ Object.instance_method(:freeze).bind_call(self)
41
+ end
42
+
43
+ def freeze
44
+ @freeze_state.set
45
+ self
46
+ end
47
+
48
+ def frozen? = @freeze_state.value
49
+
50
+ def check_mutation = check_frozen!
51
+
52
+ def prepare_mutation_key(key)
53
+ check_frozen!
54
+ canonical_key(key)
55
+ end
56
+
57
+ def [](key) = read(key, nil)[1]
58
+
59
+ def []=(key, value)
60
+ store(key, value)
61
+ end
62
+
63
+ def fetch(*arguments)
64
+ unless arguments.length.between?(1, 2)
65
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
66
+ end
67
+
68
+ key, default = arguments
69
+ default_given = arguments.length == 2
70
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && default_given
71
+ present, value = read(key, nil)
72
+ return value if present
73
+ return yield(key) if block_given?
74
+ return default if default_given
75
+
76
+ raise KeyError.new("key not found: #{key.inspect}", receiver: self, key: key)
77
+ end
78
+
79
+ def get(key, timeout: nil, &fallback)
80
+ result = read(key, timeout_deadline(timeout))
81
+ result.equal?(TIMED_OUT) ? fallback&.call : result[1]
82
+ end
83
+
84
+ def store(key, value, timeout: nil, &fallback)
85
+ check_frozen!
86
+ key = canonical_key(key)
87
+ check_value(value, "value")
88
+ result = await_response(deadline: timeout_deadline(timeout)) { request(:store, key, value, false) }
89
+ result.equal?(TIMED_OUT) ? fallback&.call : value
90
+ end
91
+
92
+ def swap(key, replacement, timeout: nil, &fallback)
93
+ check_frozen!
94
+ key = canonical_key(key)
95
+ check_value(replacement, "value")
96
+ result = await_response(deadline: timeout_deadline(timeout)) { request(:store, key, replacement, true) }
97
+ result.equal?(TIMED_OUT) ? fallback&.call : result[1]
98
+ end
99
+
100
+ def store_if_absent(key, timeout: nil, &update)
101
+ raise LocalJumpError, "no block given" unless update
102
+
103
+ claimed_update(key, timeout_deadline(timeout), claim: :absent) { update.call }
104
+ end
105
+
106
+ def compare_and_set(key, expected, replacement, timeout: nil)
107
+ check_frozen!
108
+ check_value(expected, "value")
109
+ check_value(replacement, "value")
110
+ matched = false
111
+ claimed_update(key, timeout_deadline(timeout), claim: :present) do |current|
112
+ next TIMED_OUT unless values_equal?(current, expected)
113
+
114
+ check_frozen!
115
+ matched = true
116
+ replacement
117
+ end
118
+ matched
119
+ end
120
+
121
+ def update(key, timeout: nil, &update)
122
+ raise LocalJumpError, "no block given" unless update
123
+
124
+ claimed_update(key, timeout_deadline(timeout), claim: :always, &update)
125
+ end
126
+
127
+ def upsert(key, initial_value, timeout: nil, &update)
128
+ raise LocalJumpError, "no block given" unless update
129
+ check_value(initial_value, "value")
130
+
131
+ claimed_update(key, timeout_deadline(timeout), claim: :present, initial: initial_value, &update)
132
+ end
133
+
134
+ # Yield presence and value under the entry claim.
135
+ # MAP_KEEP and MAP_DELETE are control results. Other results replace the value.
136
+ # Return whether a change committed.
137
+ def modify(key)
138
+ raise LocalJumpError, "no block given" unless block_given?
139
+ check_frozen!
140
+ key = canonical_key(key)
141
+ ticket = Object.new.freeze
142
+ sent = finished = false
143
+ begin
144
+ response = await_response(deadline: nil) do
145
+ sent = true
146
+ request(:claim, key, ticket, true)
147
+ end
148
+ present, current, signal = response[1], response[2], response[3]
149
+ owners = claim_owners
150
+ owners[signal] = Fiber.current
151
+ value = yield(present, current)
152
+ check_frozen!
153
+ action = if MAP_KEEP.equal?(value)
154
+ :abort
155
+ elsif MAP_DELETE.equal?(value)
156
+ :delete
157
+ else
158
+ :store
159
+ end
160
+ check_value(value, "value") if action == :store
161
+ result = request(:finish, key, ticket, action, value)
162
+ finished = true
163
+ result.first != :stale && (action == :store || (action == :delete && present))
164
+ ensure
165
+ owners&.delete(signal)
166
+ request(:finish, key, ticket, :abort) if sent && !finished
167
+ end
168
+ end
169
+
170
+ def wait_until_changed(key, expected, timeout: nil, &fallback)
171
+ wait_for_value(key, expected, timeout_deadline(timeout), fallback, non_nil: false)
172
+ end
173
+
174
+ def wait_until_non_nil(key, timeout: nil, &fallback)
175
+ wait_for_value(key, nil, timeout_deadline(timeout), fallback, non_nil: true)
176
+ end
177
+
178
+ def key?(key) = read(key, nil).first
179
+ def compare_keys_by_identity? = @compare_keys_by_identity
180
+ def compare_values_by_identity? = @compare_values_by_identity
181
+ def shareable_keys? = true
182
+ def shareable_values? = true
183
+ def size = await_response(deadline: nil) { request(:size) }[1]
184
+ def keys = entries_snapshot.map(&:first)
185
+
186
+ def each(&block)
187
+ return enum_for(__callee__) { size } unless block
188
+ entries_snapshot.each { block.call(it) }
189
+ self
190
+ end
191
+ alias each_pair each
192
+
193
+ def each_live
194
+ return enum_for(__method__) { size } unless block_given?
195
+ token = request(:open_cursor)[1]
196
+ begin
197
+ while true
198
+ result = await_response(deadline: nil) { request(:next_live, token) }
199
+ break if result.first == :done
200
+ yield [result[1], result[2]]
201
+ end
202
+ ensure
203
+ request(:close_cursor, token)
204
+ end
205
+ self
206
+ end
207
+
208
+ def each_key(&block)
209
+ return enum_for(__callee__) { size } unless block
210
+ entries_snapshot.each { block.call(it.first) }
211
+ self
212
+ end
213
+
214
+ def each_value(&block)
215
+ return enum_for(__callee__) { size } unless block
216
+ entries_snapshot.each { block.call(it.last) }
217
+ self
218
+ end
219
+
220
+ def delete(key)
221
+ check_frozen!
222
+ key = canonical_key(key)
223
+ result = await_response(deadline: nil) { request(:delete, key) }
224
+ result.first == :ok ? result[1] : nil
225
+ end
226
+
227
+ def getkey(key)
228
+ key = canonical_key(key)
229
+ result = await_response(deadline: nil) { request(:getkey, key) }
230
+ result.first == :ok ? result[1] : nil
231
+ end
232
+
233
+ def clear
234
+ check_frozen!
235
+ request(:clear)
236
+ self
237
+ end
238
+
239
+ private
240
+
241
+ def check_frozen! = Internal::Freeze.check(self)
242
+
243
+ def request(action, *) = @vault.weak_map(@token, action, *)
244
+
245
+ def read(key, deadline)
246
+ key = canonical_key(key)
247
+ result = await_response(deadline:) { request(:read, key) }
248
+ return TIMED_OUT if result.equal?(TIMED_OUT)
249
+ return [false, nil] if result.first == :missing
250
+
251
+ [result[1], result[2]]
252
+ end
253
+
254
+ def claimed_update(key, deadline, claim:, initial: TIMED_OUT)
255
+ check_frozen!
256
+ key = canonical_key(key)
257
+ ticket = Object.new.freeze
258
+ sent = finished = false
259
+
260
+ begin
261
+ response = await_response(deadline:) do
262
+ sent = true
263
+ request(:claim, key, ticket, claim != :present || !initial.equal?(TIMED_OUT))
264
+ end
265
+ return if response.equal?(TIMED_OUT)
266
+ return false if response.first == :missing
267
+
268
+ present, current, signal = response[1], response[2], response[3]
269
+ if claim == :absent && present
270
+ request(:finish, key, ticket, :abort)
271
+ finished = true
272
+ return current
273
+ end
274
+
275
+ owners = claim_owners
276
+ owners[signal] = Fiber.current
277
+ replacement = present || initial.equal?(TIMED_OUT) ? yield(current) : initial
278
+ check_frozen!
279
+
280
+ if replacement.equal?(TIMED_OUT)
281
+ request(:finish, key, ticket, :abort)
282
+ finished = true
283
+ return false
284
+ end
285
+
286
+ check_value(replacement, "value")
287
+ result = request(:finish, key, ticket, :store, replacement)
288
+ finished = true
289
+ result.first == :stale ? nil : replacement
290
+ ensure
291
+ owners&.delete(signal)
292
+ request(:finish, key, ticket, :abort) if sent && !finished
293
+ end
294
+ end
295
+
296
+ def entries_snapshot
297
+ result = await_response(deadline: nil) { request(:snapshot) }
298
+ result[1]
299
+ end
300
+
301
+ def await_response(deadline:)
302
+ checked_after_timeout = false
303
+ loop do
304
+ response = yield
305
+ return response unless response.first == :busy
306
+
307
+ signal, generation = response[1], response[2]
308
+ reject_recursive_wait!(signal)
309
+ timeout = remaining_timeout(deadline)
310
+ if timeout&.zero?
311
+ return TIMED_OUT if checked_after_timeout
312
+ checked_after_timeout = true
313
+ next
314
+ end
315
+ changed = signal.wait_until_changed(generation, timeout:) { TIMED_OUT }
316
+ if changed.equal?(TIMED_OUT)
317
+ return TIMED_OUT if checked_after_timeout
318
+ checked_after_timeout = true
319
+ end
320
+ end
321
+ end
322
+
323
+ def wait_for_value(key, expected, deadline, fallback, non_nil:)
324
+ key = canonical_key(key)
325
+ check_value(expected, "value")
326
+ checked_after_timeout = false
327
+ loop do
328
+ response = await_response(deadline:) { request(:wait_read, key) }
329
+ return fallback&.call if response.equal?(TIMED_OUT)
330
+ # Keep the canonical stored key alive, even when the lookup used a
331
+ # different equal key. It arrives atomically with the entry's signal.
332
+ key = response[5] if response.first == :ok
333
+ present = response.first == :ok && response[1]
334
+ current = present ? response[2] : nil
335
+ return current if non_nil ? !current.nil? : !values_equal?(current, expected)
336
+
337
+ signal = response.first == :ok ? response[3] : response[1]
338
+ generation = response.first == :ok ? response[4] : response[2]
339
+ changed = signal.wait_until_changed(generation, timeout: remaining_timeout(deadline)) { TIMED_OUT }
340
+ if changed.equal?(TIMED_OUT)
341
+ return fallback&.call if checked_after_timeout
342
+ checked_after_timeout = true
343
+ end
344
+ end
345
+ end
346
+
347
+ def claim_owners
348
+ Storage.thread.store_if_absent(CLAIM_OWNERS) { {}.compare_by_identity }
349
+ end
350
+
351
+ def reject_recursive_wait!(signal)
352
+ owner = claim_owners[signal]
353
+ return unless owner
354
+ raise ThreadError, "deadlock; recursive weak-map access during an update" if owner.equal?(Fiber.current)
355
+ return if Fiber.respond_to?(:scheduler) && Fiber.scheduler
356
+
357
+ raise ThreadError, "deadlock; weak-map update is owned by another unscheduled fiber"
358
+ end
359
+
360
+ def values_equal?(left, right)
361
+ compare_values_by_identity? ? left.equal?(right) : left == right
362
+ end
363
+
364
+ def canonical_key(key)
365
+ key = String.instance_method(:-@).bind_call(key) if String === key && !key.frozen? && !compare_keys_by_identity?
366
+ check_value(key, "key")
367
+ end
368
+
369
+ def check_value(value, name)
370
+ return value if Ractor.shareable?(value)
371
+ raise Ractor::IsolationError, "#{name} must be Ractor-shareable"
372
+ end
373
+
374
+ def timeout_deadline(timeout)
375
+ return if timeout.nil?
376
+
377
+ timeout = Float(timeout)
378
+ unless timeout.finite? && !timeout.negative?
379
+ raise ArgumentError, "timeout must be a finite, non-negative number or nil"
380
+ end
381
+ Clock.now + timeout
382
+ end
383
+
384
+ def remaining_timeout(deadline)
385
+ return unless deadline
386
+
387
+ remaining = deadline - Clock.now
388
+ remaining.positive? ? remaining : 0
389
+ end
390
+
391
+ def validate_boolean(value, name)
392
+ return if value.equal?(true) || value.equal?(false)
393
+ raise ArgumentError, "#{name} must be true or false"
394
+ end
395
+ end
396
+ private_constant :VaultWeakMapBase
397
+
398
+ class WeakKeyMap < VaultWeakMapBase
399
+ def weak_keys? = true
400
+ def weak_values? = false
401
+ end
402
+
403
+ class WeakValueMap < VaultWeakMapBase
404
+ def weak_keys? = false
405
+ def weak_values? = true
406
+ end
407
+
408
+ class WeakMap < VaultWeakMapBase
409
+ def weak_keys? = true
410
+ def weak_values? = true
411
+ end
412
+ end
413
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # Load the scheduler dependency before native initialization.
6
+ # Late Resolv loading can crash RubyGems for some reason
7
+ require "resolv"
8
+ require "farce/strict"
9
+
10
+ module Farce
11
+ # @!visibility private
12
+ module Internal # :nodoc: all
13
+ # Compiled extensions and Ruby helpers share one directory for each CRuby ABI.
14
+ ENGINE_PATH = "farce/engine/ruby/#{RUBY_VERSION[/^\d+\.\d+/]}".freeze
15
+ private_constant :ENGINE_PATH
16
+
17
+ begin
18
+ require "#{ENGINE_PATH}/rebind"
19
+ require "#{ENGINE_PATH}/farce"
20
+ rescue LoadError => e
21
+ # simplecov:disable
22
+ warn <<~WARNING
23
+ Farce: Failed to load native extension for Ruby #{RUBY_VERSION}.
24
+ Please run `rake compile` to build the extension.
25
+ WARNING
26
+ raise e
27
+ # simplecov:enable
28
+ end
29
+
30
+ unless const_defined?(:NATIVE_WEAK_MAPS, false) && NATIVE_WEAK_MAPS
31
+ autoload :WeakMap, "farce/engine/ruby/shared/weak_map"
32
+ autoload :WeakKeyMap, "farce/engine/ruby/shared/weak_map"
33
+ autoload :WeakValueMap, "farce/engine/ruby/shared/weak_map"
34
+ end
35
+
36
+ StrictAtom = Atom
37
+ StrictLFUMap = ShareableLFUMap
38
+ StrictLRUMap = ShareableLRUMap
39
+ StrictTreeMap = ShareableTreeMap
40
+
41
+ autoload :ProxyOwner, "farce/engine/ruby/shared/proxy_owner"
42
+ autoload :ParallelScheduler, "farce/engine/ruby/shared/parallel_scheduler"
43
+ autoload :MainScheduler, "farce/engine/ruby/shared/main_scheduler"
44
+ autoload :Lease, "farce/engine/ruby/shared/lease"
45
+ autoload :LeasePool, "farce/engine/ruby/shared/lease_pool"
46
+ autoload :StrictMap, "farce/engine/ruby/shared/strict_map"
47
+ autoload :StrictWeakKeyMap, "farce/engine/ruby/shared/strict_map"
48
+ autoload :StrictWeakMap, "farce/engine/ruby/shared/strict_map"
49
+ autoload :StrictWeakValueMap, "farce/engine/ruby/shared/strict_map"
50
+ autoload :WeakAtom, "farce/engine/ruby/shared/weak_atom" unless const_defined?(:WeakAtom)
51
+ autoload :UnsharedWeakAtom, "farce/engine/shared/unshared_weak_atom" unless const_defined?(:UnsharedWeakAtom)
52
+ autoload :UnsharedAtom, "farce/engine/shared/unshared_atom"
53
+ autoload :UnsharedVector, "farce/engine/ruby/shared/unshared_vector"
54
+ autoload :UnsharedMap, "farce/engine/shared/unshared_weak_map"
55
+ autoload :UnsharedWeakMap, "farce/engine/shared/unshared_weak_map"
56
+ autoload :UnsharedWeakKeyMap, "farce/engine/shared/unshared_weak_map"
57
+ autoload :UnsharedWeakValueMap, "farce/engine/shared/unshared_weak_map"
58
+ autoload :FiberScheduler, "farce/engine/ruby/fiber_scheduler"
59
+
60
+ autoload :BasePort, "#{ENGINE_PATH}/port"
61
+ autoload :Port, "#{ENGINE_PATH}/port"
62
+ autoload :RactorMethods, "#{ENGINE_PATH}/ractor_methods"
63
+ autoload :Vault, "#{ENGINE_PATH}/vault"
64
+
65
+ def native_ractors? = true
66
+
67
+ class << self
68
+ alias commit_native_transaction commit_transaction
69
+ end
70
+
71
+ def self.commit_transaction(entries, guards = [], transaction = nil)
72
+ external, entries = entries.partition { it.respond_to?(:commit_group) }
73
+ return ExternalTransaction.commit(entries, external, guards, transaction) unless external.empty?
74
+ guards = guards.map { it.respond_to?(:native_flag) ? it.native_flag : it }
75
+ native, portable = entries.partition { NativeTransactionEntry === it }
76
+ return commit_native_transaction(native, guards) if portable.empty?
77
+ PortableTransaction.commit(portable, guards) { commit_native_transaction(native, guards) }
78
+ end
79
+
80
+ def self.notify_transaction(entries)
81
+ entries.each { it.notify unless NativeTransactionEntry === it }
82
+ end
83
+
84
+ def prepare_method_definition(&) = Ractor.shareable_proc(&)
85
+
86
+ if ::Ractor.const_defined?(:Port, false)
87
+ def native_ports? = true
88
+ else
89
+ def native_ports? = false
90
+ end
91
+
92
+ # Native waits opt in through the scheduler's ractor_selector method.
93
+ # Blocking fibers use Ruby directly, including the helper's result retrieval.
94
+ # Version-specific hooks retain native timeout support and method visibility.
95
+ patch = lambda do |namespace, *methods, signature: "...", schedule: "self, ...", before: nil|
96
+ methods.each do |method|
97
+ visibility = namespace.private_method_defined?(method) ? "private" : "public"
98
+ namespace.class_eval <<~RUBY, __FILE__, __LINE__ + 1
99
+ alias #{method}! #{method}
100
+ private :#{method}!
101
+
102
+ def #{method}(#{signature})
103
+ #{before}
104
+ scheduler = Fiber.scheduler unless Fiber.blocking?
105
+ selector = scheduler.ractor_selector if scheduler.respond_to?(:ractor_selector)
106
+ return #{method}!(#{signature}) unless selector
107
+ selector.ractor_#{method}(#{schedule})
108
+ end
109
+ #{visibility} :#{method}
110
+ RUBY
111
+ end
112
+ end
113
+
114
+ require "#{ENGINE_PATH}/ractor_selector"
115
+ RactorSelector.install_hooks(patch)
116
+ ::Ractor.singleton_class.alias_method :recv, :receive
117
+ ::Ractor.alias_method :recv, :receive
118
+
119
+ if defined?(Darwin.main_qos_class) && defined?(Darwin.get_qos_class)
120
+ def prepare_thread
121
+ main_qos_class = Darwin.main_qos_class
122
+ qos_class, priority = Darwin.get_qos_class
123
+ Darwin.set_qos_class(main_qos_class, priority) if main_qos_class > qos_class
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ require "farce/engine/ruby/key_lock_map"
130
+ require "farce/engine/shared/trie_builder"
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ class Atom < UnsharedAtom
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,130 @@
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
+ class Exchanger
9
+ include Freeze::Unfreezable
10
+
11
+ TIMED_OUT = Object.new.freeze
12
+ WAITING = Object.new.freeze
13
+ Waiter = Struct.new(:condition, :matched, :offered, :reader, :received, :scheduler, :writer)
14
+ private_constant :TIMED_OUT, :WAITING, :Waiter
15
+
16
+ def initialize
17
+ @mutex = Mutex.new
18
+ @waiting = [nil]
19
+ Freeze.publish(self)
20
+ end
21
+
22
+ def exchange(offered, timeout: nil, &fallback)
23
+ deadline = timeout_deadline(timeout)
24
+ waiter = build_waiter(offered)
25
+
26
+ partner = @mutex.synchronize do
27
+ if partner = @waiting.first
28
+ @waiting[0] = nil
29
+ partner.received = offered
30
+ partner.matched = true
31
+ notify(partner)
32
+ partner
33
+ elsif deadline && deadline <= Clock.now
34
+ TIMED_OUT
35
+ else
36
+ @waiting[0] = waiter
37
+ nil
38
+ end
39
+ end
40
+
41
+ return partner.offered if partner && !TIMED_OUT.equal?(partner)
42
+ return timed_out(fallback) if TIMED_OUT.equal?(partner)
43
+
44
+ result = waiter.scheduler ? wait_with_scheduler(waiter, deadline) : wait_with_condition(waiter, deadline)
45
+ TIMED_OUT.equal?(result) ? timed_out(fallback) : result
46
+ ensure
47
+ remove(waiter) if waiter
48
+ waiter&.reader&.close
49
+ waiter&.writer&.close
50
+ end
51
+
52
+ private
53
+
54
+ def build_waiter(offered)
55
+ scheduler = Fiber.current_scheduler if Fiber.respond_to?(:current_scheduler)
56
+ # JRuby may run a later scheduled fiber on a backing thread where this is nil.
57
+ scheduler ||= Fiber.scheduler if Fiber.respond_to?(:scheduler) && !Fiber.current.blocking?
58
+ reader, writer = IO.pipe if scheduler
59
+ Waiter.new(
60
+ condition: ConditionVariable.new,
61
+ matched: false,
62
+ offered: offered,
63
+ reader: reader,
64
+ scheduler: scheduler,
65
+ writer: writer,
66
+ )
67
+ end
68
+
69
+ def notify(waiter)
70
+ if waiter.scheduler
71
+ waiter.writer.write_nonblock(".", exception: false)
72
+ else
73
+ waiter.condition.broadcast
74
+ end
75
+ end
76
+
77
+ def wait_with_condition(waiter, deadline)
78
+ @mutex.synchronize do
79
+ until waiter.matched
80
+ remaining = deadline - Clock.now if deadline
81
+ return cancel(waiter) if remaining && !remaining.positive?
82
+ waiter.condition.wait(@mutex, remaining)
83
+ end
84
+ waiter.received
85
+ end
86
+ end
87
+
88
+ def wait_with_scheduler(waiter, deadline)
89
+ loop do
90
+ state, result = @mutex.synchronize do
91
+ if waiter.matched
92
+ [nil, waiter.received]
93
+ else
94
+ remaining = deadline - Clock.now if deadline
95
+ remaining && !remaining.positive? ? [nil, cancel(waiter)] : [WAITING, remaining]
96
+ end
97
+ end
98
+ return result unless WAITING.equal?(state)
99
+
100
+ waiter.scheduler.io_wait(waiter.reader, IO::READABLE, result)
101
+ end
102
+ end
103
+
104
+ def cancel(waiter)
105
+ remove(waiter)
106
+ waiter.matched ? waiter.received : TIMED_OUT
107
+ end
108
+
109
+ def remove(waiter)
110
+ @mutex.owned? ? remove_locked(waiter) : @mutex.synchronize { remove_locked(waiter) }
111
+ end
112
+
113
+ def remove_locked(waiter)
114
+ @waiting[0] = nil if @waiting.first.equal?(waiter)
115
+ end
116
+
117
+ def timeout_deadline(timeout)
118
+ return unless timeout
119
+
120
+ timeout = Float(timeout)
121
+ if !timeout.finite? || timeout.negative?
122
+ raise ArgumentError, "timeout must be a finite, non-negative number or nil"
123
+ end
124
+ Clock.now + timeout
125
+ end
126
+
127
+ def timed_out(fallback) = fallback&.call
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,22 @@
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
+ class IdentityKey
9
+ BASIC_OBJECT_EQUAL_METHOD = BasicObject.instance_method(:equal?)
10
+ BASIC_OBJECT_ID_METHOD = BasicObject.instance_method(:__id__)
11
+ private_constant :BASIC_OBJECT_EQUAL_METHOD, :BASIC_OBJECT_ID_METHOD
12
+
13
+ attr_reader :value
14
+
15
+ def initialize(value) = @value = value
16
+ def hash = BASIC_OBJECT_ID_METHOD.bind_call(value)
17
+ def eql?(other) = other.is_a?(IdentityKey) && BASIC_OBJECT_EQUAL_METHOD.bind_call(value, other.value)
18
+
19
+ alias == eql?
20
+ end
21
+ end
22
+ end