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 subscriber
93 .take_rows()
94 .map(|claimed| {
95 on(InboxDelivery::batched(
96 claimed,
97 Arc::clone(&batch),
98 queue,
99 pool,
100 ))
101 })
102 .collect()
103 }
104 Taken::Leased(book, lease) => subscriber
106 .take_rows()
107 .map(|claimed| {
108 on(InboxDelivery::leased(
109 claimed, book, lease, None, queue, pool,
110 ))
111 })
112 .collect(),
113 Taken::Advised => subscriber
115 .take_advised()
116 .map(|(claimed, hold)| on(InboxDelivery::advised(claimed, hold, queue, pool)))
117 .collect(),
118 }
119 }
120}
121
122impl<DB, Row> BatchLane<DB, Row> for RowLane
124where
125 DB: QueueDatabase,
126 Row: Events<DB> + QueueRow<Lane = Self>,
127{
128 type Batch = RowBatch<DB, Row>;
129
130 fn batch(claim: BatchClaim<'_, DB, Row>) -> Self::Batch {
131 RowBatch::new(claim)
132 }
133}
134
135pub struct RowBatch<DB, Row>
193where
194 DB: QueueDatabase,
195 Row: Events<DB> + QueueRow<Lane = RowLane>,
196{
197 deliveries: RowDeliveries<DB, Row>,
198}
199
200#[doc(hidden)]
206pub struct RowDeliveries<DB, Row>
207where
208 DB: QueueDatabase,
209 Row: Events<DB> + QueueRow<Lane = RowLane>,
210{
211 rows: vec::IntoIter<Row>,
213 headers: vec::IntoIter<Row::Headers>,
217 claims: Claims<DB, Row>,
219 gone: vec::IntoIter<InboxDelivery<DB, Row>>,
222 queue: &'static Queue,
223 pool: &'static ServicePool<DB>,
224 #[cfg(feature = "testing")]
227 shared: Arc<Shared<DB>>,
228}
229
230enum Claims<DB: QueueDatabase, Row: Events<DB>> {
232 Locked(Arc<BatchTx<DB>>),
234 Leased(&'static LeaseBook<DB, Row>, vec::IntoIter<Slot>),
237 Advised(vec::IntoIter<LockHold<DB>>),
239}
240
241impl<DB, Row> RowBatch<DB, Row>
242where
243 DB: QueueDatabase,
244 Row: Events<DB> + QueueRow<Lane = RowLane>,
245{
246 fn new(claim: BatchClaim<'_, DB, Row>) -> Self {
249 let BatchClaim {
250 subscriber,
251 taken,
252 count,
253 } = claim;
254 let (queue, pool) = (subscriber.queue(), subscriber.pool());
255 #[cfg(feature = "testing")]
256 let shared = Arc::clone(&subscriber.shared);
257 let on = |delivery: InboxDelivery<DB, Row>| {
258 #[cfg(feature = "testing")]
259 let delivery = delivery.on(&shared);
260 delivery
261 };
262 let mut rows = Vec::with_capacity(count);
263 let mut headers = Vec::new();
264 let mut gone = Vec::new();
265 let claims = match taken {
266 Taken::Locked(tx) => {
267 let batch = BatchTx::new(tx, count);
268 for claimed in subscriber.take_rows() {
269 match claimed {
270 Claimed::Row(row) => take(row, &mut rows, &mut headers, count),
271 claimed => gone.push(on(InboxDelivery::batched(
272 claimed,
273 Arc::clone(&batch),
274 queue,
275 pool,
276 ))),
277 }
278 }
279 Claims::Locked(batch)
280 }
281 Taken::Leased(book, lease) => {
282 let mut slots = Vec::with_capacity(count);
283 for claimed in subscriber.take_rows() {
284 match claimed {
285 Claimed::Row(row) => {
286 slots.push(book.enter(Row::id(&row), lease));
287 take(row, &mut rows, &mut headers, count);
288 }
289 claimed => gone.push(on(InboxDelivery::leased(
290 claimed, book, lease, None, queue, pool,
291 ))),
292 }
293 }
294 Claims::Leased(book, slots.into_iter())
295 }
296 Taken::Advised => {
297 let mut holds = Vec::with_capacity(count);
298 for (claimed, hold) in subscriber.take_advised() {
299 match claimed {
300 Claimed::Row(row) => {
301 holds.push(hold);
302 take(row, &mut rows, &mut headers, count);
303 }
304 claimed => {
305 gone.push(on(InboxDelivery::advised(claimed, hold, queue, pool)));
306 }
307 }
308 }
309 Claims::Advised(holds.into_iter())
310 }
311 };
312 Self {
313 deliveries: RowDeliveries {
314 rows: rows.into_iter(),
315 headers: headers.into_iter(),
316 claims,
317 gone: gone.into_iter(),
318 queue,
319 pool,
320 #[cfg(feature = "testing")]
321 shared,
322 },
323 }
324 }
325}
326
327fn take<DB: QueueDatabase, Row: Events<DB>>(
330 mut row: Row,
331 rows: &mut Vec<Row>,
332 headers: &mut Vec<Row::Headers>,
333 count: usize,
334) {
335 let taken = Row::Headers::take(&mut row);
336 if !headers.is_empty() || !taken.is_unset() {
337 if headers.is_empty() {
338 headers.reserve_exact(count);
339 headers.resize_with(rows.len(), Row::Headers::default);
340 }
341 headers.push(taken);
342 }
343 rows.push(row);
344}
345
346impl<DB, Row> CarriesBatch<Row> for RowBatch<DB, Row>
347where
348 DB: QueueDatabase,
349 Row: Events<DB> + QueueRow<Lane = RowLane>,
350{
351 fn carried(&self) -> &[Row] {
352 self.deliveries.rows.as_slice()
353 }
354}
355
356impl<DB, Row> IntoIterator for RowBatch<DB, Row>
357where
358 DB: QueueDatabase,
359 Row: Events<DB> + QueueRow<Lane = RowLane>,
360{
361 type Item = InboxDelivery<DB, Row>;
362 type IntoIter = RowDeliveries<DB, Row>;
363
364 fn into_iter(self) -> Self::IntoIter {
365 self.deliveries
366 }
367}
368
369impl<DB, Row> Iterator for RowDeliveries<DB, Row>
370where
371 DB: QueueDatabase,
372 Row: Events<DB> + QueueRow<Lane = RowLane>,
373{
374 type Item = InboxDelivery<DB, Row>;
375
376 fn next(&mut self) -> Option<Self::Item> {
377 if self.rows.len() == 0 {
378 return self.gone.next();
379 }
380 let hold = match &mut self.claims {
381 Claims::Locked(batch) => Hold::Batch(Arc::clone(batch)),
382 Claims::Leased(book, slots) => Hold::Lease {
383 book: *book,
384 slot: slots.next()?,
385 tx: None,
386 },
387 Claims::Advised(holds) => Hold::Advisory(holds.next()?),
388 };
389 let row = self.rows.next()?;
391 let headers = self.headers.next().unwrap_or_default();
392 let delivery = InboxDelivery::of_batch(row, headers, hold, self.queue, self.pool);
393 #[cfg(feature = "testing")]
394 let delivery = delivery.on(&self.shared);
395 Some(delivery)
396 }
397
398 fn size_hint(&self) -> (usize, Option<usize>) {
399 let len = self.rows.len() + self.gone.len();
400 (len, Some(len))
401 }
402}
403
404impl<DB, Row> ExactSizeIterator for RowDeliveries<DB, Row>
405where
406 DB: QueueDatabase,
407 Row: Events<DB> + QueueRow<Lane = RowLane>,
408{
409}
410
411impl<DB, Row> Drop for RowDeliveries<DB, Row>
412where
413 DB: QueueDatabase,
414 Row: Events<DB> + QueueRow<Lane = RowLane>,
415{
416 fn drop(&mut self) {
417 self.for_each(drop);
420 }
421}
422
423impl<DB, Row> fmt::Debug for RowBatch<DB, Row>
424where
425 DB: QueueDatabase,
426 Row: Events<DB> + QueueRow<Lane = RowLane>,
427{
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 f.debug_struct("RowBatch")
430 .field("subscription", &self.deliveries.queue.name)
431 .field("rows", &self.deliveries.rows.len())
432 .field("gone", &self.deliveries.gone.len())
433 .finish_non_exhaustive()
434 }
435}
436
437impl<DB, Row> fmt::Debug for RowDeliveries<DB, Row>
438where
439 DB: QueueDatabase,
440 Row: Events<DB> + QueueRow<Lane = RowLane>,
441{
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 f.debug_struct("RowDeliveries")
444 .field("subscription", &self.queue.name)
445 .field("left", &self.len())
446 .finish_non_exhaustive()
447 }
448}