Skip to content

Commit

Permalink
Use future and do not block if reloading.
Browse files Browse the repository at this point in the history
  • Loading branch information
sdedic committed Dec 12, 2023
1 parent e6900cf commit a200e00
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.util.Properties;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -472,13 +473,17 @@ public MavenProject getOriginalMavenProjectOrNull() {
* the method blocks until the project reload eventually finishes in the reload thread / RP.
* @return possibly reloaded Maven project.
*/
public MavenProject getFreshOriginalMavenProject() {
public CompletableFuture<MavenProject> getFreshOriginalMavenProject() {
if (reloadTask.isFinished()) {
return getOriginalMavenProject();
return CompletableFuture.completedFuture(getOriginalMavenProject());
} else {
LOG.log(Level.FINE, "Asked for project {0} being updated, waiting for the refresh to complete.", projectFile);
reloadTask.waitFinished();
return getOriginalMavenProject();
CompletableFuture<MavenProject> f = new CompletableFuture<>();
reloadTask.addTaskListener((e) -> {
LOG.log(Level.FINE, "Project {0} update done.", projectFile);
f.complete(getOriginalMavenProject());
});
return f;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -162,7 +163,7 @@ Collection<? extends ProjectProblem> doGetProblems(boolean sync) {
* @param sync if the call should complete synchronously
*/
private Pair<Collection<ProjectProblem>, Boolean> doGetProblems1(boolean sync) {
final MavenProject updatedPrj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
final CompletableFuture<MavenProject> pending = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
Callable<Pair<Collection<ProjectProblem>, Boolean>> c;

synchronized (this) {
Expand All @@ -176,25 +177,50 @@ private Pair<Collection<ProjectProblem>, Boolean> doGetProblems1(boolean sync) {

}
MavenProject o = analysedProject.get();
LOG.log(Level.FINER, "Called getProblems for {0}, analysed = {1}, current = {2}",
new Object[] { project, o == null ? 0 : System.identityHashCode(o), System.identityHashCode(updatedPrj) });
//for non changed project models, no need to recalculate, always return the cached value
Object wasprocessed = updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
if (o == updatedPrj && wasprocessed != null) {
Pair<Collection<ProjectProblem>, Boolean> cached = problemsCache;
LOG.log(Level.FINER, "getProblems: Project was processed, cached is: {0}", cached);
if (cached != null) {
return cached;
if (pending.isDone()) {
try {
// cannot block, if .isDone().
MavenProject updatedPrj = pending.get();
LOG.log(Level.FINER, "Called getProblems for {0}, analysed = {1}, current = {2}",
new Object[] { project, o == null ? 0 : System.identityHashCode(o), System.identityHashCode(updatedPrj) });
Object wasprocessed = updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
if (o == updatedPrj && wasprocessed != null) {
Pair<Collection<ProjectProblem>, Boolean> cached = problemsCache;
LOG.log(Level.FINER, "getProblems: Project was processed, cached is: {0}", cached);
if (cached != null) {
return cached;
}
}
} catch (ExecutionException | InterruptedException ex) {
LOG.log(Level.FINER, "Project load for {0} threw exception {1}", new Object[] { project, ex.getMessage() });
LOG.log(Level.FINER, "Stacktrace:", ex);
}
}
} else {
LOG.log(Level.FINER, "Called getProblems for {0}, analysed = {1}, current = PENDING",
new Object[] { project, o == null ? 0 : System.identityHashCode(o) });
}

SanityBuildAction sba = cachedSanityBuild.get();
if (sba != null && sba.getPendingResult() == null) {
cachedSanityBuild.clear();
}

// PENDING: think if .thenApplyAsync would be more useful.
c = () -> {
// double check, the project may be invalidated during the time.
MavenProject prj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
MavenProject prj;

try {
prj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject().get();
LOG.log(Level.FINER, "Evaluating getProblems for {0}, analysed = {1}, current = {2}",
new Object[] { project, o == null ? 0 : System.identityHashCode(o), System.identityHashCode(prj) });
} catch (ExecutionException | InterruptedException ex) {
// should not happen
LOG.log(Level.FINER, "Project load for {0} threw exception {1}", new Object[] { project, ex.getMessage() });
LOG.log(Level.FINER, "Stacktrace:", ex);
return Pair.of( new ArrayList<>(), sanityBuildStatus);
}
Object wasprocessed2 = prj.getContextValue(MavenModelProblemsProvider.class.getName());
synchronized (MavenModelProblemsProvider.this) {
if (wasprocessed2 != null) {
Expand Down Expand Up @@ -244,7 +270,14 @@ private Pair<Collection<ProjectProblem>, Boolean> doGetProblems1(boolean sync) {
new Object[] { round, prj });
// force reload, then wait for the reload to complete
NbMavenProject.fireMavenProjectReload(project);
prj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
try {
prj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject().get();
} catch (ExecutionException | InterruptedException ex2) {
// should not happen
LOG.log(Level.FINER, "Project load for {0} threw exception {1}", new Object[] { project, ex2.getMessage() });
LOG.log(Level.FINER, "Stacktrace:", ex2);
break;
}
}
}
if (prj != null && !sanityBuildStatus) {
Expand Down

0 comments on commit a200e00

Please sign in to comment.