itsi-scheduler 0.1.0 → 0.1.2

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +219 -23
  3. data/Rakefile +7 -1
  4. data/ext/itsi_error/Cargo.toml +2 -0
  5. data/ext/itsi_error/src/from.rs +70 -0
  6. data/ext/itsi_error/src/lib.rs +10 -37
  7. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  8. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  9. data/ext/itsi_rb_helpers/Cargo.toml +2 -0
  10. data/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  11. data/ext/itsi_rb_helpers/src/lib.rs +90 -10
  12. data/ext/itsi_scheduler/Cargo.toml +9 -1
  13. data/ext/itsi_scheduler/extconf.rb +1 -1
  14. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  15. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  16. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  17. data/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  18. data/ext/itsi_scheduler/src/lib.rs +31 -10
  19. data/ext/itsi_server/Cargo.toml +41 -0
  20. data/ext/itsi_server/extconf.rb +6 -0
  21. data/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  22. data/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  23. data/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  24. data/ext/itsi_server/src/lib.rs +103 -0
  25. data/ext/itsi_server/src/request/itsi_request.rs +277 -0
  26. data/ext/itsi_server/src/request/mod.rs +1 -0
  27. data/ext/itsi_server/src/response/itsi_response.rs +347 -0
  28. data/ext/itsi_server/src/response/mod.rs +1 -0
  29. data/ext/itsi_server/src/server/bind.rs +168 -0
  30. data/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  31. data/ext/itsi_server/src/server/io_stream.rs +104 -0
  32. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +13 -0
  33. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +5 -0
  34. data/ext/itsi_server/src/server/itsi_server.rs +230 -0
  35. data/ext/itsi_server/src/server/lifecycle_event.rs +8 -0
  36. data/ext/itsi_server/src/server/listener.rs +259 -0
  37. data/ext/itsi_server/src/server/mod.rs +11 -0
  38. data/ext/itsi_server/src/server/process_worker.rs +196 -0
  39. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +253 -0
  40. data/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  41. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +238 -0
  42. data/ext/itsi_server/src/server/signal.rs +57 -0
  43. data/ext/itsi_server/src/server/thread_worker.rs +368 -0
  44. data/ext/itsi_server/src/server/tls.rs +152 -0
  45. data/ext/itsi_tracing/Cargo.toml +4 -0
  46. data/ext/itsi_tracing/src/lib.rs +36 -6
  47. data/lib/itsi/scheduler/version.rb +1 -1
  48. data/lib/itsi/scheduler.rb +137 -1
  49. metadata +38 -4
@@ -6,6 +6,142 @@ require_relative "scheduler/itsi_scheduler"
6
6
  module Itsi
7
7
  class Scheduler
8
8
  class Error < StandardError; end
9
- # Your code goes here...
9
+
10
+ def self.resume_token
11
+ @resume_token ||= 0
12
+ @resume_token += 1
13
+ end
14
+
15
+ def initialize
16
+ @join_waiters = {}.compare_by_identity
17
+ @token_map = {}.compare_by_identity
18
+ @resume_tokens = {}.compare_by_identity
19
+ @unblocked = [[], []]
20
+ @unblock_idx = 0
21
+ @unblocked_mux = Mutex.new
22
+ @resume_fiber = method(:resume_fiber).to_proc
23
+ @resume_fiber_with_readiness = method(:resume_fiber_with_readiness).to_proc
24
+ @resume_blocked = method(:resume_blocked).to_proc
25
+ end
26
+
27
+ def block(_, timeout, fiber = Fiber.current, token = Scheduler.resume_token)
28
+ @join_waiters[fiber] = true
29
+
30
+ start_timer(timeout, token) if timeout
31
+ @resume_tokens[token] = fiber
32
+ @token_map[fiber] = token
33
+ Fiber.yield
34
+ ensure
35
+ @resume_tokens.delete(token)
36
+ @token_map.delete(fiber)
37
+ @join_waiters.delete(fiber)
38
+ end
39
+
40
+ # Register an IO waiter.
41
+ # This will get resumed by our scheduler inside the call to
42
+ # fetch_events.
43
+ def io_wait(io, events, duration)
44
+ fiber = Fiber.current
45
+ token = Scheduler.resume_token
46
+ readiness = register_io_wait(io.fileno, events, duration, token)
47
+ readiness || block(nil, duration, fiber, token)
48
+ end
49
+
50
+ def unblock(_blocker, fiber)
51
+ @unblocked_mux.synchronize do
52
+ @unblocked[@unblock_idx] << fiber
53
+ end
54
+ wake
55
+ end
56
+
57
+ def kernel_sleep(duration)
58
+ block nil, duration
59
+ end
60
+
61
+ def tick
62
+ events = fetch_due_events
63
+ timers = fetch_due_timers
64
+ unblocked = switch_unblock_batch
65
+ events&.each(&@resume_fiber_with_readiness)
66
+ unblocked.each(&@resume_blocked)
67
+ unblocked.clear
68
+ timers&.each(&@resume_fiber)
69
+ end
70
+
71
+ def resume_fiber(token)
72
+ if (fiber = @resume_tokens.delete(token))
73
+ fiber.resume
74
+ end
75
+ rescue StandardError => e
76
+ warn "Failed to resume fiber #{fiber}: #{e.message}"
77
+ end
78
+
79
+ def resume_fiber_with_readiness((token, readiness))
80
+ if (fiber = @resume_tokens.delete(token))
81
+ fiber.resume(readiness)
82
+ end
83
+ rescue StandardError => e
84
+ warn "Failed to resume fiber #{fiber}: #{e.message}"
85
+ end
86
+
87
+ def resume_blocked(fiber)
88
+ if (token = @token_map[fiber])
89
+ resume_fiber(token)
90
+ elsif fiber.alive?
91
+ fiber.resume
92
+ end
93
+ end
94
+
95
+ def switch_unblock_batch
96
+ @unblocked_mux.synchronize do
97
+ current = @unblocked[@unblock_idx]
98
+ @unblock_idx = (@unblock_idx + 1) % 2
99
+ current
100
+ end
101
+ end
102
+
103
+ # Yields upwards to the scheduler, with an intention to
104
+ # resume the fiber that yielded ASAP.
105
+ def yield
106
+ kernel_sleep(0) if work?
107
+ end
108
+
109
+ # Keep running until we've got no timers we're awaiting, no pending IO, no temporary yields,
110
+ # no pending unblocks.
111
+ def work?
112
+ !@unblocked[@unblock_idx].empty? || !@join_waiters.empty? || has_pending_io?
113
+ end
114
+
115
+ # Run until no more work needs doing.
116
+ def run
117
+ tick while work?
118
+ debug "Exit Scheduler"
119
+ end
120
+
121
+ # Hook invoked at the end of the thread.
122
+ # Will start our scheduler's Reactor.
123
+ def scheduler_close
124
+ run
125
+ ensure
126
+ @closed ||= true
127
+ freeze
128
+ end
129
+
130
+ # Need to defer to Process::Status rather than our extension
131
+ # as we don't have a means of creating our own Process::Status.
132
+ def process_wait(pid, flags)
133
+ Thread.new do
134
+ Process::Status.wait(pid, flags)
135
+ end.value
136
+ end
137
+
138
+ def closed?
139
+ @closed
140
+ end
141
+
142
+ # Spin up a new fiber and immediately resume it.
143
+ def fiber(&blk)
144
+ Fiber.new(blocking: false, &blk).tap(&:resume)
145
+ end
10
146
  end
