Skip to content
This repository was archived by the owner on Oct 16, 2022. It is now read-only.

Conversation

@gabrielgerhardsson
Copy link
Contributor

RecursionSafeAsyncCaller will try to run the call in the current thread as much as possible, while keeping track of recursion to avoid StackOverflowException in the thread. If recursion becomes too deep, the next call is deferred to a separate thread (normal thread pool). State is kept per-thread - stack overflow will be avoided for any thread that passes this code. It is vital to choose a suitable maximum recursion depth.

I should have split out the comment commit to a separate pull request I guess. Will do that next time.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.56% when pulling 61707f4 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

} else {
// Case B: Defer to a separate thread
// This happens when recursion depth of the current thread is larger than limit, to
// avoid stack overflow.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: prefer block comments for multiline comments.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.56% when pulling f0dae5d on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.56% when pulling b8c0a70 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@Override
public void execute(final Runnable runnable) {
// Use thread local counter for recursionDepth
Integer recursionDepth = recursionDepthPerThread.get();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make final. You can avoid incrementing the local variable with:

final Integer recursionDepth = recursionDepthPerThread.get();
recursionDepthPerThread.set(recursionDepth + 1);

/*  */

recursionDepthPerThread.set(recursionDepth);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have fixed


private StackTraceElement[] stack = new StackTraceElement[0];

@SuppressWarnings("unchecked")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid this with:

@RunWith(MockitoJUnitRunner.class)
public class RecursionSafeAsyncCallerTest {
    @Mock
    public FutureDone<Object> done;
    /*  */
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have fixed


@Override
public <T> void resolve(final FutureDone<T> handle, final T result) {
execute(new Runnable() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Target version is 1.8, prefer lambdas:

execute(() -> caller.resolve(handle, result));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've fixed

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 3062f1f on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@udoprog
Copy link
Owner

udoprog commented Nov 7, 2016

Need a way to activate the stack guard, my suggestion would be to add a an option to TinyAsyncBuilder
and make use of it somewhere around here:
https://github.com/udoprog/tiny-async-java/blob/master/tiny-async-core/src/main/java/eu/toolchain/async/TinyAsyncBuilder.java#L111

Also remember to squash your commits.

After that, this looks good to me.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 9f41ea9 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@gabrielgerhardsson
Copy link
Contributor Author

Thank you @udoprog. A couple of thoughts below.

Activation: After considering this a bit, I'm proposing that both the current caller and threadedCaller each gets an optional recursion guard instance in front of them. In my opinion it's valuable for both. The normal operation of both callers will remain in the default case, until heavy recursion is detected at which time the stack will be protected by deferring a recursive call. What do you think?

Squashing commits: I've done this now. Looks good?

@gabrielgerhardsson
Copy link
Contributor Author

Commited a suggestion for how to activate the stack guard.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 11e6fb3 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 931bd54 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 6a852ec on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling d9c6df8 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

RecursionSafeAsyncCaller will try to run the call in the current thread as much as possible, while keeping track of recursion to avoid StackOverflowError. If recursion becomes too deep, the next call is deferred to a separate thread (ExecutorService thread pool).
State is kept per-thread - will be tracked for any thread that passes this code.
It is important to choose a suitable maximum recursion depth.
Add option to TinyAsyncBuilder to make use of RecursionSafeAsyncCaller in front of both the non-threaded caller and threadedCaller
@coveralls
Copy link

Coverage Status

Coverage increased (+0.7%) to 78.47% when pulling 0cbff23 on gabrielgerhardsson:master into fa3e8d1 on udoprog:master.

@udoprog udoprog merged commit 7b9f17d into udoprog:master Nov 9, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants