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,44 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ module PortableTransaction
8
+ # Validate a size-only read without comparing values. Keep the index locked
9
+ # through publication so additions and removals wait. Cells created after
10
+ # preparation use temporary locks. A live absent cell remains reserved by
11
+ # its initializer and invalidates the attempt. Present or retired cells
12
+ # cannot change membership without the index lock.
13
+ class StrongMapSizeEntry < StrongMapEntry
14
+ def initialize(source, size)
15
+ super(source, nil, :strong_map, size)
16
+ end
17
+
18
+ def prepare
19
+ capture_cells
20
+ @cell_locks = {}.compare_by_identity
21
+ @cells.each { @cell_locks[it.instance_variable_get(:@mutex)] = true }
22
+ end
23
+
24
+ def valid?
25
+ return false if @index_lock.instance_variable_get(:@reserved)
26
+ current = @index.instance_variable_get(:@entries).compact
27
+ acquired = []
28
+ begin
29
+ current.each do |cell|
30
+ lock = cell.instance_variable_get(:@mutex)
31
+ next if @cell_locks.key?(lock)
32
+ return false unless lock.try_lock
33
+ acquired << lock
34
+ end
35
+ return false if current.any? { it.instance_variable_get(:@reserved) }
36
+ current.count { !it.instance_variable_get(:@retired) && it.instance_variable_get(:@present) } == @baseline
37
+ ensure
38
+ acquired.reverse_each(&:unlock)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ module PortableTransaction
8
+ # Keep the state object and lock stable for ordinary operations already
9
+ # waiting on them. Only replace storage under that existing lock.
10
+ class TreeEntry < Entry
11
+ def initialize(source, working, revision, lock, field) # rubocop:disable Lint/MissingSuper
12
+ @source = source
13
+ @working = working
14
+ @state = source.instance_variable_get(:@state)
15
+ @baseline = revision
16
+ @locks = [lock]
17
+ @field = field
18
+ @dirty = @applied = false
19
+ end
20
+
21
+ def prepare
22
+ state = @working.instance_variable_get(:@state)
23
+ @replacement = @field == :tree ? state.tree : state.entries
24
+ @next_version = @baseline + 1
25
+ end
26
+
27
+ def valid?
28
+ return false if @dirty && @source.frozen?
29
+ owner = if @field == :tree
30
+ @source.instance_variable_get(:@guard).instance_variable_get(:@owner)
31
+ else
32
+ @state.operation_owner
33
+ end
34
+ return false if owner || @state.revision != @baseline
35
+ @original = @field == :tree ? @state.tree : @state.entries
36
+ true
37
+ end
38
+
39
+ def apply
40
+ return unless @dirty
41
+ @applied = true
42
+ replace(@replacement, @next_version)
43
+ end
44
+
45
+ def restore
46
+ replace(@original, @baseline) if @applied
47
+ end
48
+
49
+ def notify = nil
50
+
51
+ private
52
+
53
+ def replace(storage, revision)
54
+ if @field == :tree
55
+ @state.tree = storage
56
+ else
57
+ @state.instance_variable_set(:@entries, storage)
58
+ end
59
+ @state.revision = revision
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ # Portable commits use existing mutexes. Validation compares original
8
+ # storage by identity without invoking user equality or hash callbacks.
9
+ module PortableTransaction
10
+ include Autoloads
11
+
12
+ def self.same?(left, right) = BasicObject.instance_method(:equal?).bind_call(left, right)
13
+
14
+ def self.snapshot(source, kind)
15
+ case kind
16
+ when :atom
17
+ value, version = source.instance_variable_get(:@mutex).synchronize do
18
+ [source.instance_variable_get(:@value), source.instance_variable_get(:@version)]
19
+ end
20
+ working = source.class.new(value, compare_by_identity: source.compare_by_identity?)
21
+ Entry.new(source, working, kind, version)
22
+ when :vector
23
+ values = source.snapshot
24
+ working = source.class.new(values, compare_by_identity: source.compare_by_identity?)
25
+ Entry.new(source, working, kind, values)
26
+ when :map, :strong_map
27
+ pairs = source.transaction_pairs
28
+ working = source.class.new(
29
+ compare_keys_by_identity: source.compare_keys_by_identity?,
30
+ compare_values_by_identity: source.compare_values_by_identity?,
31
+ )
32
+ pairs.each { |key, value| working[key] = value }
33
+ baseline = {}.compare_by_identity
34
+ pairs.each { |key, value| baseline[key] = value }
35
+ entry_class = kind == :strong_map ? StrongMapEntry : Entry
36
+ entry_class.new(source, working, kind, baseline)
37
+ end
38
+ end
39
+
40
+ def self.commit(entries, guards = [])
41
+ entries.each(&:prepare)
42
+ locks = entries.flat_map(&:locks).uniq.sort_by(&:object_id)
43
+ acquired = []
44
+ begin
45
+ locks.each do |lock|
46
+ return false unless lock.try_lock
47
+ acquired << lock
48
+ end
49
+ return false if guards.any?(&:value)
50
+ return false unless entries.all?(&:valid?)
51
+ begin
52
+ entries.each(&:apply)
53
+ unless !block_given? || yield
54
+ entries.reverse_each(&:restore)
55
+ return false
56
+ end
57
+ rescue Exception # rubocop:disable Lint/RescueException -- restore before propagating any interruption
58
+ entries.reverse_each(&:restore)
59
+ raise
60
+ end
61
+ true
62
+ ensure
63
+ acquired.reverse_each(&:unlock)
64
+ end
65
+ end
66
+
67
+ class Entry
68
+ attr_reader :working, :locks
69
+
70
+ def initialize(source, working, kind, baseline)
71
+ @source = source
72
+ @working = working
73
+ @kind = kind
74
+ @baseline = baseline
75
+ @dirty = false
76
+ @applied = false
77
+ @field = { atom: :@value, vector: :@values, map: :@map }.fetch(kind)
78
+ @locks = if kind == :map
79
+ %i[@reservation_mutex @state_mutex].map { source.instance_variable_get(it) }
80
+ else
81
+ [source.instance_variable_get(:@mutex)]
82
+ end
83
+ end
84
+
85
+ def write!
86
+ @dirty = true
87
+ end
88
+
89
+ def prepare
90
+ @replacement = @working.instance_variable_get(@field)
91
+ @next_version = @baseline + 1 if @kind == :atom
92
+ end
93
+
94
+ def valid?
95
+ frozen = @kind == :map ? @source.frozen? : @source.instance_variable_get(:@farce_frozen)
96
+ return false if @dirty && frozen
97
+ @original = @source.instance_variable_get(@field)
98
+ case @kind
99
+ when :atom
100
+ !@source.instance_variable_get(:@updating) &&
101
+ @source.instance_variable_get(:@version) == @baseline
102
+ when :vector
103
+ !@source.instance_variable_get(:@updating) && @original.size == @baseline.size &&
104
+ @baseline.each_index.all? { PortableTransaction.same?(@original[it], @baseline[it]) }
105
+ when :map
106
+ return false unless @source.transaction_idle?
107
+ pairs = @source.transaction_pairs
108
+ pairs.size == @baseline.size && pairs.all? do |key, value|
109
+ @baseline.key?(key) && PortableTransaction.same?(@baseline[key], value)
110
+ end
111
+ end
112
+ end
113
+
114
+ def apply
115
+ return unless @dirty
116
+ @applied = true
117
+ @source.instance_variable_set(@field, @replacement)
118
+ @source.instance_variable_set(:@version, @next_version) if @kind == :atom
119
+ end
120
+
121
+ # CRuby's Array iteration captures storage without its Ruby mutex.
122
+ # Hide provisional replacements from newly starting iterators.
123
+ def reserve
124
+ return unless @kind == :vector
125
+ @reserved = true
126
+ @source.instance_variable_set(:@updating, :transaction)
127
+ end
128
+
129
+ def unreserve
130
+ return unless @reserved
131
+ @source.instance_variable_set(:@updating, false)
132
+ @reserved = false
133
+ end
134
+
135
+ def restore
136
+ return unless @applied
137
+ @source.instance_variable_set(@field, @original)
138
+ @source.instance_variable_set(:@version, @baseline) if @kind == :atom
139
+ end
140
+
141
+ def notify
142
+ return unless @dirty
143
+ signal = @source.instance_variable_get(@kind == :map ? :@change_signal : :@signal)
144
+ if @kind == :atom
145
+ @locks.first.synchronize { signal.broadcast }
146
+ else
147
+ signal.broadcast
148
+ end
149
+ end
150
+ end
151
+
152
+ # Validate only cardinality while ordinary map mutations are excluded by
153
+ # the existing reservation and state locks. This entry never publishes data.
154
+ class MapSizeEntry < Entry
155
+ def initialize(source, size)
156
+ super(source, nil, :map, size)
157
+ end
158
+
159
+ def prepare = nil
160
+ def valid? = @source.transaction_idle? && @source.size == @baseline
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ # Close proxy channels when their owner exits, without retaining unused proxies.
8
+ module ProxyOwnerNotifications
9
+ def initialize
10
+ @alive = Flag.new(true)
11
+ @supervisors = Strict::Map.new(compare_by_identity: true)
12
+ end
13
+
14
+ def alive? = @alive.value
15
+
16
+ def register(supervisor)
17
+ @supervisors[supervisor] = true
18
+ supervisor.stop unless alive?
19
+ end
20
+
21
+ def unregister(supervisor) = @supervisors.delete(supervisor)
22
+
23
+ def stop
24
+ @alive.value = false
25
+ @supervisors.each_key(&:stop)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ # Keep reservation waits cancelable without shortening their overall deadline.
9
+ module ReservationWaiting
10
+ def self.wait(signal, generation, deadline)
11
+ while true
12
+ remaining = deadline - Clock.now if deadline
13
+ return false if remaining && !remaining.positive?
14
+
15
+ # LeaseWaiting supplies the full remaining timeout on default engines
16
+ # and short cancellation slices on JRuby. Reuse that existing hook
17
+ # without changing how other Signal users wait.
18
+ interval = LeaseWaiting.wait_interval(remaining)
19
+ return true if signal.wait(generation, timeout: interval) { false }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ # A shareable task and its transferred arguments.
8
+ class ScheduledTask
9
+ include Internal::Copyable
10
+ include Shareable::Immutable
11
+
12
+ MANAGER = ModeManager.new
13
+
14
+ def initialize(args, block, mode)
15
+ @block = Ractor.shareable_proc(&block)
16
+ @unwrap = false
17
+ @args = args.map! do |arg|
18
+ wrapped = MANAGER.wrap(arg, mode:)
19
+ @unwrap = true if MANAGER.managed_envelope?(wrapped)
20
+ wrapped
21
+ end.freeze
22
+ super()
23
+ end
24
+
25
+ def to_proc(completion = nil)
26
+ if completion
27
+ if @unwrap
28
+ lambda do
29
+ @block.call(*@args.map { |arg| MANAGER.unwrap(arg) })
30
+ ensure
31
+ completion.task_finished
32
+ end
33
+ else
34
+ lambda do
35
+ @block.call(*@args)
36
+ ensure
37
+ completion.task_finished
38
+ end
39
+ end
40
+ elsif @unwrap
41
+ -> { @block.call(*@args.map { |arg| MANAGER.unwrap(arg) }) }
42
+ else
43
+ -> { @block.call(*@args) }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+ require "fcntl"
3
+ require "socket"
4
+ require "io/nonblock"
5
+
6
+ module Farce
7
+ module Internal
8
+ # IO hooks and helpers shared by the scheduler implementations.
9
+ module SchedulerIO
10
+ def io_select(readers = nil, writers = nil, errors = nil, timeout = nil)
11
+ check_fiber
12
+ timeout = duration_value(timeout)
13
+ groups = [readers, writers, errors].map { |list| list.nil? ? [] : list.to_ary.dup }
14
+ ios = groups.map { |list| list.map(&:to_io) }
15
+ check_fiber # to_ary/to_io can run arbitrary Ruby
16
+
17
+ found = select_result(groups, ios, 0)
18
+ return checkpoint_result(found) if found || timeout&.zero?
19
+ token = arm_wait
20
+
21
+ register_select(token, groups, ios)
22
+ wait_with_timeout(token, timeout, nil)
23
+ ensure
24
+ retire_wait(token) if token
25
+ end
26
+
27
+ SINGLE_TRANSFER = defined?(IO::Buffer::VERSION) && IO::Buffer::VERSION >= 3
28
+ private_constant :SINGLE_TRANSFER
29
+
30
+ if SINGLE_TRANSFER
31
+ def io_pread(io, buffer, file_offset, offset, length)
32
+ positional_io(false, io, buffer, length, file_offset, offset, single_transfer: true)
33
+ end
34
+
35
+ def io_pwrite(io, buffer, file_offset, offset, length)
36
+ positional_io(true, io, buffer, length, file_offset, offset, single_transfer: true)
37
+ end
38
+ else
39
+ def io_pread(io, buffer, file_offset, minimum, offset = 0)
40
+ positional_io(false, io, buffer, minimum, file_offset, offset)
41
+ end
42
+
43
+ def io_pwrite(io, buffer, file_offset, minimum, offset = 0)
44
+ positional_io(true, io, buffer, minimum, file_offset, offset)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def owner_thread = Thread.current
51
+ def start_fiber(fiber) = fiber.resume
52
+ def policy_changed = nil
53
+ def dispatch_budget = 256
54
+ def finish_fiber = nil
55
+ def begin_close = nil
56
+ def begin_shutdown = nil
57
+
58
+ def select_snapshot(groups, timeout)
59
+ Fiber.blocking { IO.select(*groups, timeout) }
60
+ end
61
+
62
+ # Coercion belongs to admission. A mutable wrapper must not switch the IO
63
+ # being observed after its wait has been registered.
64
+ def select_result(groups, ios, timeout)
65
+ selected = select_snapshot(ios, timeout)
66
+ return unless selected
67
+ identities = selected.map do |list|
68
+ list.each_with_object({}.compare_by_identity) { |io, set| set[io] = true }
69
+ end
70
+ groups.each_with_index.map do |list, i|
71
+ list.each_with_index.filter_map { |object, j| object if identities[i].key?(ios[i][j]) }
72
+ end
73
+ end
74
+
75
+ def readiness(result)
76
+ return 0 unless result
77
+ (result[0].empty? ? 0 : IO::READABLE) |
78
+ (result[1].empty? ? 0 : IO::WRITABLE) |
79
+ (result[2].empty? ? 0 : IO::PRIORITY)
80
+ end
81
+
82
+ def transfer_arguments(io, buffer, minimum, offset, writing)
83
+ check_fiber
84
+ io = io.to_io
85
+ minimum, offset = Integer(minimum), Integer(offset)
86
+ check_fiber
87
+ io.fileno
88
+ raise ArgumentError, "minimum and offset exceed buffer size" if
89
+ minimum.negative? || offset.negative? || offset > buffer.size || minimum > buffer.size - offset
90
+ raise IO::Buffer::AccessError, "buffer is readonly" if !writing && buffer.readonly?
91
+ [io, minimum, offset]
92
+ end
93
+
94
+ def locked_buffer(buffer, &work)
95
+ !SINGLE_TRANSFER && buffer.locked? ? work.call : buffer.locked(&work)
96
+ end
97
+
98
+ def duplicate_io(io, writing)
99
+ # IO#dup flushes Ruby's buffers. During an io_write hook that would flush
100
+ # the same payload twice. Duplicate the descriptor below Ruby buffering.
101
+ Fiber.blocking do
102
+ copy = IO.for_fd(io.fcntl(Fcntl::F_DUPFD, 0), writing ? "w" : "r")
103
+ copy.close_on_exec = true
104
+ copy
105
+ end
106
+ end
107
+
108
+ def positional_io(writing, io, buffer, minimum, file_offset, offset, single_transfer: false)
109
+ io, minimum, offset = transfer_arguments(io, buffer, minimum, offset, writing)
110
+ file_offset = Integer(file_offset)
111
+ check_fiber
112
+ locked_buffer(buffer) do
113
+ copy = duplicate_io(io, writing)
114
+ capacity = single_transfer ? minimum : buffer.size - offset
115
+ minimum = capacity.zero? ? 0 : 1 if single_transfer
116
+ data = buffer.get_string(offset, capacity) if writing
117
+ value = background do
118
+ worker_transfer(copy, writing, data, capacity, minimum, file_offset)
119
+ end
120
+ if writing || value.is_a?(Integer)
121
+ value
122
+ else
123
+ buffer.set_string(value, offset)
124
+ value.bytesize
125
+ end
126
+ ensure
127
+ copy&.close
128
+ end
129
+ end
130
+
131
+ # File workers own copies. A cancelled caller waits for acknowledgement
132
+ # before its ensure closes the duplicated IO or releases any borrowed state.
133
+ def file_transfer(writing, io, buffer, minimum, offset, capacity = buffer.size - offset)
134
+ copy = duplicate_io(io, writing)
135
+ data = buffer.get_string(offset, capacity) if writing
136
+ value = background do
137
+ worker_transfer(copy, writing, data, capacity, minimum)
138
+ end
139
+ return value if writing || value.is_a?(Integer)
140
+ buffer.set_string(value, offset)
141
+ value.bytesize
142
+ ensure
143
+ copy&.close
144
+ end
145
+
146
+ def worker_transfer(io, writing, data, capacity, minimum, position = nil)
147
+ total = 0
148
+ output = +"".b
149
+ return writing ? 0 : output if capacity.zero?
150
+ loop do
151
+ remaining = capacity - total
152
+ if writing
153
+ chunk = data.byteslice(total, remaining)
154
+ amount = position ? io.pwrite(chunk, position + total) : io.syswrite(chunk)
155
+ else
156
+ chunk = position ? io.pread(remaining, position + total) : io.sysread(remaining)
157
+ output << chunk
158
+ amount = chunk.bytesize
159
+ end
160
+ total += amount
161
+ break if amount.zero? || total >= minimum
162
+ end
163
+ writing ? total : output
164
+ rescue EOFError
165
+ output
166
+ rescue SystemCallError => e
167
+ total.positive? ? (writing ? total : output) : -e.errno
168
+ end
169
+ end
170
+ end
171
+ end