11
147
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itsi-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-01 00:00:00.000000000 Z
10
+ date: 2025-03-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: libclang
@@ -56,13 +56,47 @@ files:
56
56
  - Rakefile
57
57
  - ext/itsi_error/Cargo.lock
58
58
  - ext/itsi_error/Cargo.toml
59
+ - ext/itsi_error/src/from.rs
59
60
  - ext/itsi_error/src/lib.rs
61
+ - ext/itsi_instrument_entry/Cargo.toml
62
+ - ext/itsi_instrument_entry/src/lib.rs
60
63
  - ext/itsi_rb_helpers/Cargo.lock
61
64
  - ext/itsi_rb_helpers/Cargo.toml
65
+ - ext/itsi_rb_helpers/src/heap_value.rs
62
66
  - ext/itsi_rb_helpers/src/lib.rs
63
67
  - ext/itsi_scheduler/Cargo.toml
64
68
  - ext/itsi_scheduler/extconf.rb
69
+ - ext/itsi_scheduler/src/itsi_scheduler.rs
70
+ - ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs
71
+ - ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs
72
+ - ext/itsi_scheduler/src/itsi_scheduler/timer.rs
65
73
  - ext/itsi_scheduler/src/lib.rs
74
+ - ext/itsi_server/Cargo.toml
75
+ - ext/itsi_server/extconf.rb
76
+ - ext/itsi_server/src/body_proxy/big_bytes.rs
77
+ - ext/itsi_server/src/body_proxy/itsi_body_proxy.rs
78
+ - ext/itsi_server/src/body_proxy/mod.rs
79
+ - ext/itsi_server/src/lib.rs
80
+ - ext/itsi_server/src/request/itsi_request.rs
81
+ - ext/itsi_server/src/request/mod.rs
82
+ - ext/itsi_server/src/response/itsi_response.rs
83
+ - ext/itsi_server/src/response/mod.rs
84
+ - ext/itsi_server/src/server/bind.rs
85
+ - ext/itsi_server/src/server/bind_protocol.rs
86
+ - ext/itsi_server/src/server/io_stream.rs
87
+ - ext/itsi_server/src/server/itsi_ca/itsi_ca.crt
88
+ - ext/itsi_server/src/server/itsi_ca/itsi_ca.key
89
+ - ext/itsi_server/src/server/itsi_server.rs
90
+ - ext/itsi_server/src/server/lifecycle_event.rs
91
+ - ext/itsi_server/src/server/listener.rs
92
+ - ext/itsi_server/src/server/mod.rs
93
+ - ext/itsi_server/src/server/process_worker.rs
94
+ - ext/itsi_server/src/server/serve_strategy/cluster_mode.rs
95
+ - ext/itsi_server/src/server/serve_strategy/mod.rs
96
+ - ext/itsi_server/src/server/serve_strategy/single_mode.rs
97
+ - ext/itsi_server/src/server/signal.rs
98
+ - ext/itsi_server/src/server/thread_worker.rs
99
+ - ext/itsi_server/src/server/tls.rs
66
100
  - ext/itsi_tracing/Cargo.lock
67
101
  - ext/itsi_tracing/Cargo.toml
68
102
  - ext/itsi_tracing/src/lib.rs
@@ -83,12 +117,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
117
  requirements:
84
118
  - - ">="
85
119
  - !ruby/object:Gem::Version
86
- version: 3.1.0
120
+ version: 3.0.0
87
121
  required_rubygems_version: !ruby/object:Gem::Requirement
88
122
  requirements:
89
123
  - - ">="
90
124
  - !ruby/object:Gem::Version
91
- version: 3.3.11
125
+ version: 3.1.11
92
126
  requirements: []
93
127
  rubygems_version: 3.6.2
94
128
  specification_version: 4