-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
WFLY-12321 #12449
WFLY-12321 #12449
Conversation
...jb/infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/InfinispanBeanManager.java
Outdated
Show resolved
Hide resolved
clustering/api/src/main/java/org/wildfly/clustering/dispatcher/CommandDispatcher.java
Outdated
Show resolved
Hide resolved
.../infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/BeanExpirationScheduler.java
Outdated
Show resolved
Hide resolved
.../infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/BeanExpirationScheduler.java
Outdated
Show resolved
Hide resolved
return; | ||
} | ||
task = expireTask; | ||
expireTask = null; |
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.
Should we be concerned that the expireTask can be reset after this synchronized block completes? Whose cancels the Future in that case?
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 agree, I fixed that by checking if expireTask is different from null at the end of the file, before trying to reschedule it and reset the field.
...jb/infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/InfinispanBeanManager.java
Show resolved
Hide resolved
...jb/infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/InfinispanBeanManager.java
Outdated
Show resolved
Hide resolved
ejb3/src/main/java/org/jboss/as/ejb3/cache/simple/SimpleCache.java
Outdated
Show resolved
Hide resolved
@pferraro I've updated the PR with all your feedback. Also, I removed the commit for "At LocalCommandDispatcher for clustering, executeOnMember should check if this node is equal to member, and not if it is equal to itself". I was thinking it shoudl have its own Jira, dont you agree? Or do you prefer to have the commit at this PR as it was before? |
Agreed. I merged it last week. |
4e2b959
to
605d0b3
Compare
...rc/test/java/org/jboss/as/test/clustering/cluster/dispatcher/bean/CommandDispatcherBean.java
Outdated
Show resolved
Hide resolved
clustering/ejb/infinispan/src/main/java/org/wildfly/clustering/ejb/infinispan/Scheduler.java
Show resolved
Hide resolved
* the near future. | ||
* @author Flavia Rainone | ||
*/ | ||
public class PrepareReeschedulingSchedulerCommand<I> implements Command<Void, Scheduler<I>> { |
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.
Spelling fix: PrepareReschedulingSchedulerCommand :)
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.
Ooops, thanks :-)
With the latest changes |
Retest this please |
private void cancel(Bean<I, T> bean) { | ||
if (this.dispatcher != null) { | ||
final Node node = locatePrimaryOwner(bean.getId()); |
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.
Remove this line.
@@ -219,8 +218,28 @@ public Affinity getWeakAffinity(I id) { | |||
return Affinity.NONE; | |||
} | |||
|
|||
private void prepareRescheduling(Bean<I, T> bean) { | |||
if (this.dispatcher != null) { | |||
final Node node = locatePrimaryOwner(bean.getId()); |
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.
Remove this line.
} | ||
|
||
@Override | ||
public void cancel(Locality locality) { | ||
for (I id: this.expirationFutures.keySet()) { | ||
for (I id: expirationTracker.getTrackedIds()) { |
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.
Iterating over this set will be prone to ConcurrentModificationExceptions.
} | ||
|
||
@Override | ||
public void cancel(Locality locality) { | ||
for (I id: this.evictionFutures.keySet()) { | ||
for (I id: this.expirationTracker.getTrackedIds()) { |
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.
Iterating over this set will be prone to ConcurrentModificationExceptions.
firstExpiration != lastExpiration) { | ||
firstExpiration = firstExpiration.nextExpiration; | ||
} | ||
expiration.previousExpiration = null; |
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.
the nextExpriation must also me cleared, or an endless loop can result
firstExpiration = lastExpiration = expiration; | ||
} else if (lastExpiration != expiration) { | ||
// if the last expiration to occur is not current node, add it to the | ||
// last of the expiration list |
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.
This logic makes the assumption that the newly tracked bean will be the last to expire. While this is true when scheduling a bean for expiration at the end of an invocation, this is generally not the case when a member takes on the responsibility for expiring a given bean, i.e. when triggered from InfinispanBeanManager.schedule(Locality oldLocality, Locality newLocality).
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.
Oh, I see. I'll try to think on a solution and I'll assert the perf gains with the benchmark to make sure this PR is really needed.
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.
One solution is to replace the expiration tracker with a collection, e.g. io.undertow.util.ConcurrentDirectDeque. We can then construct the scheduler with a queue implementation appropriate for the use case. In the clustered case, where the assumption above is violated, we could use a priority queue, where elements are inserted according to their next expiration, rather then just appending to the end. Insertions/removals would be slower, i.e. log(N) instead of constant time, but that way we can still optimize for the local case.
@pferraro this commit is ready for review |
Retest this please |
Retest this please |
0f4a9a8
to
1178575
Compare
Retest this please |
try { | ||
this.executeOnPrimaryOwner(id, new PrepareReschedulingSchedulerCommand<>(id)); | ||
} catch (Exception e) { | ||
InfinispanEjbLogger.ROOT_LOGGER.failedToCancelBean(e, id); |
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.
@pferraro I didn t think it was worthy to add a new logging message for something that will be later removed. If you prefer to have a logging message created for this, let me know.
public void evict(I id) { | ||
try { | ||
// Cache eviction is a local operation, so we need to broadcast this to the cluster | ||
this.dispatcher.executeOnGroup(new EvictCommand<>(id)); |
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.
Given that this is now a local-only scheduler, there is no need to dispatch an eviction command.
@bstansberry This is a performance optimization for local SFSBs. Not essential for WF18, but still desirable. |
this.executor = executor; | ||
this.idleTimeout = idleTimeout; | ||
this.expirationTracker = new ExpirationTracker<>(idleTimeout); | ||
this.dispatcher = dispatcherFactory.createCommandDispatcher(dispatcherName + "/eviction", evictor); |
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.
This scheduler no longer has any need to create a CommandDispatcher, no?
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.
done
// do nothing, this is a local-only scheduler | ||
} | ||
|
||
static class EvictCommand<I> implements Command<Void, BeanGroupEvictor<I>> { |
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 class is referenced any longer.
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.
done
|
||
@Override | ||
public void evict(I id) { | ||
// do nothing, this is a local-only scheduler |
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.
This method needs to evict the bean, i.e. this.evictor.evict(id);
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.
done
…a single task for eviction and another for bean expiration and never cancel that task; instead, update the expiration of the bean so it can be checked by the task if the bean has actually expired
@pferraro all requested changes are done |
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.
Thanks Flavia. I think this is ready now.
Do not merge yet
Jira: https://issues.jboss.org/browse/WFLY-12321
This PR has to incorporate a few more feedbacks and will most likely be broken into more PRs and Jiras.
EAP Jira (temporary): https://issues.jboss.org/browse/JBEAP-17049