1212 publish /5 , publish_delivered /4 ,
1313 discard /3 , drain_confirmed /1 ,
1414 dropwhile /2 , fetchwhile /4 , fetch /2 , drop /2 , ack /2 , requeue /3 ,
15- ackfold /4 , len /1 , is_empty /1 , depth /1 ,
15+ ackfold /5 , len /1 , is_empty /1 , depth /1 ,
1616 update_rates /1 , needs_timeout /1 , timeout /1 ,
1717 handle_pre_hibernate /1 , resume /1 , msg_rates /1 ,
1818 info /2 , invoke /3 , is_duplicate /2 ,
@@ -562,12 +562,12 @@ fetch(AckRequired, State) ->
562562 % % it is possible that the message wasn't read from disk
563563 % % at this point, so read it in.
564564 {Msg0 , State2 } = read_msg (MsgStatus , State1 ),
565- Msg = add_delivery_count (MsgStatus # msg_status .seq_id , Msg0 , State2 ),
565+ Msg = annotate_delivery_count (MsgStatus # msg_status .seq_id , Msg0 , State2 ),
566566 {AckTag , State3 } = remove (AckRequired , MsgStatus , State2 ),
567567 {{Msg , MsgStatus # msg_status .is_delivered , AckTag }, a (State3 )}
568568 end .
569569
570- add_delivery_count (SeqId , Msg , # vqstate {
570+ annotate_delivery_count (SeqId , Msg , # vqstate {
571571 redeliver_seq_id = RedeliverSeqId ,
572572 delivery_count = DeliveryCount }) ->
573573 case DeliveryCount of
@@ -589,6 +589,7 @@ drop(AckRequired, State) ->
589589 {empty , a (State1 )};
590590 {{value , MsgStatus }, State1 } ->
591591 {AckTag , State2 } = remove (AckRequired , MsgStatus , State1 ),
592+ % % @todo I think the first element is not needed, only need to return state.
592593 {{MsgStatus # msg_status .msg_id , AckTag }, a (State2 )}
593594 end .
594595
@@ -647,12 +648,17 @@ requeue(AckTags, DelFailed, #vqstate { q_head = QHead0,
647648 in_counter = InCounter + MsgCount
648649 }))}.
649650
650- ackfold (MsgFun , Acc , State , AckTags ) ->
651+ % % This function is called when messages get discarded (rejected AMQP 1.0 outcome)
652+ % % and delivered to a dead letter queue. We must therefore increase the delivery_count
653+ % % for these messages the same as if they were requeued.
654+ ackfold (MsgFun , Acc , State , AckTags , DelFailed ) ->
651655 {AccN , StateN } =
652656 lists :foldl (fun (SeqId , {Acc0 , State0 }) ->
653657 MsgStatus = lookup_pending_ack (SeqId , State0 ),
654- {Msg , State1 } = read_msg (MsgStatus , State0 ),
655- {MsgFun (Msg , SeqId , Acc0 ), State1 }
658+ {Msg0 , State1 } = read_msg (MsgStatus , State0 ),
659+ State2 = maybe_inc_delivery_count (SeqId , DelFailed , State1 ),
660+ Msg = annotate_delivery_count (MsgStatus # msg_status .seq_id , Msg0 , State2 ),
661+ {MsgFun (Msg , SeqId , Acc0 ), State2 }
656662 end , {Acc , State }, AckTags ),
657663 {AccN , a (StateN )}.
658664
@@ -1391,7 +1397,8 @@ process_queue_entries1(
13911397 # msg_status { seq_id = SeqId } = MsgStatus ,
13921398 Fun ,
13931399 {FetchAcc , State }) ->
1394- {Msg , State1 } = read_msg (MsgStatus , State ),
1400+ {Msg0 , State1 } = read_msg (MsgStatus , State ),
1401+ Msg = annotate_delivery_count (MsgStatus # msg_status .seq_id , Msg0 , State1 ),
13951402 State2 = record_pending_ack (
13961403 MsgStatus # msg_status {
13971404 is_delivered = true }, State1 ),
@@ -1511,6 +1518,7 @@ publish1(Msg,
15111518 q_tail = QTail = # q_tail { count = QTailCount },
15121519 qi_embed_msgs_below = IndexMaxSize ,
15131520 next_seq_id = SeqId ,
1521+ delivery_count = DeliveryCount0 ,
15141522 in_counter = InCount ,
15151523 durable = IsDurable ,
15161524 unconfirmed = UC ,
@@ -1538,7 +1546,9 @@ publish1(Msg,
15381546 end ,
15391547 {UC1 , UCS1 } = maybe_needs_confirming (NeedsConfirming , persist_to (MsgStatus ),
15401548 MsgId , UC , UCS ),
1549+ DeliveryCount = update_delivery_count (SeqId , Msg , DeliveryCount0 ),
15411550 State3 # vqstate { next_seq_id = SeqId + 1 ,
1551+ delivery_count = DeliveryCount ,
15421552 in_counter = InCount + 1 ,
15431553 unconfirmed = UC1 ,
15441554 unconfirmed_simple = UCS1 }.
@@ -1549,6 +1559,7 @@ publish_delivered1(Msg,
15491559 _ChPid , PersistFun ,
15501560 State = # vqstate { qi_embed_msgs_below = IndexMaxSize ,
15511561 next_seq_id = SeqId ,
1562+ delivery_count = DeliveryCount0 ,
15521563 in_counter = InCount ,
15531564 out_counter = OutCount ,
15541565 durable = IsDurable ,
@@ -1562,9 +1573,11 @@ publish_delivered1(Msg,
15621573 State2 = record_pending_ack (m (MsgStatus1 ), State1 ),
15631574 {UC1 , UCS1 } = maybe_needs_confirming (NeedsConfirming , persist_to (MsgStatus ),
15641575 MsgId , UC , UCS ),
1576+ DeliveryCount = update_delivery_count (SeqId , Msg , DeliveryCount0 ),
15651577 {SeqId ,
15661578 stats_published_pending_acks (MsgStatus1 ,
15671579 State2 # vqstate { next_seq_id = SeqId + 1 ,
1580+ delivery_count = DeliveryCount ,
15681581 out_counter = OutCount + 1 ,
15691582 in_counter = InCount + 1 ,
15701583 unconfirmed = UC1 ,
@@ -1580,6 +1593,12 @@ maybe_needs_confirming(true, queue_store, MsgId, UC, UCS) ->
15801593maybe_needs_confirming (true , _ , MsgId , UC , UCS ) ->
15811594 {sets :add_element (MsgId , UC ), UCS }.
15821595
1596+ update_delivery_count (SeqId , Msg , DeliveryCount ) ->
1597+ case mc :get_annotation (delivery_count , Msg ) of
1598+ undefined -> DeliveryCount ;
1599+ Count -> DeliveryCount #{SeqId => Count }
1600+ end .
1601+
15831602maybe_write_msg_to_disk (Force , MsgStatus = # msg_status {
15841603 seq_id = SeqId ,
15851604 msg = Msg , msg_id = MsgId ,
@@ -1827,26 +1846,29 @@ requeue_merge([SeqId | Rest] = SeqIds, DelFailed, Q, Front, MsgIds, State) ->
18271846 case msg_from_pending_ack (SeqId , State ) of
18281847 {none , _ } ->
18291848 requeue_merge (Rest , DelFailed , Q , Front , MsgIds , State );
1830- {# msg_status { msg_id = MsgId } = MsgStatus , State1 = # vqstate { redeliver_seq_id = RedeliverSeqId , delivery_count = DeliveryCount0 } } ->
1849+ {# msg_status { msg_id = MsgId } = MsgStatus , State1 } ->
18311850 % % Increment delivery_count.
1832- DeliveryCount = case DelFailed of
1833- true -> maps :update_with (SeqId ,
1834- fun (V ) -> V + 1 end ,
1835- % % Message was possibly delivered at least once.
1836- case SeqId < RedeliverSeqId of
1837- true -> 2 ;
1838- false -> 1
1839- end ,
1840- DeliveryCount0 );
1841- false -> DeliveryCount0
1842- end ,
1843- State2 = stats_requeued_memory (MsgStatus , State1 # vqstate {delivery_count = DeliveryCount }),
1844- requeue_merge (Rest , DelFailed , Q , ? QUEUE :in (MsgStatus , Front ), [MsgId | MsgIds ], State2 )
1851+ State2 = maybe_inc_delivery_count (SeqId , DelFailed , State1 ),
1852+ State3 = stats_requeued_memory (MsgStatus , State2 ),
1853+ requeue_merge (Rest , DelFailed , Q , ? QUEUE :in (MsgStatus , Front ), [MsgId | MsgIds ], State3 )
18451854 end
18461855 end ;
18471856requeue_merge ([], _ , Q , Front , MsgIds , State ) ->
18481857 {? QUEUE :join (Front , Q ), MsgIds , State }.
18491858
1859+ maybe_inc_delivery_count (_ , false , State ) ->
1860+ State ;
1861+ maybe_inc_delivery_count (SeqId , true , State = # vqstate {redeliver_seq_id = RedeliverSeqId , delivery_count = DeliveryCount0 }) ->
1862+ DeliveryCount = maps :update_with (SeqId ,
1863+ fun (V ) -> V + 1 end ,
1864+ % % Message was possibly delivered at least once.
1865+ case SeqId < RedeliverSeqId of
1866+ true -> 2 ;
1867+ false -> 1
1868+ end ,
1869+ DeliveryCount0 ),
1870+ State # vqstate {delivery_count = DeliveryCount }.
1871+
18501872% % Mostly opposite of record_pending_ack/2
18511873msg_from_pending_ack (SeqId , State ) ->
18521874 case remove_pending_ack (false , SeqId , State ) of
0 commit comments