Sequences refactorings and removed unused code (part of #3798)#3693
Sequences refactorings and removed unused code (part of #3798)#3693fjy merged 6 commits intoapache:masterfrom
Conversation
…apache#3563 (more consistent and paranoiac resource handing in Sequences subsystem); Add Sequences.wrap() for DRY in MetricsEmittingQueryRunner, CPUTimeMetricQueryRunner and SpecificSegmentQueryRunner; Catch MissingSegmentsException in SpecificSegmentQueryRunner's yielder.next() method (follow up on apache#3617)
|
Marking Discuss as confusion was evident on the dev sync about what this is actually fixing or improving in practice. @leventov could you please elaborate on whether this is fixing/improving actual observed issues, actual issues that were unobserved, or things that are not known to be actual issues? |
|
….common.guava package; fix apache#3563 (more consistent and paranoiac resource handing in Sequences subsystem); Add Sequences.wrap() for DRY in MetricsEmittingQueryRunner, CPUTimeMetricQueryRunner and SpecificSegmentQueryRunner; Catch MissingSegmentsException in SpecificSegmentQueryRunner's yielder.next() method (follow up on apache#3617)
| { | ||
| if (isDone()) { | ||
| boolean done = isDone(); | ||
| baseYielder.close(); |
There was a problem hiding this comment.
Behavior here is different if baseYielder.close() throws an exception – the runnable will no longer execute. Is that intentional?
There was a problem hiding this comment.
Not executing effect if exception is thrown in close() was aligned with behaviour in accumulate(), where exec.execute(effect) was just called after subSequence.accumulate(), without finally. However it seems reasonable to me to execute effect if exception is thrown in close(). To distinguish between exception thrown in close() and during the processing (before the sequence "is done") I had to use YieldingSequenceBase.
Also this whole thing of not executing the effect if the subsequence is not done is questionable. We use Sequences.withEffect() in two places in production. It seems to me that it makes sense to execute the effect in those places even if the subsequence is not "done" (especially considering that Sequences.limit() makes the sequence never done). What do you think?
There was a problem hiding this comment.
It looks like Sequences.withEffect is only used for populating cache (in CachingClusteredClient and CachingQueryRunner). In that case, I think it's important to avoid populating the cache if the sequence isn't done, since the cache should only contain full result sets.
I'm not sure if there's a good reason that limited sequences have that isDone behavior though. I would think a limited sequence that reaches its limit is "done". But maybe there's something I'm missing.
There was a problem hiding this comment.
there's also a problem with caching whereby serializing for cache is very expensive, but if you allow the cache to be calculated / populated in the background, then things like HLL buffers get recycled too soon. Not sure if such a thing is solvable at this point, but it would be nice if background caching worked right with how query resources are freed.
| if (thrown != null) { | ||
| builder.setDimension(DruidMetrics.STATUS, "failed"); | ||
| } else if (!isDone) { | ||
| builder.setDimension(DruidMetrics.STATUS, "short"); |
There was a problem hiding this comment.
It's sketchy to call builder.setDimension here, after emitter.emit(builder.build(...)) has already been called. This will be going in and editing a hashmap that has already been handed off to the emitter.
| } | ||
| } | ||
| // Use finally block because emitting query time (in `try {}`, above) and the status (in `finally {}`, | ||
| // below) are unrelated and we don't want the latter to be skipped if the former thrown any exception. |
There was a problem hiding this comment.
Part of the Emitter contract is that emitter.emit does not throw unless something is really wrong (like OOME or link error or something). So this shouldn't be a worry.
|
Other than those 3 comments, the rest looks good to me. |
…e throws exception from close()
|
@gianm thanks, addressed comments. |
|
@gianm I want also resolve the question with |
|
ok @leventov. @cheddar do you have insight into this thread: #3693 (comment), & if there's a good reason for why things are the way they are? |
|
Gian, which things specifically? Just reading the description of the PR it
all sounds legit (and I would agree that the yielder closing thing is a
bug). Are there specific things you are concerned about?
…On Wed, Jan 11, 2017 at 7:14 PM Gian Merlino ***@***.***> wrote:
ok @leventov <https://github.com/leventov>. @cheddar
<https://github.com/cheddar> do you have insight into this thread: #3693
(comment)
<#3693 (comment)>, & if
there's a good reason for why things are the way they are?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3693 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AANOyr5STYgjeR-J3ocMVATUQLffPYz1ks5rRZqngaJpZM4Kx7lg>
.
|
|
@cheddar Just wondering if there's a good reason that limited sequences aren't done when they finish, or if that's a bug. It seems like a bug but maybe there's a reason that they behave the way they do. |
|
@gianm I'm not sure why you think it wouldn't be done. I see That said, I also realize you might be talking abotu the Also, all of the "baggage" related stuff I would expect to be done in the |
|
Ahhh, I think I see what's going on. I misunderstood the behavior that exists now. I thought that @leventov was saying that limited sequences don't act as done when they hit their limit. They do and that's good. What does happen is that if you do this: Sequences.limit(
Sequences.withEffect(baseSequence, runnable, exec),
threshold
)Then the "runnable" will not run if the "threshold" is reached before "baseSequence" is exhausted. This is good behavior for what we use withEffect for in production, which is populating the cache. We don't want the cache to populate with an un-exhausted result set. So I think the behavior is fine as-is and just needs to be documented (since it's not obvious what is going on and why). |
|
I think the "fix" to #3849 is to just rename "withEffect" to
"withEffectOnCompletion" or "withEffectOnExhaustion".
Sounds like that is by design (I'll admit, I also find it
counter-intuitive, but if those are the semantics, they are the semantics),
so it's the naming that is making it confusing.
…--Eric
On Fri, Jan 13, 2017 at 2:48 PM Roman Leventov ***@***.***> wrote:
@gianm <https://github.com/gianm> @cheddar <https://github.com/cheddar>
the problem is #3849 <#3849>. I
don't see how it could be easily fixed, so I'm not going to fix this in
this PR. At least, this PR shouldn't make the things worse than they used
to be. So I'm removing [WIP]
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3693 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AANOyrCwvKoXnALxkVDbeBqrPXUjOKzpks5rR_8mgaJpZM4Kx7lg>
.
|
|
Could someone please review this? @cheddar @himanshug @jon-wei |
|
This patch looks good to me. |
|
LGTM, 👍 |
…pache#3693) * Removing unused code from io.druid.java.util.common.guava package; fix apache#3563 (more consistent and paranoiac resource handing in Sequences subsystem); Add Sequences.wrap() for DRY in MetricsEmittingQueryRunner, CPUTimeMetricQueryRunner and SpecificSegmentQueryRunner; Catch MissingSegmentsException in SpecificSegmentQueryRunner's yielder.next() method (follow up on apache#3617) * Make Sequences.withEffect() execute the effect if the wrapped sequence throws exception from close() * Fix strange code in MetricsEmittingQueryRunner * Add comment on why YieldingSequenceBase is used in Sequences.withEffect() * Use Closer in OrderedMergeSequence and MergeSequence to close multiple yielders
This PR includes several related fixes/refactorings around
Sequencessubsystem, in the importance order:Sequences.withBaggage()andSequences.withEffect()to consistently close the baggage and execute the effect after base sequence is closed. Before, it was so inaccumulate()path but was the opposite inYielderpath. This in mentioned in Review resource handling in Sequence/Yielder subsystem #3563.SpecificSegmentQueryRunner, which catchesMissingSegmentsExceptionintoYielder()but doesn't catch exception inYielder.next(). This fix develops the idea of SpecificSegmentQueryRunner misses missing segments from toYielder() #3617. Probably it could never be an issue in practice, because if the segment is missing,MissingSegmentsExceptionshould always be thrown fromtoYielder(). But I'm not sure.Sequences.wrap()which allows to simplify and remove repetitive code fromMetricsEmittingQueryRunner,CPUTimeMetricQueryRunnerandSpecificSegmentQueryRunner.Sequencessubsystemio.druid.java.util.common.guavapackage.Sequencesclass rather than constructing XxxSequence classes directory; reduce visibility of the latter somewhere.