| Commit message (Collapse) | Author | Age | Files | Lines |
| | |
|
| | |
|
| | |
|
| |\ |
|
| | | |
|
| | |\ |
|
| | | |
| | |
| | |
| | | |
but have unsynced slaves at that point.
|
| | | | |
|
| | |\ \ |
|
| | | |\ \ |
|
| | | | |\ \ |
|
| | | | | |\ \ |
|
| | | | | |/ / |
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | | |
that the parameter exists.
|
| | | | |/ / |
|
| | | |/ /
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Specifically in all the cases where handle_other might have changed
the connection_state.
This is most straightforward and obvious to guarantee by always
invoking recvloop after handle_other, unless we are stopping.
This does expose an inconsistency in the various non-throw/exit
termination cases: two of them were returning State, the other
ok. Let's go with the latter; it's easiest.
We also take the opportunity to eliminate 'Deb' from the handle_other
signature. This is only needed in the {system, ...} message case,
which we now handle specially.
|
| | | | | |
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
It makes no difference whether we call handle_exception before or
after control_throttle, so lets use an order that more clearly calls
out the similarity to the controlled exit case.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
by re-introducing a call to control_throttle.
This was present in 3.0.x, and is needed there, but is actually not
needed here, due to other changes made in the area. But the reason is
quite subtle...
For control_throttle to do something here, the channel_cleanup would
have to be called for a channel for which we have run out of
credit. Now, credit is only consumed when sending content-bearing
methods to the channel with rabbit_channel:do_flow. There is a
subsequent invocation of control_throttle in the code which will set
the connection_state to 'blocking'. But this is immediately followed
by a call to post_process_frame. The frame we are looking at must be
the last frame of a content-bearing method, since otherwise the method
would not be complete and we wouldn't have passed it to the
channel. Hence that frame can only be a content_header or, more
likely, a content_body. For both of these, post_process_frame invokes
maybe_block, which will turn a 'blocking' into 'blocked'. And from
that point onwards we will no longer read anything from the socket or
process anything already in buf. So we certainly can't be processing a
channel.close_ok.
In other words, post_process_frame can only be invoked with a
channel.close_ok frame when the connection_state is 'running', or
blocking/blocked for a reason other than having run out of credit for
a channel, i.e. an alarm. Therefore forgetting about the channel as
part of the channel_cleanup call does not have an effect on
credit_flow:blocked(). And hence an invocation of control_throttle
will not alter the connection_state and is therefore unnecessary.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
- handle the no-op case (controlled exit of a channel we've forgotten
about already) explicitly
- better clause order and formatting.
|
| | | | | |
|
| | |\ \ \ |
|
| | | | | | |
|
| | | | | | |
|
| | | |\ \ \
| | | |/ /
| | |/| | |
|
| | | |\ \ \ |
|
| | | | | | | |
|
| | | | | | | |
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | | |
boot/0 or start/0, create a new process to hold the name instead.
|
| | | |/ / /
| | | | |
| | | | |
| | | | | |
stopping.
|
| | | | | | |
|
| | | | | | |
|
| |\ \ \ \ \
| | |_|/ /
| |/| | | |
|
| | |\ \ \ \ |
|
| | | |\ \ \ \ |
|
| | | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
And on recover. And when the timer goes off. That's all we need.
new call sites:
- in deliver_or_enqueue/3, when enqueuing a message (that we couldn't
deliver to a consumer straight away) with an expiry to the head.
the queue. NB: Previously we were always (re)setting a timer when
enqueuing a message with an expiry, which is wasteful when the new
message isn't at the head (i.e. the queue was non-empty) or when it
needs expiring immediately.
- requeue_and_run/2, since a message may get requeued to the
head. This call site arises due to removal of the
run_message_queue/1 call site (see below).
unchanged call sites:
- init_ttl/2 - this is the recovery case
- fetch/2, after fetching - this is the basic "queue head changes"
case
- handle_info/drop_expired - this is the message expiry timer
removed call sites:
- run_message_queue/1 - this internally calls fetch/2 (see above) but
also invoking drop_expired_msgs at the beginning. This now happens
at the call sites, where it is necessary. Which actually only is in
requeue_and_run, and not the others, none of which change the queue
content prior to calling run_message_queue/1
- possibly_unblock/3 - unblocking of consumers
- handle_call/basic_consumer - adding a consumer
- handle_call/basic_get, prior to the call to fetch/2.
- handle_call/stat
|
| | | |/ / / /
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Since that would only be necessary of the BQ:invoke modified the
consumers, which it can't, or added messages to the queue, which it
shouldn't.
|
| | |/ / / / |
|
| | | | | | |
|
| | |\ \ \ \
| | | |/ /
| | |/| | |
|
| | | |\ \ \ |
|
| | | |/ / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
...so messages with an expiry that are at the head of the queue after
a basic.get do not get stuck there in the absence of other queue
activity.
Rather than simply adding a call to drop_expired_messages/1 after the
call to fetch/1 in the basic_get code, we insert the call into
fetch/1, which allows us to remove it from the other call site. Thus
fetch/1 preserves the invariant we are after, namely that whenever a
queue has a message at the head with an expiry, there is a timer set
to drop said message.
Note that the message count returned by basic.get does not reflect the
dropping of expired messages after the fetched message. That's ok
since we make no guarantee that messages are expired straight
away. And note that on 'default' (rather than 'stable') the behaviour
is actually different; due to various other changes there we will in
fact return the reduced count.
|
| | | |/ /
| |/| | |
|
| | |\ \ \ |
|
| | | | | |
| | | | |
| | | | |
| | | | | |
up in the registry).
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
- use BQ:is_empty instead of BQ:len
- make use of Stop flag
|
| | | | | | |
|
| | | | | | |
|
| | | | | | |
|
| | | | | | |
|