21
21
detach /2 ,
22
22
transfer /3 ,
23
23
flow /4 ,
24
- disposition /6
24
+ disposition /5
25
25
]).
26
26
27
27
% % Private API
131
131
available = 0 :: non_neg_integer (),
132
132
drain = false :: boolean (),
133
133
partial_transfers :: undefined | {# 'v1_0.transfer' {}, [binary ()]},
134
- auto_flow :: never | {auto , RenewWhenBelow :: pos_integer (), Credit :: pos_integer ()}
135
- }).
134
+ auto_flow :: never | {auto , RenewWhenBelow :: pos_integer (), Credit :: pos_integer ()},
135
+ incoming_unsettled = #{} :: #{delivery_number () => ok }
136
+ }).
136
137
137
138
-record (state ,
138
139
{channel :: pos_integer (),
155
156
connection_config :: amqp10_client_connection :connection_config (),
156
157
outgoing_delivery_id = ? INITIAL_OUTGOING_DELIVERY_ID :: delivery_number (),
157
158
outgoing_unsettled = #{} :: #{delivery_number () => {amqp10_msg :delivery_tag (), Notify :: pid ()}},
158
- incoming_unsettled = #{} :: #{delivery_number () => output_handle ()},
159
159
notify :: pid ()
160
160
}).
161
161
@@ -204,14 +204,18 @@ transfer(Session, Amqp10Msg, Timeout) ->
204
204
flow (Session , Handle , Flow , RenewWhenBelow ) ->
205
205
gen_statem :cast (Session , {flow_link , Handle , Flow , RenewWhenBelow }).
206
206
207
- -spec disposition (pid (), link_role (), delivery_number (), delivery_number (), boolean (),
207
+ % % Sending a disposition on a sender link (with receiver-settle-mode = second)
208
+ % % is currently unsupported.
209
+ -spec disposition (link_ref (), delivery_number (), delivery_number (), boolean (),
208
210
amqp10_client_types :delivery_state ()) -> ok .
209
- disposition (Session , Role , First , Last , Settled , DeliveryState ) ->
210
- gen_statem :call (Session , {disposition , Role , First , Last , Settled ,
211
+ disposition (# link_ref {role = receiver ,
212
+ session = Session ,
213
+ link_handle = Handle },
214
+ First , Last , Settled , DeliveryState ) ->
215
+ gen_statem :call (Session , {disposition , Handle , First , Last , Settled ,
211
216
DeliveryState }, ? TIMEOUT ).
212
217
213
218
214
-
215
219
% % -------------------------------------------------------------------
216
220
% % Private API.
217
221
% % -------------------------------------------------------------------
@@ -277,7 +281,7 @@ mapped(cast, 'end', State) ->
277
281
send_end (State ),
278
282
{next_state , end_sent , State };
279
283
mapped (cast , {flow_link , OutHandle , Flow0 , RenewWhenBelow }, State0 ) ->
280
- State = send_flow_link (fun send / 2 , OutHandle , Flow0 , RenewWhenBelow , State0 ),
284
+ State = send_flow_link (OutHandle , Flow0 , RenewWhenBelow , State0 ),
281
285
{keep_state , State };
282
286
mapped (cast , {flow_session , Flow0 = # 'v1_0.flow' {incoming_window = {uint , IncomingWindow }}},
283
287
# state {next_incoming_id = NII ,
@@ -367,45 +371,43 @@ mapped(cast, {#'v1_0.transfer'{handle = {uint, InHandle},
367
371
State = book_partial_transfer_received (
368
372
State0 # state {links = Links #{OutHandle => Link1 }}),
369
373
{keep_state , State };
370
- mapped (cast , {# 'v1_0.transfer' {handle = {uint , InHandle },
371
- delivery_id = MaybeDeliveryId ,
372
- settled = Settled } = Transfer0 , Payload0 },
373
- # state {incoming_unsettled = Unsettled0 } = State0 ) ->
374
-
374
+ mapped (cast , {Transfer0 = # 'v1_0.transfer' {handle = {uint , InHandle }},
375
+ Payload0 }, State0 ) ->
375
376
{ok , # link {target = {pid , TargetPid },
376
- output_handle = OutHandle ,
377
- ref = LinkRef } = Link0 } =
378
- find_link_by_input_handle (InHandle , State0 ),
377
+ ref = LinkRef ,
378
+ incoming_unsettled = Unsettled
379
+ } = Link0 } = find_link_by_input_handle (InHandle , State0 ),
379
380
380
- {Transfer , Payload , Link1 } = complete_partial_transfer (Transfer0 , Payload0 , Link0 ),
381
- Msg = decode_as_msg (Transfer , Payload ),
382
-
383
- % stash the DeliveryId - not sure for what yet
384
- Unsettled = case MaybeDeliveryId of
385
- {uint , DeliveryId } when Settled =/= true ->
386
- Unsettled0 #{DeliveryId => OutHandle };
387
- _ ->
388
- Unsettled0
389
- end ,
381
+ {Transfer = # 'v1_0.transfer' {settled = Settled ,
382
+ delivery_id = {uint , DeliveryId }},
383
+ Payload , Link1 } = complete_partial_transfer (Transfer0 , Payload0 , Link0 ),
390
384
385
+ Msg = decode_as_msg (Transfer , Payload ),
386
+ Link2 = case Settled of
387
+ true ->
388
+ Link1 ;
389
+ _ ->
390
+ % % "If not set on the first (or only) transfer for a (multi-transfer) delivery,
391
+ % % then the settled flag MUST be interpreted as being false." [2.7.5]
392
+ Link1 # link {incoming_unsettled = Unsettled #{DeliveryId => ok }}
393
+ end ,
391
394
% link bookkeeping
392
395
% notify when credit is exhausted (link_credit = 0)
393
396
% detach the Link with a transfer-limit-exceeded error code if further
394
397
% transfers are received
395
- State1 = State0 # state {incoming_unsettled = Unsettled },
396
- case book_transfer_received (State1 , Link1 ) of
397
- {ok , Link2 , State2 } ->
398
+ case book_transfer_received (State0 , Link2 ) of
399
+ {ok , Link3 , State1 } ->
398
400
% deliver
399
401
TargetPid ! {amqp10_msg , LinkRef , Msg },
400
- State = auto_flow (Link2 , State2 ),
402
+ State = auto_flow (Link3 , State1 ),
401
403
{keep_state , State };
402
- {credit_exhausted , Link2 , State } ->
404
+ {credit_exhausted , Link3 , State } ->
403
405
TargetPid ! {amqp10_msg , LinkRef , Msg },
404
- notify_credit_exhausted (Link2 ),
406
+ notify_credit_exhausted (Link3 ),
405
407
{keep_state , State };
406
- {transfer_limit_exceeded , Link2 , State } ->
407
- logger :warning (" transfer_limit_exceeded for link ~tp " , [Link2 ]),
408
- Link = detach_with_error_cond (Link2 , State ,
408
+ {transfer_limit_exceeded , Link3 , State } ->
409
+ logger :warning (" transfer_limit_exceeded for link ~tp " , [Link3 ]),
410
+ Link = detach_with_error_cond (Link3 , State ,
409
411
? V_1_0_LINK_ERROR_TRANSFER_LIMIT_EXCEEDED ),
410
412
{keep_state , update_link (Link , State )}
411
413
end ;
@@ -501,12 +503,15 @@ mapped({call, From},
501
503
end ;
502
504
503
505
mapped ({call , From },
504
- {disposition , Role , First , Last , Settled0 , DeliveryState },
505
- # state {incoming_unsettled = Unsettled0 } = State0 ) ->
506
+ {disposition , OutputHandle , First , Last , Settled0 , DeliveryState },
507
+ # state {links = Links } = State0 ) ->
508
+ #{OutputHandle := Link0 = # link {incoming_unsettled = Unsettled0 }} = Links ,
506
509
Unsettled = serial_number :foldl (fun maps :remove /2 , Unsettled0 , First , Last ),
507
- State = State0 # state {incoming_unsettled = Unsettled },
510
+ Link = Link0 # link {incoming_unsettled = Unsettled },
511
+ State1 = State0 # state {links = Links #{OutputHandle := Link }},
512
+ State = auto_flow (Link , State1 ),
508
513
Disposition = # 'v1_0.disposition' {
509
- role = translate_role (Role ),
514
+ role = translate_role (receiver ),
510
515
first = {uint , First },
511
516
last = {uint , Last },
512
517
settled = Settled0 ,
@@ -599,7 +604,7 @@ send_transfer(Transfer0, Parts0, MaxMessageSize, #state{socket = Socket,
599
604
{ok , length (Frames )}
600
605
end .
601
606
602
- send_flow_link (Send , OutHandle ,
607
+ send_flow_link (OutHandle ,
603
608
# 'v1_0.flow' {link_credit = {uint , Credit }} = Flow0 , RenewWhenBelow ,
604
609
# state {links = Links ,
605
610
next_incoming_id = NII ,
@@ -625,7 +630,7 @@ send_flow_link(Send, OutHandle,
625
630
% % initial attach frame from the sender this field MUST NOT be set." [2.7.4]
626
631
delivery_count = maybe_uint (DeliveryCount ),
627
632
available = uint (Available )},
628
- ok = Send (Flow , State ),
633
+ ok = send (Flow , State ),
629
634
State # state {links = Links #{OutHandle =>
630
635
Link # link {link_credit = Credit ,
631
636
auto_flow = AutoFlow }}}.
@@ -777,8 +782,9 @@ send_attach(Send, #{name := Name, role := Role} = Args, {FromPid, _},
777
782
max_message_size = MaxMessageSize },
778
783
ok = Send (Attach , State ),
779
784
785
+ LinkRef = make_link_ref (element (1 , Role ), self (), OutHandle ),
780
786
Link = # link {name = Name ,
781
- ref = make_link_ref ( element ( 1 , Role ), self (), OutHandle ) ,
787
+ ref = LinkRef ,
782
788
output_handle = OutHandle ,
783
789
state = attach_sent ,
784
790
role = element (1 , Role ),
@@ -790,7 +796,7 @@ send_attach(Send, #{name := Name, role := Role} = Args, {FromPid, _},
790
796
791
797
{State # state {links = Links #{OutHandle => Link },
792
798
next_link_handle = NextLinkHandle ,
793
- link_index = LinkIndex #{Name => OutHandle }}, Link # link . ref }.
799
+ link_index = LinkIndex #{Name => OutHandle }}, LinkRef }.
794
800
795
801
- spec handle_session_flow (# 'v1_0.flow' {}, # state {}) -> # state {}.
796
802
handle_session_flow (# 'v1_0.flow' {next_incoming_id = MaybeNII ,
@@ -908,7 +914,6 @@ translate_delivery_state({modified,
908
914
translate_delivery_state (released ) -> # 'v1_0.released' {};
909
915
translate_delivery_state (received ) -> # 'v1_0.received' {}.
910
916
911
- translate_role (sender ) -> false ;
912
917
translate_role (receiver ) -> true .
913
918
914
919
maybe_notify_link_credit (# link {role = sender ,
@@ -987,9 +992,11 @@ book_transfer_received(#state{next_incoming_id = NID,
987
992
988
993
auto_flow (# link {link_credit = LC ,
989
994
auto_flow = {auto , RenewWhenBelow , Credit },
990
- output_handle = OutHandle }, State )
991
- when LC < RenewWhenBelow ->
992
- send_flow_link (fun send /2 , OutHandle ,
995
+ output_handle = OutHandle ,
996
+ incoming_unsettled = Unsettled },
997
+ State )
998
+ when LC + map_size (Unsettled ) < RenewWhenBelow ->
999
+ send_flow_link (OutHandle ,
993
1000
# 'v1_0.flow' {link_credit = {uint , Credit }},
994
1001
RenewWhenBelow , State );
995
1002
auto_flow (_ , State ) ->
@@ -1045,7 +1052,8 @@ socket_send0({tcp, Socket}, Data) ->
1045
1052
socket_send0 ({ssl , Socket }, Data ) ->
1046
1053
ssl :send (Socket , Data ).
1047
1054
1048
- - spec make_link_ref (_ , _ , _ ) -> link_ref ().
1055
+ - spec make_link_ref (link_role (), pid (), output_handle ()) ->
1056
+ link_ref ().
1049
1057
make_link_ref (Role , Session , Handle ) ->
1050
1058
# link_ref {role = Role , session = Session , link_handle = Handle }.
1051
1059
@@ -1100,7 +1108,6 @@ format_status(Status = #{data := Data0}) ->
1100
1108
connection_config = ConnectionConfig ,
1101
1109
outgoing_delivery_id = OutgoingDeliveryId ,
1102
1110
outgoing_unsettled = OutgoingUnsettled ,
1103
- incoming_unsettled = IncomingUnsettled ,
1104
1111
notify = Notify
1105
1112
} = Data0 ,
1106
1113
Links = maps :map (
@@ -1119,7 +1126,8 @@ format_status(Status = #{data := Data0}) ->
1119
1126
available = Available ,
1120
1127
drain = Drain ,
1121
1128
partial_transfers = PartialTransfers0 ,
1122
- auto_flow = AutoFlow
1129
+ auto_flow = AutoFlow ,
1130
+ incoming_unsettled = IncomingUnsettled
1123
1131
}) ->
1124
1132
PartialTransfers = case PartialTransfers0 of
1125
1133
undefined ->
@@ -1141,7 +1149,9 @@ format_status(Status = #{data := Data0}) ->
1141
1149
available => Available ,
1142
1150
drain => Drain ,
1143
1151
partial_transfers => PartialTransfers ,
1144
- auto_flow => AutoFlow }
1152
+ auto_flow => AutoFlow ,
1153
+ incoming_unsettled => maps :size (IncomingUnsettled )
1154
+ }
1145
1155
end , Links0 ),
1146
1156
Data = #{channel => Channel ,
1147
1157
remote_channel => RemoteChannel ,
@@ -1160,7 +1170,6 @@ format_status(Status = #{data := Data0}) ->
1160
1170
connection_config => maps :remove (sasl , ConnectionConfig ),
1161
1171
outgoing_delivery_id => OutgoingDeliveryId ,
1162
1172
outgoing_unsettled => maps :size (OutgoingUnsettled ),
1163
- incoming_unsettled => maps :size (IncomingUnsettled ),
1164
1173
notify => Notify },
1165
1174
Status #{data := Data }.
1166
1175
0 commit comments