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,38 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group WeakRef Integration
6
+ require "farce" unless defined?(Farce::Walker)
7
+ require "weakref" unless defined?(WeakRef)
8
+
9
+ module Farce
10
+ # Traverse the live referent. Collected references have no children.
11
+ Walker.define(::WeakRef) do |object, walker|
12
+ value = begin
13
+ object.__getobj__
14
+ rescue ::WeakRef::RefError
15
+ next object
16
+ end
17
+
18
+ walker.update(object, [value]) do |target, results|
19
+ # WeakRef has no setter, so replacement values need a new reference.
20
+ target.class.new(results.first)
21
+ end
22
+ end
23
+
24
+ Internal::Converter.define(::WeakRef, WeakRef) do
25
+ def convert!(ref)
26
+ @seen.fetch(ref) do
27
+ begin
28
+ value = ref.__getobj__
29
+ rescue ::WeakRef::RefError
30
+ next @seen[ref] = Farce::WeakRef::RECYCLED
31
+ end
32
+ converted = convert(value)
33
+ # Return new values directly so they have a strong owner.
34
+ @seen[ref] = converted.equal?(value) ? Farce::WeakRef.new(converted) : converted
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group Yajl Integration
6
+ # Yajl 1.4.3 cannot encode or parse inside non-main native Ractors.
7
+ require "farce"
8
+ require "yajl" unless defined?(Yajl::Encoder)
9
+ require "json" unless [].respond_to?(:to_json)
10
+ require_relative "shared/to_json"
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @api private
7
+ module Integrations
8
+ # Dependency entry points, ending with the feature that activates each integration.
9
+ INTEGRATIONS = {
10
+ active_support: %w[active_support active_support/core_ext].freeze,
11
+ bson: %w[bson].freeze,
12
+ cbor: %w[cbor].freeze,
13
+ dry_types: %w[dry/types].freeze,
14
+ concurrent: %w[concurrent/map concurrent/tvar concurrent].freeze,
15
+ json: %w[json].freeze,
16
+ msgpack: %w[msgpack].freeze,
17
+ psych: %w[psych].freeze,
18
+ oj: %w[oj].freeze,
19
+ sorted_set: %w[sorted_set].freeze,
20
+ weakref: %w[weakref].freeze,
21
+ yajl: %w[yajl].freeze,
22
+ ractor_tmvar: %w[ractor/tvar ractor/tmvar].freeze,
23
+ ractor_sharing: %w[
24
+ ractor/tvar
25
+ ractor/lockvar
26
+ ractor/lockhash
27
+ ractor/keylockhash
28
+ ractor/active_object
29
+ ractor/actor_hash
30
+ ractor/sharing
31
+ ].freeze,
32
+ }.freeze
33
+
34
+ PATHS = INTEGRATIONS.to_h { [_2.last, _1] }.merge(
35
+ "concurrent/tvar" => :concurrent,
36
+ "ractor/tvar" => :ractor_sharing,
37
+ "oj/json" => :oj,
38
+ "yajl/json_gem" => :yajl,
39
+ ).freeze
40
+
41
+ # Zeitwerk aliases Kernel#require. Prepending there can leave the aliased
42
+ # wrapper without a valid super target on TruffleRuby. Define the instance
43
+ # hook above Object so Kernel#require remains available for those aliases
44
+ # and Ruby's Ractor-aware Object#require stays in the lookup chain.
45
+ module RequireHook
46
+ private
47
+
48
+ # Load a feature and its integration while preserving require's result.
49
+ # @param path [String, #to_path] The feature to load.
50
+ # @return [Boolean] Whether the requested feature was newly loaded.
51
+ def require(path, ...)
52
+ path = File.path(path)
53
+ result = Integrations.loading(path) { super }
54
+ integration = PATHS[path.delete_suffix(".rb")]
55
+ if integration && !Integrations.loading?(integration) && Farce.config.autoload_integrations
56
+ integration_path = "farce/integrations/#{integration}"
57
+ Integrations.loading(integration_path) { super(integration_path) }
58
+ end
59
+ result
60
+ end
61
+ end
62
+ private_constant :RequireHook
63
+
64
+ # A prepended singleton hook can recurse when Zeitwerk aliases it. Preserve
65
+ # the original method explicitly instead of relying on super here.
66
+ class << Kernel
67
+ alias farce_original_require require
68
+ private :farce_original_require
69
+
70
+ # Load a feature and its integration through Kernel.require.
71
+ # @api private
72
+ # @param path [String, #to_path] The feature to load.
73
+ # @return [Boolean] Whether the requested feature was newly loaded.
74
+ def require(path, ...)
75
+ path = File.path(path)
76
+ result = Integrations.loading(path) { farce_original_require(path, ...) }
77
+ integration = PATHS[path.delete_suffix(".rb")]
78
+ if integration && !Integrations.loading?(integration) && Farce.config.autoload_integrations
79
+ integration_path = "farce/integrations/#{integration}"
80
+ Integrations.loading(integration_path) { farce_original_require(integration_path) }
81
+ end
82
+ result
83
+ end
84
+ end
85
+
86
+ private_constant :INTEGRATIONS, :PATHS
87
+
88
+ extend self
89
+
90
+ # Avoid requiring an integration again while it loads its own dependencies.
91
+ # @api private
92
+ def loading(path)
93
+ return yield unless path.start_with?("farce/integrations/")
94
+ previous = Thread.current[:farce_loading_integration]
95
+ Thread.current[:farce_loading_integration] = path.delete_prefix("farce/integrations/").delete_suffix(".rb").to_sym
96
+ begin
97
+ yield
98
+ ensure
99
+ Thread.current[:farce_loading_integration] = previous
100
+ end
101
+ end
102
+
103
+ # @api private
104
+ def loading?(integration) = Thread.current[:farce_loading_integration] == integration
105
+
106
+ # Activate integrations at startup when automatic loading is enabled.
107
+ # @api private
108
+ def setup
109
+ Object.prepend(RequireHook)
110
+ load_active if Farce.config.autoload_integrations
111
+ end
112
+
113
+ # Loads all integrations for gems that have already been loaded.
114
+ # @return [Array<Symbol>] the list of integrations that were loaded
115
+ # @!scope class
116
+ def load_active
117
+ result = []
118
+ INTEGRATIONS.each_key do |integration|
119
+ next unless loaded?("farce/integrations/#{integration}") ||
120
+ PATHS.any? { |path, target| target == integration && loaded?(path) }
121
+ require "farce/integrations/#{integration}"
122
+ result << integration
123
+ end
124
+ result
125
+ end
126
+
127
+ # Attempts to load all available integrations.
128
+ # If the integration could be loaded, it will be included in the result.
129
+ # @return [Array<Symbol>] the list of integrations that were loaded
130
+ # @!scope class
131
+ def load_available
132
+ result = []
133
+ INTEGRATIONS.each do |integration, require_paths|
134
+ next unless try_require("farce/integrations/#{integration}", *require_paths)
135
+ result << integration
136
+ end
137
+ result
138
+ end
139
+
140
+ private
141
+
142
+ def loaded?(path)
143
+ path = "#{path}.rb" unless path.end_with?(".rb")
144
+ paths = $LOAD_PATH.map { File.expand_path(path, it) }
145
+ paths.any? { $LOADED_FEATURES.include?(it) }
146
+ end
147
+
148
+ def try_require(path, *ignore)
149
+ require path
150
+ true
151
+ rescue LoadError => e
152
+ raise e unless e.path == path || ignore.include?(e.path)
153
+ false
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ # Autoload runs on the main Ractor, where CONFIG can still be accessed before
8
+ # freezing. Keep this lazy so requiring Farce leaves configuration mutable.
9
+ FROZEN_CONFIG = CONFIG.freeze
10
+ end
11
+ end
@@ -0,0 +1,47 @@
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
+ # @!visibility private
9
+ module Autoloads
10
+ def self.[](*, **)
11
+ Module.new do
12
+ define_singleton_method(:append_features) do |namespace|
13
+ Autoloads.define(namespace, *, **)
14
+ end
15
+ end
16
+ end
17
+
18
+ SEGMENTS = { "io" => "IO", "lru" => "LRU", "lfu" => "LFU" }.freeze
19
+ private_constant :SEGMENTS
20
+
21
+ def self.inflect(name, **inflections)
22
+ name.split(%r{::|/}).map do |part|
23
+ next if part.empty?
24
+ inflections.fetch(part.to_sym) { part.split("_").map { SEGMENTS.fetch(it, it.sub(/^./, &:upcase)) }.join }
25
+ end.compact.join("::")
26
+ end
27
+
28
+ def self.define(namespace, path = nil, skip: nil, **)
29
+ path ||= namespace.name.gsub(/([a-z])([A-Z])/, "\\1_\\2").gsub("::", "/").downcase
30
+ path = File.expand_path(path, "#{__dir__}/../..")
31
+ skip = ::Set[*skip]
32
+
33
+ skip.map!(&:to_s)
34
+
35
+ Dir.glob("#{path}/*.rb").each do |file|
36
+ base_name = File.basename(file, ".rb")
37
+ next if base_name.start_with?("_") || base_name.start_with?(".") || skip.include?(base_name)
38
+ const_name = inflect(base_name, **)
39
+ next if namespace.const_defined?(const_name, false) || $LOADED_FEATURES.include?(file)
40
+ namespace.autoload(const_name, file)
41
+ end
42
+ end
43
+
44
+ def self.append_features(namespace) = define(namespace)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,122 @@
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
+ # Shared blocking wrapper behavior for the public priority-based queues.
9
+ module BlockingPriorityQueue
10
+ # Remove all values and wake waiters.
11
+ def clear
12
+ internal_queue.clear
13
+ self
14
+ end
15
+
16
+ # Close the queue and wake waiters.
17
+ def close
18
+ internal_queue.close
19
+ self
20
+ end
21
+
22
+ # Stop new pushes and close after the final value is removed.
23
+ def seal
24
+ internal_queue.seal
25
+ self
26
+ end
27
+
28
+ # Wait until capacity is available without adding a value.
29
+ def wait_push(timeout: nil)
30
+ raise_unwritable if sealed?
31
+ return true unless capacity
32
+
33
+ wait(timeout) do
34
+ raise_unwritable if sealed?
35
+ size < capacity
36
+ end
37
+ end
38
+
39
+ # The approximate number of waiting execution contexts.
40
+ def num_waiting = internal_signal.num_waiting
41
+
42
+ Internal.delegate(
43
+ self, :internal_queue, :age_tracking?, :capacity, :closed?, :empty?, :generation,
44
+ :oldest_age, :oldest_enqueued_at, :sealed?, :size,
45
+ )
46
+
47
+ private
48
+
49
+ def initialize_copy(_other)
50
+ raise TypeError, "priority queues cannot be copied"
51
+ end
52
+
53
+ def initialize(capacity:, reverse_order: false, track_age: false)
54
+ @reverse_order = reverse_order
55
+ @signal = queue_signal
56
+ @queue = queue_storage_class.new(capacity:, signal: internal_signal, track_age:)
57
+ super()
58
+ end
59
+
60
+ def internal_signal = @signal
61
+
62
+ def queue_storage_class = Internal::PriorityQueue
63
+ def queue_signal = Signal.new
64
+
65
+ def delete_from_storage(priority, value, compare_by_identity:)
66
+ if compare_by_identity
67
+ internal_queue.delete_identity(priority, value)
68
+ else
69
+ internal_queue.delete(priority, value)
70
+ end
71
+ end
72
+
73
+ def push_to_storage(priority, non_block, value, timeout:)
74
+ deadline = timeout_at(timeout) unless timeout.nil?
75
+
76
+ while true
77
+ return true if internal_queue.push(priority, value)
78
+ raise ThreadError, "queue full" if non_block
79
+ return false unless wait_push(timeout: remaining_timeout(deadline))
80
+ end
81
+ end
82
+
83
+ def normalize_timeout(timeout)
84
+ return nil if timeout.nil?
85
+
86
+ timeout = Float(timeout)
87
+ raise ArgumentError, "timeout must be non-negative" if timeout.negative?
88
+ raise ArgumentError, "timeout must be finite" unless timeout.finite?
89
+ raise ArgumentError, "timeout must be a number" if timeout.nan?
90
+
91
+ timeout
92
+ end
93
+
94
+ def wait(timeout)
95
+ deadline = timeout_at(timeout)
96
+
97
+ while true
98
+ generation = internal_signal.generation
99
+ raise ::Farce::ClosedQueueError, "queue is closed" if closed?
100
+ return true if yield
101
+ return false unless internal_signal.wait(generation, timeout: remaining_timeout(deadline))
102
+ end
103
+ end
104
+
105
+ def raise_unwritable
106
+ closed = closed?
107
+ error = closed ? ::Farce::ClosedQueueError : ::Farce::SealedQueueError
108
+ raise error, closed ? "queue is closed" : "queue is sealed"
109
+ end
110
+
111
+ def timeout_at(timeout)
112
+ Clock.timeout(normalize_timeout(timeout)) unless timeout.nil?
113
+ end
114
+
115
+ def remaining_timeout(timeout_at)
116
+ return unless timeout_at
117
+ timeout = timeout_at - Clock.now
118
+ timeout.positive? ? timeout : 0
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,106 @@
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 Converter
9
+ class Factory
10
+ class << self
11
+ attr_writer :target_name
12
+ end
13
+
14
+ def self.target_name
15
+ return @target_name if defined?(@target_name) && @target_name
16
+ superclass.target_name if superclass.respond_to?(:target_name)
17
+ end
18
+
19
+ attr_reader :target_class, :namespace, :options, :converter
20
+
21
+ def initialize(converter)
22
+ @converter = converter
23
+ @namespace = converter.namespace
24
+ @options = converter.options
25
+ @seen = {}.compare_by_identity
26
+
27
+ case target_name = self.class.target_name
28
+ when Symbol, String then @target_class = @namespace.const_get(target_name)
29
+ when Class then @target_class = target_name
30
+ else raise TypeError, "Unsupported target name: #{target_name.inspect}"
31
+ end
32
+ end
33
+
34
+ def convert(value) = @converter.convert(value)
35
+
36
+ def convert!(value)
37
+ @seen.fetch(value) do
38
+ instance = @seen[value] = prepare(value)
39
+ apply(instance, value)
40
+ yield instance
41
+ instance
42
+ end
43
+ end
44
+
45
+ def prepare(_, **) = @target_class.new(**, **@options)
46
+ end
47
+
48
+ REGISTER = ClassMirror.new(Factory)
49
+ private_constant :REGISTER
50
+
51
+ def self.define(klass, target_name, &block)
52
+ if block && block.arity != 0
53
+ definition = Internal.prepare_method_definition(&block)
54
+ block = proc { define_method(:apply, &definition) }
55
+ end
56
+ factory_class = REGISTER.define(klass, &block)
57
+ factory_class.target_name = target_name
58
+ factory_class
59
+ end
60
+
61
+ define(Hash, :Map) do
62
+ def apply(instance, value) = value.each { instance[_1] = convert(_2) }
63
+
64
+ def prepare(value, **)
65
+ return super unless value.compare_by_identity?
66
+ super(value, compare_keys_by_identity: true, **)
67
+ end
68
+ end
69
+
70
+ define(Array, :Vector) { |instance, value| value.each { instance << convert(it) } }
71
+
72
+ define(::Set, :Set) do
73
+ def apply(instance, value) = value.each { instance << convert(it) }
74
+
75
+ def prepare(value, **)
76
+ return super unless value.compare_by_identity?
77
+ super(value, compare_by_identity: true, **)
78
+ end
79
+ end
80
+
81
+ define(ObjectSpace::WeakMap, :WeakMap) do
82
+ def apply(instance, value) = value.each { instance[_1] = convert(_2) }
83
+ def prepare(value, **) = super(value, compare_keys_by_identity: true, **)
84
+ end
85
+
86
+ attr_reader :options, :namespace
87
+
88
+ def initialize(namespace, freeze: nil, **options, &callback)
89
+ @namespace = namespace
90
+ @options = options
91
+ @freeze = freeze
92
+ @factories = {}
93
+ @callback = callback
94
+ end
95
+
96
+ def convert(value)
97
+ factory_class = REGISTER[value.class]
98
+ return @callback ? @callback.call(value) : value unless factory_class.target_name
99
+ factory = @factories[factory_class] ||= factory_class.new(self)
100
+ factory.convert!(value) do |result|
101
+ result.freeze if @freeze.nil? ? value.frozen? : @freeze
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ # Preserve the publication guarantees of public shareable wrappers.
8
+ module Copyable
9
+ private
10
+
11
+ def initialize_dup(other)
12
+ super
13
+ publish_copy(other, operation: :dup) if is_a?(Shareable)
14
+ end
15
+
16
+ def initialize_clone(other, freeze: nil)
17
+ super
18
+ publish_copy(other, operation: :clone, freeze:) if is_a?(Shareable)
19
+ end
20
+
21
+ def publish_copy(other, operation:, freeze: nil)
22
+ if respond_to?(:publish_shareable_copy, true)
23
+ publish_shareable_copy(other, operation:, freeze:)
24
+ elsif operation == :dup || freeze != false
25
+ Ractor.make_shareable(self) if Internal.native_ractors?
26
+ self.freeze
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ # Mixin to have some BasicObject methods still trigger method_missing
8
+ # Notable exceptions: #equal?, #__send__, #__id__
9
+ module Delegation
10
+ def ==(other) = method_missing(:==, other)
11
+ def ! = method_missing(:!)
12
+ def instance_eval(...) = method_missing(:instance_eval, ...)
13
+ def instance_exec(...) = method_missing(:instance_exec, ...)
14
+
15
+ def !=(other)
16
+ method_missing(:!=, other)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ # Own portable locks while native participants hold logical reservations.
8
+ # Portable replacements remain hidden until the foreign commit is resolved.
9
+ class ExternalTransaction
10
+ def self.commit(entries, external, guards, transaction)
11
+ groups = external.map(&:commit_group).uniq
12
+ raise TypeError, "only one external commit integration may participate" unless groups.size == 1
13
+
14
+ native, portable = entries.partition { NativeTransactionEntry === it }
15
+ context = new(portable, guards, groups.first.new(external), transaction)
16
+ flags = guards.map { it.respond_to?(:native_flag) ? it.native_flag : it }
17
+ Internal.reserve_transaction(native, flags, context)
18
+ end
19
+
20
+ def initialize(entries, guards, group, transaction)
21
+ @entries, @guards, @group, @transaction = entries, guards, group, transaction
22
+ @acquired = []
23
+ @attempted = nil
24
+ @entries.each(&:prepare)
25
+ @locks = (@entries.flat_map(&:locks) + @guards.filter_map { it.lock if it.respond_to?(:native_flag) })
26
+ .uniq.sort_by(&:object_id)
27
+ end
28
+
29
+ def acquire?
30
+ @locks.each do |lock|
31
+ return false if lock.owned?
32
+ @attempted = lock
33
+ return false unless lock.try_lock
34
+ @acquired << lock
35
+ @attempted = nil
36
+ end
37
+ @guards.none?(&:value) && @entries.all?(&:valid?)
38
+ end
39
+
40
+ def publish_external
41
+ @entries.each { it.reserve if it.respond_to?(:reserve) }
42
+ @entries.each(&:apply)
43
+ @group.commit
44
+ end
45
+
46
+ def committed? = @group.committed?
47
+ def restore = @entries.reverse_each(&:restore)
48
+
49
+ # Repeatable even if a return TracePoint interrupted a completed unlock.
50
+ def finish
51
+ @entries.each { it.unreserve if it.respond_to?(:unreserve) }
52
+ [*@acquired, @attempted].compact.uniq.reverse_each do |lock|
53
+ lock.unlock if lock.owned?
54
+ end
55
+ @entries.each(&:notify) if committed?
56
+ end
57
+ end
58
+ end
59
+ end