|
1 | 1 | import { Counter, ValueType, metrics } from "@opentelemetry/api"; |
| 2 | +import { PeerState } from "./PeerState.js"; |
2 | 3 | import { CO_VALUE_PRIORITY, type CoValuePriority } from "./priority.js"; |
3 | 4 | import type { SyncMessage } from "./sync.js"; |
4 | 5 |
|
@@ -65,6 +66,10 @@ export class LinkedList<T> { |
65 | 66 | this.meter?.pull(); |
66 | 67 | return value; |
67 | 68 | } |
| 69 | + |
| 70 | + isEmpty() { |
| 71 | + return this.head === undefined; |
| 72 | + } |
68 | 73 | } |
69 | 74 |
|
70 | 75 | class QueueMeter { |
@@ -152,3 +157,79 @@ export class PriorityBasedMessageQueue { |
152 | 157 | return this.queues[priority]?.shift(); |
153 | 158 | } |
154 | 159 | } |
| 160 | + |
| 161 | +export class IncomingMessagesQueue { |
| 162 | + private queues: [LinkedList<SyncMessage>, PeerState][]; |
| 163 | + private peerToQueue: WeakMap<PeerState, LinkedList<SyncMessage>>; |
| 164 | + currentQueue = 0; |
| 165 | + |
| 166 | + constructor() { |
| 167 | + this.queues = []; |
| 168 | + this.peerToQueue = new WeakMap(); |
| 169 | + } |
| 170 | + |
| 171 | + public push(msg: SyncMessage, peer: PeerState) { |
| 172 | + const queue = this.peerToQueue.get(peer); |
| 173 | + |
| 174 | + if (!queue) { |
| 175 | + const newQueue = new LinkedList<SyncMessage>(); |
| 176 | + this.peerToQueue.set(peer, newQueue); |
| 177 | + this.queues.push([newQueue, peer]); |
| 178 | + newQueue.push(msg); |
| 179 | + } else { |
| 180 | + queue.push(msg); |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + public pull() { |
| 185 | + const entry = this.queues[this.currentQueue]; |
| 186 | + |
| 187 | + if (!entry) { |
| 188 | + return undefined; |
| 189 | + } |
| 190 | + |
| 191 | + const [queue, peer] = entry; |
| 192 | + const msg = queue.shift(); |
| 193 | + |
| 194 | + if (queue.isEmpty()) { |
| 195 | + this.queues.splice(this.currentQueue, 1); |
| 196 | + this.peerToQueue.delete(peer); |
| 197 | + } else { |
| 198 | + this.currentQueue++; |
| 199 | + } |
| 200 | + |
| 201 | + if (this.currentQueue >= this.queues.length) { |
| 202 | + this.currentQueue = 0; |
| 203 | + } |
| 204 | + |
| 205 | + if (msg) { |
| 206 | + return { msg, peer }; |
| 207 | + } |
| 208 | + |
| 209 | + return undefined; |
| 210 | + } |
| 211 | + |
| 212 | + processing = false; |
| 213 | + |
| 214 | + processQueue( |
| 215 | + callback: (msg: SyncMessage, peer: PeerState, stop: () => void) => void, |
| 216 | + ) { |
| 217 | + this.processing = true; |
| 218 | + |
| 219 | + let entry: { msg: SyncMessage; peer: PeerState } | undefined; |
| 220 | + |
| 221 | + while ((entry = this.pull())) { |
| 222 | + const { msg, peer } = entry; |
| 223 | + |
| 224 | + callback(msg, peer, () => { |
| 225 | + this.processing = false; |
| 226 | + }); |
| 227 | + |
| 228 | + if (!this.processing) { |
| 229 | + break; |
| 230 | + } |
| 231 | + } |
| 232 | + |
| 233 | + this.processing = false; |
| 234 | + } |
| 235 | +} |
0 commit comments