ratomic 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +7 -2
- data/ext/ratomic/src/lib.rs +14 -3
- data/ext/ratomic/src/mpmc_queue.rs +7 -7
- data/lib/ratomic/pool.rb +17 -1
- data/lib/ratomic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4ca3b68838c5f869284756b01f00e56960cbb5dff8e640efc03682d10d28a50
|
|
4
|
+
data.tar.gz: 959794b19074d1ecfba5bdb08223ba372a6443fbc96fe833d0ce324aa3c52d5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9697f964c65bdc3a951da84836ebadf947d370d74efd258015fb5401267acd6d78248de238f9da6db60edecccbe0a8bbd83a327e424d6fb6e74066ee60fe16de
|
|
7
|
+
data.tar.gz: 8bbbba4064050e577b23b48e8363653b5438ea157a68cffc607a53588e2785fdc9c2d5879d846593fa9f2757667df1df77784811c239b4f5b5d9cc684f00ae74
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.1] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
- Fix `Ratomic::Queue` slot indexing for non-power-of-two capacities.
|
|
6
|
+
- Fix `Ratomic::Map#fetch_and_modify` to propagate block exceptions instead of panicking.
|
|
7
|
+
|
|
3
8
|
## [0.2.0] - 2026-06-04
|
|
4
9
|
|
|
5
10
|
- Drop Ruby 3.x support and require Ruby 4.
|
data/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Ratomic
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/ratomic)
|
|
4
|
+
[](https://github.com/mperham/ratomic/actions)
|
|
5
|
+
[](https://codecov.io/gh/mperham/ratomic)
|
|
6
|
+
[](https://www.ruby-lang.org/en/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
|
|
3
10
|
Ratomic provides mutable data structures for use with Ruby's Ractors.
|
|
4
11
|
This allows Ruby code to scale beyond the infamous GVL.
|
|
5
12
|
|
|
@@ -31,8 +38,6 @@ Install the gem and add to the application's Gemfile by executing:
|
|
|
31
38
|
bundle add ratomic
|
|
32
39
|
```
|
|
33
40
|
|
|
34
|
-
TODO: We have not released a gem yet.
|
|
35
|
-
|
|
36
41
|
## Usage
|
|
37
42
|
|
|
38
43
|
Ratomic provides several useful Ractor-safe structures.
|
data/ext/ratomic/src/lib.rs
CHANGED
|
@@ -115,11 +115,22 @@ impl HashMap {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
let proc = ruby.block_proc()?;
|
|
118
|
+
let mut error = None;
|
|
118
119
|
rb_self.0.fetch_and_modify(value_to_raw(key), |value| {
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
match proc.call::<_, Value>((unsafe { value_from_raw(value) },)) {
|
|
121
|
+
Ok(result) => value_to_raw(result),
|
|
122
|
+
Err(err) => {
|
|
123
|
+
error = Some(err);
|
|
124
|
+
value
|
|
125
|
+
}
|
|
126
|
+
}
|
|
121
127
|
});
|
|
122
|
-
|
|
128
|
+
|
|
129
|
+
if let Some(err) = error {
|
|
130
|
+
Err(err)
|
|
131
|
+
} else {
|
|
132
|
+
Ok(())
|
|
133
|
+
}
|
|
123
134
|
}
|
|
124
135
|
}
|
|
125
136
|
|
|
@@ -15,7 +15,7 @@ unsafe impl Sync for QueueElement {}
|
|
|
15
15
|
|
|
16
16
|
pub struct MpmcQueue {
|
|
17
17
|
buffer: Vec<QueueElement>,
|
|
18
|
-
|
|
18
|
+
buffer_size: usize,
|
|
19
19
|
enqueue_pos: AtomicUsize,
|
|
20
20
|
dequeue_pos: AtomicUsize,
|
|
21
21
|
gc_guard: GcGuard,
|
|
@@ -25,7 +25,7 @@ pub struct MpmcQueue {
|
|
|
25
25
|
|
|
26
26
|
impl MpmcQueue {
|
|
27
27
|
pub fn new(buffer_size: usize, default: VALUE) -> Self {
|
|
28
|
-
let mut buffer = Vec::with_capacity(buffer_size
|
|
28
|
+
let mut buffer = Vec::with_capacity(buffer_size);
|
|
29
29
|
for i in 0..buffer_size {
|
|
30
30
|
buffer.push(QueueElement {
|
|
31
31
|
sequence: AtomicUsize::new(i),
|
|
@@ -42,7 +42,7 @@ impl MpmcQueue {
|
|
|
42
42
|
|
|
43
43
|
Self {
|
|
44
44
|
buffer,
|
|
45
|
-
|
|
45
|
+
buffer_size,
|
|
46
46
|
enqueue_pos: AtomicUsize::new(0),
|
|
47
47
|
dequeue_pos: AtomicUsize::new(0),
|
|
48
48
|
gc_guard,
|
|
@@ -55,7 +55,7 @@ impl MpmcQueue {
|
|
|
55
55
|
let mut cell;
|
|
56
56
|
let mut pos = self.enqueue_pos.load(Ordering::Relaxed);
|
|
57
57
|
loop {
|
|
58
|
-
cell = &self.buffer[pos
|
|
58
|
+
cell = &self.buffer[pos % self.buffer_size];
|
|
59
59
|
let seq = cell.sequence.load(Ordering::Acquire);
|
|
60
60
|
let diff = seq as isize - pos as isize;
|
|
61
61
|
if diff == 0 {
|
|
@@ -82,7 +82,7 @@ impl MpmcQueue {
|
|
|
82
82
|
let mut cell;
|
|
83
83
|
let mut pos = self.dequeue_pos.load(Ordering::Relaxed);
|
|
84
84
|
loop {
|
|
85
|
-
cell = &self.buffer[pos
|
|
85
|
+
cell = &self.buffer[pos % self.buffer_size];
|
|
86
86
|
let seq = cell.sequence.load(Ordering::Acquire);
|
|
87
87
|
let diff = seq as isize - (pos + 1) as isize;
|
|
88
88
|
if diff == 0 {
|
|
@@ -102,7 +102,7 @@ impl MpmcQueue {
|
|
|
102
102
|
|
|
103
103
|
let data = cell.data.get();
|
|
104
104
|
cell.sequence
|
|
105
|
-
.store(pos + self.
|
|
105
|
+
.store(pos + self.buffer_size, Ordering::Release);
|
|
106
106
|
self.write_sem.post();
|
|
107
107
|
|
|
108
108
|
#[cfg(feature = "simulation")]
|
|
@@ -131,7 +131,7 @@ impl MpmcQueue {
|
|
|
131
131
|
|
|
132
132
|
pub fn peek(&self) -> Option<VALUE> {
|
|
133
133
|
let pos = self.dequeue_pos.load(Ordering::Relaxed);
|
|
134
|
-
let cell = &self.buffer[pos
|
|
134
|
+
let cell = &self.buffer[pos % self.buffer_size];
|
|
135
135
|
let seq = cell.sequence.load(Ordering::Acquire);
|
|
136
136
|
let diff = seq as isize - (pos + 1) as isize;
|
|
137
137
|
if diff == 0 {
|
data/lib/ratomic/pool.rb
CHANGED
|
@@ -73,6 +73,20 @@ module Ratomic
|
|
|
73
73
|
nil
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# Stop the private coordinator Ractor.
|
|
77
|
+
#
|
|
78
|
+
# This is primarily useful for tests and short-lived scripts. A closed pool
|
|
79
|
+
# should not be used for further checkout/checkin operations.
|
|
80
|
+
#
|
|
81
|
+
# @return [nil]
|
|
82
|
+
def close
|
|
83
|
+
@control << [:shutdown]
|
|
84
|
+
@control.value
|
|
85
|
+
nil
|
|
86
|
+
rescue Ractor::ClosedError, Ractor::Error
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
|
|
76
90
|
# Checkout an object, yield it, then move it back to the pool.
|
|
77
91
|
#
|
|
78
92
|
# This is the preferred API because it guarantees checkin through an ensure
|
|
@@ -101,7 +115,7 @@ module Ratomic
|
|
|
101
115
|
|
|
102
116
|
loop do
|
|
103
117
|
command, *args = Ractor.receive
|
|
104
|
-
handle_command(command, args, available, waiting)
|
|
118
|
+
break if handle_command(command, args, available, waiting) == :shutdown
|
|
105
119
|
end
|
|
106
120
|
end
|
|
107
121
|
private_class_method :run_control_loop
|
|
@@ -114,6 +128,8 @@ module Ratomic
|
|
|
114
128
|
handle_checkin(args.fetch(0), available, waiting)
|
|
115
129
|
when :cancel
|
|
116
130
|
waiting.delete(args.fetch(0))
|
|
131
|
+
when :shutdown
|
|
132
|
+
:shutdown
|
|
117
133
|
end
|
|
118
134
|
end
|
|
119
135
|
private_class_method :handle_command
|
data/lib/ratomic/version.rb
CHANGED