Skip to content

Commit

Permalink
[JBPM-10242] Disable linear search on condition
Browse files Browse the repository at this point in the history
Setting org.jbpm.ejb.timer.disable.linear.search and
org.jbpm.ejb.timer.disable.linear.remove to true
  • Loading branch information
fjtirado committed Oct 1, 2024
1 parent d79847f commit 509e6cf
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
Expand Down Expand Up @@ -247,115 +251,86 @@ private Serializable removeTransientFields(Serializable info) {
return info;
}

private boolean performLinearSearch() {
return Boolean.getBoolean("org.jbpm.ejb.timer.linear.search");
private boolean disableLinearSearch(String suffix) {
return Boolean.getBoolean("org.jbpm.ejb.timer.disable.linear." + suffix);
}


public boolean removeJob(JobHandle jobHandle, Timer ejbTimer) {
EjbGlobalJobHandle ejbHandle = (EjbGlobalJobHandle) jobHandle;
if (useLocalCache) {
boolean removedFromCache = localCache.remove(ejbHandle.getUuid()) != null;
logger.debug("Job handle {} is {} removed from cache ", jobHandle, removedFromCache ? "" : "not" );
logger.debug("Job handle {} is {} removed from cache ", jobHandle, removedFromCache ? "" : "not");
}

if (ejbTimer != null) {
try {
ejbTimer.cancel();
return true;
} catch (Exception e) {
logger.warn("Timer cancel error for handle {}", ejbHandle.getUuid(), e);
return false;
}
return cancelTimer(ejbTimer, ejbHandle);
}

// small speed improvement using the ejb serializable info handler
GlobalJpaTimerJobInstance timerJobInstance = (GlobalJpaTimerJobInstance) ejbHandle.getTimerJobInstance();
if (timerJobInstance != null) {
Object ejbTimerHandle = timerJobInstance.getTimerInfo();
if(ejbTimerHandle instanceof TimerHandle) {
try {
((TimerHandle) ejbTimerHandle).getTimer().cancel();
} catch (Throwable e) {
logger.warn("Timer cancel error for handle {}", ejbTimerHandle, e);
return false;
}
return true;
} else {
logger.warn("No TimerHandle found for {}: {}", ejbHandle, ejbTimerHandle);
Object ejbTimerHandle = timerJobInstance.getTimerInfo();
if (ejbTimerHandle instanceof TimerHandle) {
return cancelTimer(((TimerHandle) ejbTimerHandle).getTimer(), ejbHandle);
}
} else {
logger.warn("No timerJobInstance available for {}", ejbHandle);
}
logger.debug("No valid TimerJob instance {} available for Job handle {}", timerJobInstance, ejbHandle);
return linearSearch("remove", ejbHandle.getUuid(),
(timer, job) -> cancelTimer(timer, (EjbGlobalJobHandle) job.getJobHandle())).orElse(false);
}

if (performLinearSearch()) {
for (Timer timer : timerService.getTimers()) {
try {
Serializable info = timer.getInfo();
if (info instanceof EjbTimerJob) {
EjbTimerJob job = (EjbTimerJob) info;

EjbGlobalJobHandle handle = (EjbGlobalJobHandle) job.getTimerJobInstance().getJobHandle();
if (handle.getUuid().equals(ejbHandle.getUuid())) {
logger.info("Job handle {} does match timer and is going to be canceled", jobHandle);

try {
timer.cancel();
} catch (Throwable e) {
logger.warn("Timer cancel error for handle {}", handle, e);
return false;
}
return true;
}
}
} catch (NoSuchObjectLocalException e) {
logger.debug("Timer {} has already expired or was canceled ", timer);
}
public TimerJobInstance getTimerByName(String jobName) {
if (useLocalCache) {
TimerJobInstance found = localCache.get(jobName);
if (found != null) {
logger.debug("{} found in cache", jobName);
return found;
}
logger.info("Job handle {} does not match any timer on {} scheduler service", jobHandle, this);
return false;
} else {
logger.warn("Skipping linear search to delete uuid {}", ejbHandle.getUuid());
return false;
logger.debug("{} not found in cache", jobName);
}
}

return linearSearch("search", jobName, (timer, job) -> {
if (useLocalCache) {
localCache.putIfAbsent(jobName, job);
}
return job;
}).orElse(null);
}

private boolean cancelTimer(Timer timer, EjbGlobalJobHandle ejbHandle) {
try {
timer.cancel();
return true;
} catch (Exception ex) {
logger.warn("Cancelling timer failed for handle {}", ejbHandle, ex);
return false;
}
}

public TimerJobInstance getTimerByName(String jobName) {
if (useLocalCache) {
if (localCache.containsKey(jobName)) {
logger.debug("Found job {} in cache returning", jobName);
return localCache.get(jobName);
}
}
TimerJobInstance found = null;
if (performLinearSearch()) {
private <T> Optional<T> linearSearch(String suffix, String uuid, BiFunction<Timer, TimerJobInstance, T> function) {
if (disableLinearSearch(suffix)) {
logger.warn("Skipping linear search to {} UUID {}", suffix, uuid);
} else {
logger.info("Searching UUID {} on {} scheduler service", uuid, this);
for (Timer timer : timerService.getTimers()) {
try {
Serializable info = timer.getInfo();
if (info instanceof EjbTimerJob) {
EjbTimerJob job = (EjbTimerJob) info;

EjbGlobalJobHandle handle = (EjbGlobalJobHandle) job.getTimerJobInstance().getJobHandle();

if (handle.getUuid().equals(jobName)) {
found = handle.getTimerJobInstance();
if (useLocalCache) {
localCache.putIfAbsent(jobName, found);
}
logger.debug("Job {} does match timer and is going to be returned {}", jobName, found);
break;
if (handle.getUuid().equals(uuid)) {
logger.debug("UIID {} does match timer {} and handle {}", uuid, timer,
job.getTimerJobInstance());
return Optional.of(function.apply(timer, job.getTimerJobInstance()));
}
}
} catch (NoSuchObjectLocalException e) {
logger.debug("Timer info for {} was not found ", timer);
logger.info("Info for timer {} is not there ", timer, e);
}
}
} else {
logger.warn("Skipping linear search to find uuid {}", jobName);
logger.info("UUID {} does not match any timer on {} scheduler service", uuid, this);
}
return found;
return Optional.empty();
}

public void evictCache(JobHandle jobHandle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import org.drools.core.time.impl.TimerJobInstance;
import org.jbpm.persistence.timer.GlobalJpaTimerJobInstance;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

Expand All @@ -42,8 +41,6 @@ public class EJBTimerSchedulerTest {

@Before
public void setup() {

System.setProperty("org.jbpm.ejb.timer.linear.search", "true");
TimerService timerService = mock(TimerService.class);
when(timerService.getTimers()).thenReturn(timers);

Expand All @@ -61,11 +58,6 @@ public void setup() {
scheduler.timerService = timerService;
}

@After
public void cleanup() {
System.clearProperty("org.jbpm.ejb.timer.linear.search");
}

@Test
public void testEjbTimerSchedulerTestOnTimerLoop() {
// first call to go over list of timers should not add anything to the cache as there is no matching timers
Expand Down

0 comments on commit 509e6cf

Please sign in to comment.