-
Notifications
You must be signed in to change notification settings - Fork 534
Request saturation (rule 3.17) #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @DougLea, The reason for this rule was that we couldn't find a single plausible situation where an overflow of 2^63 would make sense, so an overflow would mean a buggy Subscriber, in which case we wanted to fail fast. Remember that signalled demand == current buffer capacity (since sync Subscribers would be able to call Sane of operation (please feel free to add more here): N buffered lock-step == call |
Do you mean that the non-error saturation/overflow cases are only those in which demand is already Long.MAX_VALUE, or there is a request(MAX_VALUE) call? In which case, the "may treat as unbounded" must be changed to "must treat as unbounded" -- otherwise demand will become less than Long.MAX_VALUE after a consume. This rule seems to target a narrow class of bad usages while prohibiting a narrow class of valid usages, so might not be worthwhile. The use cases I had in mind include those with a known-to-be-slow producer (like a once-an-hour timer) for which you'd set request(Long.MAX_VALUE) up front. But then might call some utility method that must ensure demand > 0 so calls request(1). (Similar issues with other sets of request values that happen to add up to > Long.MAX_VALUE.) There's no good way for users to cope unless saturating on overflow is legal (which I'm still not sure is not legal according to current wording.) |
Hi Doug! Answers inline: On 6 Jan 2015 13:19, "DougLea" [email protected] wrote:
Which is fine, the rationale is in the footnote of the rule: " [1] : As it
It is less about preventing bad intentional usage as it is to prevent buggy
A Subscriber does not know whether a Publisher is fast or slow tho (at For a slow Publisher the overhead of calling request (1) in onNext has But then might call some utility method that must ensure demand > 0 so I am not sure I follow, isn't this covered by any the scenarios I listed? Overflowing is not compliant, IIRC the TCK checks for that.
|
I think that this comes down to either (1) adding wording that amounts to saying that upon consume, a demand of Long.MAX_VALUE is not decremented (otherwise you cannot define/detect some violations of 3.17), or (2) just omitting the wording and allowing saturation. (2) still seems like a better tradeoff. I imagine that usages will eventually include some specialized Pub/Sub pairs that do know approximate rates before hand and try to set up best flow statically. And then become unhappy when good-intentioned rules prevented them from doing this. |
I think I understand your point now, is your question whether it is legal Cheers,
|
Well, I think that if you answer that question, then you've answered all of them! |
Yes, that would be legal since it would not overflow 2^63-1. I'm open to be convinced we can drop the onError for overflow requirement, Disabling that rule may have some adverse effects on the implementations The question is how important that'd be given it'd take > 292 years to find Cheers,
|
Of course assuming that no previous demand existed prior to issuing the Cheers,
|
How about calling request(17) in onNext if you've already called request (Long.MAX_VALUE)? Since there is no Subscription.getDemand() method (and I don't think there needs to be one), the simpler the rule the better. Saturate-at-max is one way to reduce pubs/subs implementor errors as they try account for these rules when tracking. Anything simpler would be even better, but I can't think of anything. |
On Tue, Jan 6, 2015 at 3:25 PM, DougLea [email protected] wrote:
What does Mr Protocol say (@tmontgomery)?
Cheers, |
In case it is helpful: Note that the current demand is an upper bound on how much buffering producers need to guarantee not to drop or block. Capacities past a billion or so (and usually far far less) are never going to be preallocated. So subscription.request(Long.MAX_VALUE) means that the caller risks potential block/drop/fail whenever resources run out (or whenever the Publisher feels like it) rather than in a controlled fashion. This may be a common initial/casual usage idiom for simple consumers, who will then sometimes find out that they should do something better. |
On Tue, Jan 6, 2015 at 7:30 PM, DougLea [email protected] wrote:
Cheers, |
Currently we have: | <a name="3.17">17</a> | A `Subscription` MUST support an unbounded number of calls to request and MUST support a demand (sum requested - sum delivered) up to 2^63-1 (`java.lang.Long.MAX_VALUE`). A demand of exactly 2^63-1 (`java.lang.Long.MAX_VALUE`) MAY be considered by the `Publisher` as `effectively unbounded`[[1](#footnote-3-1)]. If demand becomes higher than 2^63-1 then the `Publisher` MUST signal an onError with `java.lang.IllegalStateException` on the given `Subscriber`. The cause message MUST include a reference to this rule and/or quote the full rule |
[<a name="footnote-3-1">1</a>] : As it is not feasibly reachable with current or forseen hardware within a reasonable amount of time (1 element per nanosecond would take 292 years) to fulfill a demand of 2^63-1. How about we change it to: | <a name="3.17">17</a> | A `Subscription` MUST support an unbounded number of calls to request and MUST support a demand (sum requested - sum delivered) up to 2^63-1 (`java.lang.Long.MAX_VALUE`). A demand equal or greater than 2^63-1 (`java.lang.Long.MAX_VALUE`) MAY be considered by the `Publisher` as `effectively unbounded`[[1](#footnote-3-1)]. |
[<a name="footnote-3-1">1</a>] : As it is not feasibly reachable with current or forseen hardware within a reasonable amount of time (1 element per nanosecond would take 292 years) to fulfill a demand of 2^63-1, it is allowed for a `Publisher` to stop tracking demand beyond this point. @reactive-streams/contributors What do you think about this? The implications on the spec would be to not have to emit onError on overflow of |
Yes please. Your rationale is better than mine! |
AFAICS this does not place extra burden on the Publisher and does not hurt error reporting in practice: if we overflow due to a flawed Subscriber than that would mean requestion A LOT of elements already, i.e. 1000000 outstanding demand would already be “buggy”. So: LGTM |
If the Subscriber reports more demand erroneously than it can handle, then it will fail anyway. If the Subscriber can handle arbitrary amount of elements (for example synchronous), then it again does not matter. So yes, +1 to the proposal. |
We should fix this before 1.0 in order to minimize confusion later (since changing this will break compatibility). I’ll open a PR shortly to inch forward in this direction. |
fixes #196 Also terminate spec rule sentences with a full stop where missing.
fixes #196 Also terminate spec rule sentences with a full stop where missing.
The part of rule 3.17 saying...
"If demand becomes higher than 2^63-1 then the Publisher MUST signal an onError with java.lang.IllegalStateException on the given Subscriber."
... is not clear about whether it is OK to always saturate at Long.MAX_VALUE, as in the overflow-detection code (assuming feld "demand" holding cumulative unfilled requests):
request(long n) { long prev = demand, d = prev + n; demand = (d < prev) ? Long.MAX_VALUE : d; ...}
I think it ought to be OK (if not striictly required). One reason that implementations ought to do this anyway is that Subscribers should not have to keep track of whether they've already done request(Long.MAX_VALUE) before whenever they'd like to do it.
The text was updated successfully, but these errors were encountered: