1use std::fmt;
5use std::sync::Arc;
6use std::vec;
7
8use ruststream::CarriesBatch;
9
10#[cfg(feature = "testing")]
11use super::broker::Shared;
12use super::database::QueueDatabase;
13use super::delivery::{Hold, InboxDelivery};
14use super::engine::{Claimed, Events};
15use super::form::advisory::LockHold;
16use super::form::lease::{LeaseBook, Slot};
17use super::form::row_lock::BatchTx;
18use super::headers::HeaderCell;
19use super::queue::Queue;
20use super::subscriber::{InboxSubscriber, Taken};
21use super::{Lane, PayloadLane, PayloadRow, QueueRow, RowLane};
22use crate::inbox::pools::ServicePool;
23
24#[doc(hidden)]
27pub trait BatchLane<DB: QueueDatabase, Row: Events<DB>>: Lane<Row> {
28 type Batch: IntoIterator<Item = InboxDelivery<DB, Row>> + Send;
30
31 fn batch(claim: BatchClaim<'_, DB, Row>) -> Self::Batch;
33}
34
35#[doc(hidden)]
37pub struct BatchClaim<'s, DB: QueueDatabase, Row: Events<DB>> {
38 subscriber: &'s mut InboxSubscriber<DB, Row>,
39 taken: Taken<DB, Row>,
40 count: usize,
41}
42
43impl<'s, DB: QueueDatabase, Row: Events<DB>> BatchClaim<'s, DB, Row> {
44 pub(crate) const fn new(
46 subscriber: &'s mut InboxSubscriber<DB, Row>,
47 taken: Taken<DB, Row>,
48 count: usize,
49 ) -> Self {
50 Self {
51 subscriber,
52 taken,
53 count,
54 }
55 }
56}
57
58impl<DB: QueueDatabase, Row: Events<DB>> fmt::Debug for BatchClaim<'_, DB, Row> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_struct("BatchClaim")
61 .field("subscription", &self.subscriber.queue().name)
62 .field("count", &self.count)
63 .finish_non_exhaustive()
64 }
65}
66
67impl<DB, Row> BatchLane<DB, Row> for PayloadLane
69where
70 DB: QueueDatabase,
71 Row: Events<DB> + PayloadRow,
72{
73 type Batch = Vec<InboxDelivery<DB, Row>>;
74
75 fn batch(claim: BatchClaim<'_, DB, Row>) -> Self::Batch {
76 let BatchClaim {
77 subscriber,
78 taken,
79 count,
80 } = claim;
81 let (queue, pool) = (subscriber.queue(), subscriber.pool());
82 #[cfg(feature = "testing")]
83 let shared = Arc::clone(&subscriber.shared);
84 let on = |delivery: InboxDelivery<DB, Row>| {
85 #[cfg(feature = "testing")]
86 let delivery = delivery.on(&shared);
87 delivery
88 };
89 match taken {
90 Taken::Locked(tx) => {
91 let batch = BatchTx::new(tx, count);
92 #[cfg(feature = "testing")]
93 batch.watch(&shared);
94 subscriber
95 .take_rows()
96 .map(|claimed| {
97 on(InboxDelivery::batched(
98 claimed,
99 Arc::clone(&batch),
100 queue,
101 pool,
102 ))
103 })
104 .collect()
105 }
106 Taken::Leased(book, lease) => subscriber
108 .take_rows()
109 .map(|claimed| {
110 on(InboxDelivery::leased(
111 claimed, book, lease, None, queue, pool,
112 ))
113 })
114 .collect(),
115 Taken::Advised => subscriber
117 .take_advised()
118 .map(|(claimed, hold)| on(InboxDelivery::advised(claimed, hold, queue, pool)))
119 .collect(),
120 }
121 }
122}
123
124impl<DB, Row> BatchLane<DB, Row> for RowLane
126where
127 DB: QueueDatabase,
128 Row: Events<DB> + QueueRow<Lane = Self>,
129{
130 type Batch = RowBatch<DB, Row>;
131
132 fn batch(claim: BatchClaim<'_, DB, Row>) -> Self::Batch {
133 RowBatch::new(claim)
134 }
135}
136
137pub struct RowBatch<DB, Row>
195where
196 DB: QueueDatabase,
197 Row: Events<DB> + QueueRow<Lane = RowLane>,
198{
199 deliveries: RowDeliveries<DB, Row>,
200}
201
202#[doc(hidden)]
208pub struct RowDeliveries<DB, Row>
209where
210 DB: QueueDatabase,
211 Row: Events<DB> + QueueRow<Lane = RowLane>,
212{
213 rows: vec::IntoIter<Row>,
215 headers: vec::IntoIter<Row::Headers>,
219 claims: Claims<DB, Row>,
221 gone: vec::IntoIter<InboxDelivery<DB, Row>>,
224 queue: &'static Queue,
225 pool: &'static ServicePool<DB>,
226 #[cfg(feature = "testing")]
229 shared: Arc<Shared<DB>>,
230}
231
232enum Claims<DB: QueueDatabase, Row: Events<DB>> {
234 Locked(Arc<BatchTx<DB>>),
236 Leased(&'static LeaseBook<DB, Row>, vec::IntoIter<Slot>),
239 Advised(vec::IntoIter<LockHold<DB>>),
241}
242
243impl<DB, Row> RowBatch<DB, Row>
244where
245 DB: QueueDatabase,
246 Row: Events<DB> + QueueRow<Lane = RowLane>,
247{
248 fn new(claim: BatchClaim<'_, DB, Row>) -> Self {
251 let BatchClaim {
252 subscriber,
253 taken,
254 count,
255 } = claim;
256 let (queue, pool) = (subscriber.queue(), subscriber.pool());
257 #[cfg(feature = "testing")]
258 let shared = Arc::clone(&subscriber.shared);
259 let on = |delivery: InboxDelivery<DB, Row>| {
260 #[cfg(feature = "testing")]
261 let delivery = delivery.on(&shared);
262 delivery
263 };
264 let mut rows = Vec::with_capacity(count);
265 let mut headers = Vec::new();
266 let mut gone = Vec::new();
267 let claims = match taken {
268 Taken::Locked(tx) => {
269 let batch = BatchTx::new(tx, count);
270 #[cfg(feature = "testing")]
271 batch.watch(&shared);
272 for claimed in subscriber.take_rows() {
273 match claimed {
274 Claimed::Row(row) => take(row, &mut rows, &mut headers, count),
275 claimed => gone.push(on(InboxDelivery::batched(
276 claimed,
277 Arc::clone(&batch),
278 queue,
279 pool,
280 ))),
281 }
282 }
283 Claims::Locked(batch)
284 }
285 Taken::Leased(book, lease) => {
286 let mut slots = Vec::with_capacity(count);
287 for claimed in subscriber.take_rows() {
288 match claimed {
289 Claimed::Row(row) => {
290 slots.push(book.enter(Row::id(&row), lease));
291 take(row, &mut rows, &mut headers, count);
292 }
293 claimed => gone.push(on(InboxDelivery::leased(
294 claimed, book, lease, None, queue, pool,
295 ))),
296 }
297 }
298 Claims::Leased(book, slots.into_iter())
299 }
300 Taken::Advised => {
301 let mut holds = Vec::with_capacity(count);
302 for (claimed, hold) in subscriber.take_advised() {
303 match claimed {
304 Claimed::Row(row) => {
305 holds.push(hold);
306 take(row, &mut rows, &mut headers, count);
307 }
308 claimed => {
309 gone.push(on(InboxDelivery::advised(claimed, hold, queue, pool)));
310 }
311 }
312 }
313 Claims::Advised(holds.into_iter())
314 }
315 };
316 Self {
317 deliveries: RowDeliveries {
318 rows: rows.into_iter(),
319 headers: headers.into_iter(),
320 claims,
321 gone: gone.into_iter(),
322 queue,
323 pool,
324 #[cfg(feature = "testing")]
325 shared,
326 },
327 }
328 }
329}
330
331fn take<DB: QueueDatabase, Row: Events<DB>>(
334 mut row: Row,
335 rows: &mut Vec<Row>,
336 headers: &mut Vec<Row::Headers>,
337 count: usize,
338) {
339 let taken = Row::Headers::take(&mut row);
340 if !headers.is_empty() || !taken.is_unset() {
341 if headers.is_empty() {
342 headers.reserve_exact(count);
343 headers.resize_with(rows.len(), Row::Headers::default);
344 }
345 headers.push(taken);
346 }
347 rows.push(row);
348}
349
350impl<DB, Row> CarriesBatch<Row> for RowBatch<DB, Row>
351where
352 DB: QueueDatabase,
353 Row: Events<DB> + QueueRow<Lane = RowLane>,
354{
355 fn carried(&self) -> &[Row] {
356 self.deliveries.rows.as_slice()
357 }
358}
359
360impl<DB, Row> IntoIterator for RowBatch<DB, Row>
361where
362 DB: QueueDatabase,
363 Row: Events<DB> + QueueRow<Lane = RowLane>,
364{
365 type Item = InboxDelivery<DB, Row>;
366 type IntoIter = RowDeliveries<DB, Row>;
367
368 fn into_iter(self) -> Self::IntoIter {
369 self.deliveries
370 }
371}
372
373impl<DB, Row> Iterator for RowDeliveries<DB, Row>
374where
375 DB: QueueDatabase,
376 Row: Events<DB> + QueueRow<Lane = RowLane>,
377{
378 type Item = InboxDelivery<DB, Row>;
379
380 fn next(&mut self) -> Option<Self::Item> {
381 if self.rows.len() == 0 {
382 return self.gone.next();
383 }
384 let hold = match &mut self.claims {
385 Claims::Locked(batch) => Hold::Batch(Arc::clone(batch)),
386 Claims::Leased(book, slots) => Hold::Lease {
387 book: *book,
388 slot: slots.next()?,
389 tx: None,
390 },
391 Claims::Advised(holds) => Hold::Advisory(holds.next()?),
392 };
393 let row = self.rows.next()?;
395 let headers = self.headers.next().unwrap_or_default();
396 let delivery = InboxDelivery::of_batch(row, headers, hold, self.queue, self.pool);
397 #[cfg(feature = "testing")]
398 let delivery = delivery.on(&self.shared);
399 Some(delivery)
400 }
401
402 fn size_hint(&self) -> (usize, Option<usize>) {
403 let len = self.rows.len() + self.gone.len();
404 (len, Some(len))
405 }
406}
407
408impl<DB, Row> ExactSizeIterator for RowDeliveries<DB, Row>
409where
410 DB: QueueDatabase,
411 Row: Events<DB> + QueueRow<Lane = RowLane>,
412{
413}
414
415impl<DB, Row> Drop for RowDeliveries<DB, Row>
416where
417 DB: QueueDatabase,
418 Row: Events<DB> + QueueRow<Lane = RowLane>,
419{
420 fn drop(&mut self) {
421 self.for_each(drop);
424 }
425}
426
427impl<DB, Row> fmt::Debug for RowBatch<DB, Row>
428where
429 DB: QueueDatabase,
430 Row: Events<DB> + QueueRow<Lane = RowLane>,
431{
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 f.debug_struct("RowBatch")
434 .field("subscription", &self.deliveries.queue.name)
435 .field("rows", &self.deliveries.rows.len())
436 .field("gone", &self.deliveries.gone.len())
437 .finish_non_exhaustive()
438 }
439}
440
441impl<DB, Row> fmt::Debug for RowDeliveries<DB, Row>
442where
443 DB: QueueDatabase,
444 Row: Events<DB> + QueueRow<Lane = RowLane>,
445{
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 f.debug_struct("RowDeliveries")
448 .field("subscription", &self.queue.name)
449 .field("left", &self.len())
450 .finish_non_exhaustive()
451 }
452}