-
Notifications
You must be signed in to change notification settings - Fork 52
Be truly immediate/non-blocking more often #565
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
Changes from 5 commits
0d77dbc
3821e02
b61b46e
ce094d7
ccc8048
1744145
ed81635
d214ca9
d4e4107
f4dc19d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,8 +22,6 @@ | |
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.concurrent.Callable; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.TimeoutException; | ||
|
|
||
| import javax.annotation.Nullable; | ||
|
|
||
|
|
@@ -41,8 +39,9 @@ | |
| import org.apache.brooklyn.util.collections.MutableMap; | ||
| import org.apache.brooklyn.util.core.config.ConfigBag; | ||
| import org.apache.brooklyn.util.core.flags.TypeCoercions; | ||
| import org.apache.brooklyn.util.core.task.ImmediateSupplier.ImmediateUnsupportedException; | ||
| import org.apache.brooklyn.util.core.task.ImmediateSupplier.ImmediateValueNotAvailableException; | ||
| import org.apache.brooklyn.util.core.task.Tasks; | ||
| import org.apache.brooklyn.util.core.task.ValueResolver; | ||
| import org.apache.brooklyn.util.exceptions.Exceptions; | ||
| import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException; | ||
| import org.apache.brooklyn.util.guava.Maybe; | ||
|
|
@@ -53,6 +52,7 @@ | |
|
|
||
| public abstract class AbstractConfigurationSupportInternal implements BrooklynObjectInternal.ConfigurationSupportInternal { | ||
|
|
||
| @SuppressWarnings("unused") | ||
| private static final Logger LOG = LoggerFactory.getLogger(AbstractConfigurationSupportInternal.class); | ||
|
|
||
| @Override | ||
|
|
@@ -77,10 +77,16 @@ public <T> Maybe<T> getNonBlocking(HasConfigKey<T> key) { | |
|
|
||
| @Override | ||
| public <T> Maybe<T> getNonBlocking(final ConfigKey<T> key) { | ||
| if (key instanceof StructuredConfigKey || key instanceof SubElementConfigKey) { | ||
| return getNonBlockingResolvingStructuredKey(key); | ||
| } else { | ||
| return getNonBlockingResolvingSimple(key); | ||
| try { | ||
| if (key instanceof StructuredConfigKey || key instanceof SubElementConfigKey) { | ||
| return getNonBlockingResolvingStructuredKey(key); | ||
| } else { | ||
| return getNonBlockingResolvingSimple(key); | ||
| } | ||
| } catch (ImmediateValueNotAvailableException e) { | ||
| return Maybe.absent(e); | ||
| } catch (ImmediateUnsupportedException e) { | ||
| return Maybe.absent(e); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -89,12 +95,6 @@ public <T> Maybe<T> getNonBlocking(final ConfigKey<T> key) { | |
| * execute the custom logic, as is done by {@link #get(ConfigKey)}, but non-blocking! | ||
| */ | ||
| protected <T> Maybe<T> getNonBlockingResolvingStructuredKey(final ConfigKey<T> key) { | ||
| // TODO This is a poor implementation. We risk timing out when it's just doing its | ||
| // normal work (e.g. because job's thread was starved), rather than when it's truly | ||
| // blocked. Really we'd need to dig into the implementation of get(key), so that the | ||
| // underlying work can be configured with a timeout, for when it finally calls | ||
| // ValueResolver. | ||
|
|
||
| Callable<T> job = new Callable<T>() { | ||
| @Override | ||
| public T call() { | ||
|
|
@@ -106,22 +106,15 @@ public T call() { | |
| } | ||
| }; | ||
|
|
||
| Task<T> t = getContext().submit(Tasks.<T>builder().body(job) | ||
| Task<T> t = Tasks.<T>builder().body(job) | ||
| .displayName("Resolving dependent value") | ||
| .description("Resolving "+key.getName()) | ||
| .tag(BrooklynTaskTags.TRANSIENT_TASK_TAG) | ||
| .build()); | ||
| .build(); | ||
| try { | ||
| T result = t.get(ValueResolver.NON_BLOCKING_WAIT); | ||
| return Maybe.of(result); | ||
| } catch (TimeoutException e) { | ||
| t.cancel(true); | ||
| return Maybe.<T>absent(); | ||
| } catch (ExecutionException e) { | ||
| LOG.debug("Problem resolving "+key.getName()+", returning <absent>", e); | ||
| return Maybe.<T>absent(); | ||
| } catch (InterruptedException e) { | ||
| throw Exceptions.propagate(e); | ||
| return getContext().getImmediately(t); | ||
| } catch (ImmediateUnsupportedException e) { | ||
| return Maybe.absent(); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -139,17 +132,19 @@ protected <T> Maybe<T> getNonBlockingResolvingSimple(ConfigKey<T> key) { | |
| // or Absent if the config key was unset. | ||
| Object unresolved = getRaw(key).or(key.getDefaultValue()); | ||
| final Object marker = new Object(); | ||
| // Give tasks a short grace period to resolve. | ||
| Object resolved = Tasks.resolving(unresolved) | ||
| Maybe<Object> resolved = Tasks.resolving(unresolved) | ||
| .as(Object.class) | ||
| .defaultValue(marker) | ||
| .immediately(true) | ||
| .deep(true) | ||
| .context(getContext()) | ||
| .get(); | ||
| return (resolved != marker) | ||
| ? TypeCoercions.tryCoerce(resolved, key.getTypeToken()) | ||
| : Maybe.<T>absent(); | ||
| .getMaybe(); | ||
| if (resolved.isAbsent()) return Maybe.Absent.<T>castAbsent(resolved); | ||
| if (resolved.get()==marker) { | ||
| // TODO changed Feb 2017, previously returned absent, in contrast to what the javadoc says | ||
| return Maybe.of((T)null); | ||
| } | ||
| return TypeCoercions.tryCoerce(resolved.get(), key.getTypeToken()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that there's no marker object you can rely on
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could, but not 100% sure. There may be some corner cases and some lossiness between |
||
| } | ||
|
|
||
| @Override | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this code will ever be called. The
.defaultValue(marker)only affects the behaviour of.get(). It doesn't affect the result of.getMaybe(), so we'll never have the marker object returned (now that you've changed it to usegetMaybe()).I'm fine with us leaving this in for your PR, but I'd be interested what situation you're trying to cover with this. I tried writing a few more tests but could never get into this code path.
My understanding of what it was doing previously... By setting the
defaultValue(marker)and callingget(), it was trying to avoid the exception being thrown whengetMaybe()would have return an absent (so instead it returned us the marker). That would seem to agree with the javadoc (which javadoc are you referring to?).However, I agree that your change to call
getMaybe()instead is much nicer - we get to keep the originalMaybe.absent()value has the better explanation of why it's absent.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think you are correct here. I've removed the use of
markeraltogether.