@trioforge/crucible 0.1.0 → 0.2.0
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.
- package/out/client/index.d.ts +7 -0
- package/out/client/init.luau +36 -1
- package/out/configs.d.ts +37 -0
- package/out/configs.luau +46 -0
- package/out/data.d.ts +224 -0
- package/out/data.luau +97 -0
- package/out/emit/configs.d.ts +4 -0
- package/out/emit/configs.luau +22 -0
- package/out/emit/data.d.ts +6 -0
- package/out/emit/data.luau +19 -0
- package/out/emit/index.d.ts +5 -1
- package/out/emit/init.luau +23 -7
- package/out/emit/network.d.ts +6 -0
- package/out/emit/network.luau +36 -0
- package/out/emit/replicated.d.ts +4 -0
- package/out/emit/replicated.luau +13 -0
- package/out/index.d.ts +8 -0
- package/out/init.luau +23 -0
- package/out/internal/binding.luau +5 -0
- package/out/internal/boot.luau +107 -8
- package/out/internal/configs/limits.d.ts +10 -0
- package/out/internal/configs/limits.luau +25 -0
- package/out/internal/configs/port.d.ts +29 -0
- package/out/internal/configs/port.luau +99 -0
- package/out/internal/configs/runtime.d.ts +21 -0
- package/out/internal/configs/runtime.luau +981 -0
- package/out/internal/data/admission.d.ts +1 -0
- package/out/internal/data/admission.luau +673 -0
- package/out/internal/data/declarations.d.ts +1 -0
- package/out/internal/data/declarations.luau +384 -0
- package/out/internal/data/envelope.d.ts +1 -0
- package/out/internal/data/envelope.luau +318 -0
- package/out/internal/data/handles.d.ts +1 -0
- package/out/internal/data/handles.luau +255 -0
- package/out/internal/data/inbox-transforms.d.ts +1 -0
- package/out/internal/data/inbox-transforms.luau +458 -0
- package/out/internal/data/inbox.d.ts +1 -0
- package/out/internal/data/inbox.luau +437 -0
- package/out/internal/data/lease.d.ts +1 -0
- package/out/internal/data/lease.luau +304 -0
- package/out/internal/data/limits.d.ts +1 -0
- package/out/internal/data/limits.luau +234 -0
- package/out/internal/data/messages.d.ts +1 -0
- package/out/internal/data/messages.luau +69 -0
- package/out/internal/data/operation-id.d.ts +1 -0
- package/out/internal/data/operation-id.luau +61 -0
- package/out/internal/data/paths.d.ts +2 -0
- package/out/internal/data/paths.luau +323 -0
- package/out/internal/data/port.d.ts +1 -0
- package/out/internal/data/port.luau +290 -0
- package/out/internal/data/profiles.d.ts +1 -0
- package/out/internal/data/profiles.luau +862 -0
- package/out/internal/data/receipts.d.ts +1 -0
- package/out/internal/data/receipts.luau +190 -0
- package/out/internal/data/record-bindings.d.ts +1 -0
- package/out/internal/data/record-bindings.luau +92 -0
- package/out/internal/data/record-declarations.d.ts +1 -0
- package/out/internal/data/record-declarations.luau +140 -0
- package/out/internal/data/records.d.ts +1 -0
- package/out/internal/data/records.luau +400 -0
- package/out/internal/data/runtime.d.ts +1 -0
- package/out/internal/data/runtime.luau +918 -0
- package/out/internal/data/scheduler.d.ts +1 -0
- package/out/internal/data/scheduler.luau +507 -0
- package/out/internal/data/session.d.ts +1 -0
- package/out/internal/data/session.luau +234 -0
- package/out/internal/data/shutdown.d.ts +1 -0
- package/out/internal/data/shutdown.luau +91 -0
- package/out/internal/data/waiters.d.ts +1 -0
- package/out/internal/data/waiters.luau +65 -0
- package/out/internal/lifecycle.luau +45 -0
- package/out/internal/network/catalog.d.ts +26 -0
- package/out/internal/network/catalog.luau +182 -0
- package/out/internal/network/claims.d.ts +1 -0
- package/out/internal/network/claims.luau +154 -0
- package/out/internal/network/client-session.d.ts +1 -0
- package/out/internal/network/client-session.luau +403 -0
- package/out/internal/network/codec.d.ts +63 -0
- package/out/internal/network/codec.luau +1183 -0
- package/out/internal/network/envelope.d.ts +1 -0
- package/out/internal/network/envelope.luau +247 -0
- package/out/internal/network/limits.d.ts +26 -0
- package/out/internal/network/limits.luau +55 -0
- package/out/internal/network/port.d.ts +1 -0
- package/out/internal/network/port.luau +19 -0
- package/out/internal/network/roblox-network-port.d.ts +1 -0
- package/out/internal/network/roblox-network-port.luau +105 -0
- package/out/internal/network/schema.d.ts +72 -0
- package/out/internal/network/schema.luau +386 -0
- package/out/internal/network/server-session.d.ts +1 -0
- package/out/internal/network/server-session.luau +393 -0
- package/out/internal/network/session.d.ts +1 -0
- package/out/internal/network/session.luau +266 -0
- package/out/internal/reactive/context.d.ts +1 -0
- package/out/internal/reactive/context.luau +149 -0
- package/out/internal/reactive/flush.d.ts +1 -0
- package/out/internal/reactive/flush.luau +355 -0
- package/out/internal/reactive/graph.d.ts +1 -0
- package/out/internal/reactive/graph.luau +626 -0
- package/out/internal/reactive/limits.d.ts +1 -0
- package/out/internal/reactive/limits.luau +54 -0
- package/out/internal/reactive/ownership.d.ts +1 -0
- package/out/internal/reactive/ownership.luau +626 -0
- package/out/internal/registry.luau +10 -1
- package/out/internal/sync/client-sync.d.ts +1 -0
- package/out/internal/sync/client-sync.luau +157 -0
- package/out/internal/sync/declarations.d.ts +1 -0
- package/out/internal/sync/declarations.luau +276 -0
- package/out/internal/sync/frame.d.ts +1 -0
- package/out/internal/sync/frame.luau +91 -0
- package/out/internal/sync/server-sync.d.ts +1 -0
- package/out/internal/sync/server-sync.luau +502 -0
- package/out/internal/sync/values.d.ts +1 -0
- package/out/internal/sync/values.luau +930 -0
- package/out/network.d.ts +66 -0
- package/out/network.luau +24 -0
- package/out/reactive.d.ts +76 -0
- package/out/reactive.luau +136 -0
- package/out/replicated.d.ts +38 -0
- package/out/replicated.luau +45 -0
- package/out/server/data.d.ts +54 -0
- package/out/server/data.luau +44 -0
- package/out/server/index.d.ts +16 -0
- package/out/server/init.luau +49 -3
- package/out/server/publish.d.ts +20 -0
- package/out/server/publish.luau +24 -0
- package/out/vide/index.d.ts +7 -0
- package/out/vide/init.luau +50 -0
- package/package.json +13 -2
- package/transformer/data.cjs +72 -0
- package/transformer/declarations.cjs +153 -0
- package/transformer/index.js +37 -11
- package/transformer/network.cjs +961 -0
- package/vide/package.json +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local bootClock = TS.import(script, script.Parent.Parent, "boot").bootClock
|
|
4
|
+
local _limits = TS.import(script, script.Parent, "limits")
|
|
5
|
+
local BUDGET_RECHECK_SECONDS = _limits.BUDGET_RECHECK_SECONDS
|
|
6
|
+
local BUDGET_RESERVE_FRACTION = _limits.BUDGET_RESERVE_FRACTION
|
|
7
|
+
local BUDGET_RESERVE_MIN = _limits.BUDGET_RESERVE_MIN
|
|
8
|
+
local KEY_READ_BYTES_PER_MINUTE = _limits.KEY_READ_BYTES_PER_MINUTE
|
|
9
|
+
local KEY_WRITE_BYTES_PER_MINUTE = _limits.KEY_WRITE_BYTES_PER_MINUTE
|
|
10
|
+
local LEASE_CRITICAL_SECONDS = _limits.LEASE_CRITICAL_SECONDS
|
|
11
|
+
local MAX_IN_FLIGHT = _limits.MAX_IN_FLIGHT
|
|
12
|
+
local MAX_PENDING_OPERATIONS = _limits.MAX_PENDING_OPERATIONS
|
|
13
|
+
local MAX_PENDING_PER_KEY = _limits.MAX_PENDING_PER_KEY
|
|
14
|
+
local ORDINARY_AGING_SECONDS = _limits.ORDINARY_AGING_SECONDS
|
|
15
|
+
local ORDINARY_MAX_IN_FLIGHT = _limits.ORDINARY_MAX_IN_FLIGHT
|
|
16
|
+
local RESERVED_SESSION_SLOTS = _limits.RESERVED_SESSION_SLOTS
|
|
17
|
+
local RETRY_BASE_SECONDS = _limits.RETRY_BASE_SECONDS
|
|
18
|
+
local RETRY_CAP_SECONDS = _limits.RETRY_CAP_SECONDS
|
|
19
|
+
local Waiters = TS.import(script, script.Parent, "waiters").Waiters
|
|
20
|
+
--* @internal Dispatch order, most urgent first (rule 34).
|
|
21
|
+
--* @internal
|
|
22
|
+
--* @internal
|
|
23
|
+
--* @internal
|
|
24
|
+
local Ticket
|
|
25
|
+
do
|
|
26
|
+
Ticket = setmetatable({}, {
|
|
27
|
+
__tostring = function()
|
|
28
|
+
return "Ticket"
|
|
29
|
+
end,
|
|
30
|
+
})
|
|
31
|
+
Ticket.__index = Ticket
|
|
32
|
+
function Ticket.new(...)
|
|
33
|
+
local self = setmetatable({}, Ticket)
|
|
34
|
+
return self:constructor(...) or self
|
|
35
|
+
end
|
|
36
|
+
function Ticket:constructor(port)
|
|
37
|
+
self.dispatched = false
|
|
38
|
+
self.inFlight = false
|
|
39
|
+
self.ambiguous = false
|
|
40
|
+
self.listeners = {}
|
|
41
|
+
self.waiters = Waiters.new(port)
|
|
42
|
+
end
|
|
43
|
+
function Ticket:onSettled(listener)
|
|
44
|
+
if self.settled ~= nil then
|
|
45
|
+
listener(self.settled)
|
|
46
|
+
else
|
|
47
|
+
local _listeners = self.listeners
|
|
48
|
+
local _listener = listener
|
|
49
|
+
table.insert(_listeners, _listener)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
function Ticket:wait(deadline)
|
|
53
|
+
local _condition = deadline
|
|
54
|
+
if _condition == nil then
|
|
55
|
+
_condition = math.huge
|
|
56
|
+
end
|
|
57
|
+
local limit = _condition
|
|
58
|
+
while self.settled == nil and bootClock() < limit do
|
|
59
|
+
self.waiters:park(deadline)
|
|
60
|
+
end
|
|
61
|
+
return self.settled
|
|
62
|
+
end
|
|
63
|
+
function Ticket:settle(settled)
|
|
64
|
+
if self.settled ~= nil then
|
|
65
|
+
return nil
|
|
66
|
+
end
|
|
67
|
+
self.settled = settled
|
|
68
|
+
for _, listener in self.listeners do
|
|
69
|
+
listener(settled)
|
|
70
|
+
end
|
|
71
|
+
table.clear(self.listeners)
|
|
72
|
+
self.waiters:wake()
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
local function slotOf(priority)
|
|
76
|
+
if priority == 4 then
|
|
77
|
+
return 1
|
|
78
|
+
end
|
|
79
|
+
if priority == 5 then
|
|
80
|
+
return 2
|
|
81
|
+
end
|
|
82
|
+
return 0
|
|
83
|
+
end
|
|
84
|
+
--* @internal The one keyed scheduler per server (rules 32 to 36). Every time is bootClock() (rule 25).
|
|
85
|
+
local KeyedScheduler
|
|
86
|
+
do
|
|
87
|
+
KeyedScheduler = setmetatable({}, {
|
|
88
|
+
__tostring = function()
|
|
89
|
+
return "KeyedScheduler"
|
|
90
|
+
end,
|
|
91
|
+
})
|
|
92
|
+
KeyedScheduler.__index = KeyedScheduler
|
|
93
|
+
function KeyedScheduler.new(...)
|
|
94
|
+
local self = setmetatable({}, KeyedScheduler)
|
|
95
|
+
return self:constructor(...) or self
|
|
96
|
+
end
|
|
97
|
+
function KeyedScheduler:constructor(port, diagnose)
|
|
98
|
+
self.port = port
|
|
99
|
+
self.diagnose = diagnose
|
|
100
|
+
self.queue = {}
|
|
101
|
+
self.lanes = {}
|
|
102
|
+
self.traffic = {}
|
|
103
|
+
self.pendingPerKey = {}
|
|
104
|
+
self.pending = 0
|
|
105
|
+
self.inFlight = 0
|
|
106
|
+
self.shared = 0
|
|
107
|
+
self.ordinary = 0
|
|
108
|
+
self.sequence = 0
|
|
109
|
+
self.pumping = false
|
|
110
|
+
self.again = false
|
|
111
|
+
self.timerAt = math.huge
|
|
112
|
+
end
|
|
113
|
+
function KeyedScheduler:reserve()
|
|
114
|
+
return math.max(BUDGET_RESERVE_MIN, math.floor(BUDGET_RESERVE_FRACTION * (60 + 40 * self.port.players.count())))
|
|
115
|
+
end
|
|
116
|
+
function KeyedScheduler:setDispatchCutoff(at)
|
|
117
|
+
self.cutoff = at
|
|
118
|
+
self:pump()
|
|
119
|
+
end
|
|
120
|
+
function KeyedScheduler:submit(request)
|
|
121
|
+
local ticket = Ticket.new(self.port)
|
|
122
|
+
local now = bootClock()
|
|
123
|
+
if self.cutoff ~= nil and now >= self.cutoff then
|
|
124
|
+
ticket:settle({
|
|
125
|
+
kind = "closing",
|
|
126
|
+
})
|
|
127
|
+
return ticket
|
|
128
|
+
end
|
|
129
|
+
local lane = `{request.store}\0{request.key}`
|
|
130
|
+
local counted = slotOf(request.priority) ~= 0
|
|
131
|
+
if counted then
|
|
132
|
+
local _condition = self.pendingPerKey[lane]
|
|
133
|
+
if _condition == nil then
|
|
134
|
+
_condition = 0
|
|
135
|
+
end
|
|
136
|
+
local perKey = _condition
|
|
137
|
+
if self.pending >= MAX_PENDING_OPERATIONS or perKey >= MAX_PENDING_PER_KEY then
|
|
138
|
+
ticket:settle({
|
|
139
|
+
kind = "overloaded",
|
|
140
|
+
})
|
|
141
|
+
return ticket
|
|
142
|
+
end
|
|
143
|
+
self.pending += 1
|
|
144
|
+
local _pendingPerKey = self.pendingPerKey
|
|
145
|
+
local _arg1 = perKey + 1
|
|
146
|
+
_pendingPerKey[lane] = _arg1
|
|
147
|
+
end
|
|
148
|
+
local _queue = self.queue
|
|
149
|
+
local _object = {
|
|
150
|
+
request = request,
|
|
151
|
+
ticket = ticket,
|
|
152
|
+
lane = lane,
|
|
153
|
+
}
|
|
154
|
+
local _left = "sequence"
|
|
155
|
+
self.sequence += 1
|
|
156
|
+
_object[_left] = self.sequence
|
|
157
|
+
_object.enqueuedAt = now
|
|
158
|
+
_object.counted = counted
|
|
159
|
+
_object.readyAt = now
|
|
160
|
+
_object.retries = 0
|
|
161
|
+
table.insert(_queue, _object)
|
|
162
|
+
self:pump()
|
|
163
|
+
return ticket
|
|
164
|
+
end
|
|
165
|
+
function KeyedScheduler:rank(entry, now)
|
|
166
|
+
local request = entry.request
|
|
167
|
+
local _condition = request.priority == 3 and request.renewal == true
|
|
168
|
+
if _condition then
|
|
169
|
+
local _condition_1 = request.safeUntil
|
|
170
|
+
if _condition_1 == nil then
|
|
171
|
+
_condition_1 = math.huge
|
|
172
|
+
end
|
|
173
|
+
_condition = _condition_1 - now < LEASE_CRITICAL_SECONDS
|
|
174
|
+
end
|
|
175
|
+
if _condition then
|
|
176
|
+
return 0
|
|
177
|
+
end
|
|
178
|
+
if request.priority == 5 and now - entry.enqueuedAt >= ORDINARY_AGING_SECONDS then
|
|
179
|
+
return 2 + 0.5
|
|
180
|
+
end
|
|
181
|
+
return request.priority
|
|
182
|
+
end
|
|
183
|
+
function KeyedScheduler:before(a, b, now)
|
|
184
|
+
local ra = self:rank(a, now)
|
|
185
|
+
local rb = self:rank(b, now)
|
|
186
|
+
if ra ~= rb then
|
|
187
|
+
return ra < rb
|
|
188
|
+
end
|
|
189
|
+
if ra == 0 or ra == 1 or ra == 3 then
|
|
190
|
+
local _condition = a.request.safeUntil
|
|
191
|
+
if _condition == nil then
|
|
192
|
+
_condition = math.huge
|
|
193
|
+
end
|
|
194
|
+
local sa = _condition
|
|
195
|
+
local _condition_1 = b.request.safeUntil
|
|
196
|
+
if _condition_1 == nil then
|
|
197
|
+
_condition_1 = math.huge
|
|
198
|
+
end
|
|
199
|
+
local sb = _condition_1
|
|
200
|
+
if sa ~= sb then
|
|
201
|
+
return sa < sb
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
return a.sequence < b.sequence
|
|
205
|
+
end
|
|
206
|
+
function KeyedScheduler:hasSlot(entry)
|
|
207
|
+
if self.inFlight >= MAX_IN_FLIGHT then
|
|
208
|
+
return false
|
|
209
|
+
end
|
|
210
|
+
local slot = slotOf(entry.request.priority)
|
|
211
|
+
if slot == 0 then
|
|
212
|
+
return true
|
|
213
|
+
end
|
|
214
|
+
if self.shared >= MAX_IN_FLIGHT - RESERVED_SESSION_SLOTS then
|
|
215
|
+
return false
|
|
216
|
+
end
|
|
217
|
+
return slot == 1 or self.ordinary < ORDINARY_MAX_IN_FLIGHT
|
|
218
|
+
end
|
|
219
|
+
function KeyedScheduler:hasBudget(entry)
|
|
220
|
+
local update = entry.request.kind == "update"
|
|
221
|
+
if entry.request.priority ~= 5 then
|
|
222
|
+
return self.port.budget(entry.request.kind) >= 1
|
|
223
|
+
end
|
|
224
|
+
local reserve = self:reserve()
|
|
225
|
+
if self.port.budget("read") <= reserve then
|
|
226
|
+
return false
|
|
227
|
+
end
|
|
228
|
+
return not update or self.port.budget("update") > reserve
|
|
229
|
+
end
|
|
230
|
+
function KeyedScheduler:recent(lane, now)
|
|
231
|
+
local _traffic = self.traffic
|
|
232
|
+
local _lane = lane
|
|
233
|
+
local _condition = _traffic[_lane]
|
|
234
|
+
if _condition == nil then
|
|
235
|
+
_condition = {}
|
|
236
|
+
end
|
|
237
|
+
-- ▼ ReadonlyArray.filter ▼
|
|
238
|
+
local _newValue = {}
|
|
239
|
+
local _callback = function(t)
|
|
240
|
+
return now - t.at < 60
|
|
241
|
+
end
|
|
242
|
+
local _length = 0
|
|
243
|
+
for _k, _v in _condition do
|
|
244
|
+
if _callback(_v, _k - 1, _condition) == true then
|
|
245
|
+
_length += 1
|
|
246
|
+
_newValue[_length] = _v
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
-- ▲ ReadonlyArray.filter ▲
|
|
250
|
+
local kept = _newValue
|
|
251
|
+
if #kept == 0 then
|
|
252
|
+
local _traffic_1 = self.traffic
|
|
253
|
+
local _lane_1 = lane
|
|
254
|
+
_traffic_1[_lane_1] = nil
|
|
255
|
+
else
|
|
256
|
+
local _traffic_1 = self.traffic
|
|
257
|
+
local _lane_1 = lane
|
|
258
|
+
_traffic_1[_lane_1] = kept
|
|
259
|
+
end
|
|
260
|
+
return kept
|
|
261
|
+
end
|
|
262
|
+
function KeyedScheduler:paced(entry, now)
|
|
263
|
+
local update = entry.request.kind == "update"
|
|
264
|
+
local bytes = entry.request.bytes
|
|
265
|
+
for _, t in self:recent(entry.lane, now) do
|
|
266
|
+
if t.update == update then
|
|
267
|
+
bytes += t.bytes
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
return bytes <= (if update then KEY_WRITE_BYTES_PER_MINUTE else KEY_READ_BYTES_PER_MINUTE)
|
|
271
|
+
end
|
|
272
|
+
function KeyedScheduler:settle(entry, settled)
|
|
273
|
+
local _queue = self.queue
|
|
274
|
+
local _entry = entry
|
|
275
|
+
local index = (table.find(_queue, _entry) or 0) - 1
|
|
276
|
+
if index ~= -1 then
|
|
277
|
+
table.remove(self.queue, index + 1)
|
|
278
|
+
end
|
|
279
|
+
local _lanes = self.lanes
|
|
280
|
+
local _lane = entry.lane
|
|
281
|
+
if _lanes[_lane] == entry then
|
|
282
|
+
local _lanes_1 = self.lanes
|
|
283
|
+
local _lane_1 = entry.lane
|
|
284
|
+
_lanes_1[_lane_1] = nil
|
|
285
|
+
end
|
|
286
|
+
if entry.counted then
|
|
287
|
+
self.pending -= 1
|
|
288
|
+
local _pendingPerKey = self.pendingPerKey
|
|
289
|
+
local _lane_1 = entry.lane
|
|
290
|
+
local _condition = _pendingPerKey[_lane_1]
|
|
291
|
+
if _condition == nil then
|
|
292
|
+
_condition = 1
|
|
293
|
+
end
|
|
294
|
+
local perKey = _condition - 1
|
|
295
|
+
if perKey <= 0 then
|
|
296
|
+
local _pendingPerKey_1 = self.pendingPerKey
|
|
297
|
+
local _lane_2 = entry.lane
|
|
298
|
+
_pendingPerKey_1[_lane_2] = nil
|
|
299
|
+
else
|
|
300
|
+
local _pendingPerKey_1 = self.pendingPerKey
|
|
301
|
+
local _lane_2 = entry.lane
|
|
302
|
+
_pendingPerKey_1[_lane_2] = perKey
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
entry.ticket:settle(settled)
|
|
306
|
+
end
|
|
307
|
+
function KeyedScheduler:givenUp(entry)
|
|
308
|
+
return if entry.ticket.ambiguous then {
|
|
309
|
+
kind = "uncertain",
|
|
310
|
+
} else {
|
|
311
|
+
kind = "timeout",
|
|
312
|
+
}
|
|
313
|
+
end
|
|
314
|
+
function KeyedScheduler:finish(entry, outcome)
|
|
315
|
+
local _result = entry.request.onResult
|
|
316
|
+
if _result ~= nil then
|
|
317
|
+
_result(outcome)
|
|
318
|
+
end
|
|
319
|
+
if outcome.kind == "ok" or not outcome.retryable then
|
|
320
|
+
if outcome.kind == "error" then
|
|
321
|
+
self.diagnose(`storage:{entry.request.store}:{outcome.code}`, `{entry.request.store} storage error {outcome.code} on key {entry.request.key}`)
|
|
322
|
+
end
|
|
323
|
+
self:settle(entry, {
|
|
324
|
+
kind = "done",
|
|
325
|
+
outcome = outcome,
|
|
326
|
+
})
|
|
327
|
+
return nil
|
|
328
|
+
end
|
|
329
|
+
if outcome.ambiguous then
|
|
330
|
+
entry.ticket.ambiguous = true
|
|
331
|
+
end
|
|
332
|
+
local now = bootClock()
|
|
333
|
+
local span = math.min(RETRY_CAP_SECONDS, RETRY_BASE_SECONDS * 2 ^ entry.retries)
|
|
334
|
+
entry.retries += 1
|
|
335
|
+
entry.readyAt = now + self.port.random() * span
|
|
336
|
+
local _exp = entry.request.dispatchDeadline
|
|
337
|
+
local _condition = self.cutoff
|
|
338
|
+
if _condition == nil then
|
|
339
|
+
_condition = math.huge
|
|
340
|
+
end
|
|
341
|
+
local limit = math.min(_exp, _condition)
|
|
342
|
+
if entry.readyAt >= limit then
|
|
343
|
+
self:settle(entry, self:givenUp(entry))
|
|
344
|
+
else
|
|
345
|
+
local _queue = self.queue
|
|
346
|
+
local _entry = entry
|
|
347
|
+
table.insert(_queue, _entry)
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
function KeyedScheduler:dispatch(entry, now)
|
|
351
|
+
local _queue = self.queue
|
|
352
|
+
local _queue_1 = self.queue
|
|
353
|
+
local _entry = entry
|
|
354
|
+
local _arg0 = (table.find(_queue_1, _entry) or 0) - 1
|
|
355
|
+
table.remove(_queue, _arg0 + 1)
|
|
356
|
+
local _lanes = self.lanes
|
|
357
|
+
local _lane = entry.lane
|
|
358
|
+
local _entry_1 = entry
|
|
359
|
+
_lanes[_lane] = _entry_1
|
|
360
|
+
local slot = slotOf(entry.request.priority)
|
|
361
|
+
self.inFlight += 1
|
|
362
|
+
if slot ~= 0 then
|
|
363
|
+
self.shared += 1
|
|
364
|
+
end
|
|
365
|
+
if slot == 2 then
|
|
366
|
+
self.ordinary += 1
|
|
367
|
+
end
|
|
368
|
+
entry.ticket.dispatched = true
|
|
369
|
+
entry.ticket.inFlight = true
|
|
370
|
+
local request = entry.request
|
|
371
|
+
local update = request.kind == "update"
|
|
372
|
+
local traffic = self:recent(entry.lane, now)
|
|
373
|
+
local _arg0_1 = {
|
|
374
|
+
at = now,
|
|
375
|
+
bytes = request.bytes,
|
|
376
|
+
update = update,
|
|
377
|
+
}
|
|
378
|
+
table.insert(traffic, _arg0_1)
|
|
379
|
+
local _traffic = self.traffic
|
|
380
|
+
local _lane_1 = entry.lane
|
|
381
|
+
_traffic[_lane_1] = traffic
|
|
382
|
+
local transform = if update then request.transform() else nil
|
|
383
|
+
local _result = request.onDispatch
|
|
384
|
+
if _result ~= nil then
|
|
385
|
+
_result(now)
|
|
386
|
+
end
|
|
387
|
+
self.port.spawn(function()
|
|
388
|
+
local ok, result = pcall(function()
|
|
389
|
+
return if update then self.port.update(request.store, request.key, transform) else self.port.read(request.store, request.key)
|
|
390
|
+
end)
|
|
391
|
+
self.inFlight -= 1
|
|
392
|
+
if slot ~= 0 then
|
|
393
|
+
self.shared -= 1
|
|
394
|
+
end
|
|
395
|
+
if slot == 2 then
|
|
396
|
+
self.ordinary -= 1
|
|
397
|
+
end
|
|
398
|
+
entry.ticket.inFlight = false
|
|
399
|
+
local outcome = if ok then result else {
|
|
400
|
+
kind = "error",
|
|
401
|
+
code = 0,
|
|
402
|
+
retryable = true,
|
|
403
|
+
ambiguous = true,
|
|
404
|
+
}
|
|
405
|
+
local handled, err = pcall(function()
|
|
406
|
+
return self:finish(entry, outcome)
|
|
407
|
+
end)
|
|
408
|
+
if not handled then
|
|
409
|
+
self:settle(entry, {
|
|
410
|
+
kind = "done",
|
|
411
|
+
outcome = {
|
|
412
|
+
kind = "error",
|
|
413
|
+
code = 0,
|
|
414
|
+
retryable = false,
|
|
415
|
+
ambiguous = true,
|
|
416
|
+
},
|
|
417
|
+
})
|
|
418
|
+
self.diagnose(`finish:{request.store}`, `{request.store} request handling failed: {err}`)
|
|
419
|
+
end
|
|
420
|
+
self:pump()
|
|
421
|
+
end)
|
|
422
|
+
end
|
|
423
|
+
function KeyedScheduler:pump()
|
|
424
|
+
if self.pumping then
|
|
425
|
+
self.again = true
|
|
426
|
+
return nil
|
|
427
|
+
end
|
|
428
|
+
self.pumping = true
|
|
429
|
+
repeat
|
|
430
|
+
do
|
|
431
|
+
self.again = false
|
|
432
|
+
self:step()
|
|
433
|
+
end
|
|
434
|
+
until not self.again
|
|
435
|
+
self.pumping = false
|
|
436
|
+
end
|
|
437
|
+
function KeyedScheduler:step()
|
|
438
|
+
local now = bootClock()
|
|
439
|
+
local wake = math.huge
|
|
440
|
+
local blocked = false
|
|
441
|
+
local _array = {}
|
|
442
|
+
local _length = #_array
|
|
443
|
+
local _array_1 = self.queue
|
|
444
|
+
table.move(_array_1, 1, #_array_1, _length + 1, _array)
|
|
445
|
+
for _, entry in _array do
|
|
446
|
+
local _exp = entry.request.dispatchDeadline
|
|
447
|
+
local _condition = self.cutoff
|
|
448
|
+
if _condition == nil then
|
|
449
|
+
_condition = math.huge
|
|
450
|
+
end
|
|
451
|
+
local limit = math.min(_exp, _condition)
|
|
452
|
+
if now >= limit then
|
|
453
|
+
self:settle(entry, self:givenUp(entry))
|
|
454
|
+
else
|
|
455
|
+
wake = math.min(wake, limit)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
while true do
|
|
459
|
+
local best
|
|
460
|
+
for _, entry in self.queue do
|
|
461
|
+
if entry.readyAt > now then
|
|
462
|
+
wake = math.min(wake, entry.readyAt)
|
|
463
|
+
continue
|
|
464
|
+
end
|
|
465
|
+
local _lanes = self.lanes
|
|
466
|
+
local _lane = entry.lane
|
|
467
|
+
local holder = _lanes[_lane]
|
|
468
|
+
if (holder ~= nil and holder ~= entry) or not self:hasSlot(entry) then
|
|
469
|
+
continue
|
|
470
|
+
end
|
|
471
|
+
if not self:hasBudget(entry) or not self:paced(entry, now) then
|
|
472
|
+
blocked = true
|
|
473
|
+
continue
|
|
474
|
+
end
|
|
475
|
+
if best == nil or self:before(entry, best, now) then
|
|
476
|
+
best = entry
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
if best == nil then
|
|
480
|
+
break
|
|
481
|
+
end
|
|
482
|
+
self:dispatch(best, now)
|
|
483
|
+
end
|
|
484
|
+
if blocked then
|
|
485
|
+
wake = math.min(wake, now + BUDGET_RECHECK_SECONDS)
|
|
486
|
+
end
|
|
487
|
+
self:arm(wake, now)
|
|
488
|
+
end
|
|
489
|
+
function KeyedScheduler:arm(at, now)
|
|
490
|
+
if at == math.huge or at >= self.timerAt then
|
|
491
|
+
return nil
|
|
492
|
+
end
|
|
493
|
+
if self.timer ~= nil then
|
|
494
|
+
self.port.cancel(self.timer)
|
|
495
|
+
end
|
|
496
|
+
self.timerAt = at
|
|
497
|
+
self.timer = self.port.delay(math.max(at - now, 0), function()
|
|
498
|
+
self.timer = nil
|
|
499
|
+
self.timerAt = math.huge
|
|
500
|
+
self:pump()
|
|
501
|
+
end)
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
return {
|
|
505
|
+
Ticket = Ticket,
|
|
506
|
+
KeyedScheduler = KeyedScheduler,
|
|
507
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|