mbien commented on code in PR #6514:
URL: https://github.com/apache/netbeans/pull/6514#discussion_r1346903220


##########
java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java:
##########
@@ -559,29 +587,123 @@ void stopHardReferencingMavenPoject() {
         return newproject;
     }
 
+    /**
+     * Task that potential project reloads should wait on. If set, a {@link 
fireProjectReload}(true) will be scheduled only after this blocker finishes.
+     */
+    private RequestProcessor.Task reloadBlocker;
 
-
+    /**
+     * Schedules project operation that delays potential reloads. If a reload 
is posted, it will be performed only after
+     * this operation compeltes (successfully, or erroneously). Multiple 
project operations can be scheduled, an eventual project reload
+     * should happen after all those operations complete. It is possible to 
postpone project reload indefinitely, avoid unnecessary
+     * operation schedules.
+     * 
+     * @param r operation to run
+     * @return controlling task.
+     */
+    public RequestProcessor.Task 
scheduleProjectOperation(RequestProcessor.Task t) {
+        if (Boolean.getBoolean("test.reload.sync")) {
+            LOG.log(Level.FINE, "Running the blocking task synchronously 
(test.reload.sync set)");
+            t.run();
+            return t;
+        } else {
+            synchronized (this) {
+                if (reloadBlocker == null) {
+                    LOG.log(Level.FINER, "Blocking project reload on task 
{0}", t);
+                    reloadBlocker = t;
+                    return t;
+                } else {

Review Comment:
   this looks a bit dangerous, the task is already running when passed into 
this method, which means that there is a point in time when the task is active 
without being marked as blocker.
   ```
   
((NbMavenProjectImpl)this.nbproject).scheduleProjectOperation(MavenModelProblemsProvider.RP.post(toRet));
   ```
   Should this method have a RP param and actually schedule the tasks _inside_ 
the method? (+ throw exception when the task is already running).



##########
java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java:
##########
@@ -559,29 +587,123 @@ void stopHardReferencingMavenPoject() {
         return newproject;
     }
 
+    /**
+     * Task that potential project reloads should wait on. If set, a {@link 
fireProjectReload}(true) will be scheduled only after this blocker finishes.
+     */
+    private RequestProcessor.Task reloadBlocker;
 
-
+    /**
+     * Schedules project operation that delays potential reloads. If a reload 
is posted, it will be performed only after
+     * this operation compeltes (successfully, or erroneously). Multiple 
project operations can be scheduled, an eventual project reload
+     * should happen after all those operations complete. It is possible to 
postpone project reload indefinitely, avoid unnecessary
+     * operation schedules.
+     * 
+     * @param r operation to run
+     * @return controlling task.
+     */
+    public RequestProcessor.Task 
scheduleProjectOperation(RequestProcessor.Task t) {
+        if (Boolean.getBoolean("test.reload.sync")) {
+            LOG.log(Level.FINE, "Running the blocking task synchronously 
(test.reload.sync set)");
+            t.run();
+            return t;
+        } else {
+            synchronized (this) {
+                if (reloadBlocker == null) {
+                    LOG.log(Level.FINER, "Blocking project reload on task 
{0}", t);
+                    reloadBlocker = t;
+                    return t;
+                } else {
+                    // will chain after existing reload blocker AND the new 
task.
+                    final RequestProcessor.Task t2 = RELOAD_RP.create(() -> 
{});
+                    LOG.log(Level.FINER, "Creating project blocker {0}, chain 
after existing blocker {1}", new Object[] { t2, t });
+                    reloadBlocker.addTaskListener((e) -> {
+                        t.addTaskListener((e2) -> {
+                            synchronized (NbMavenProjectImpl.this) {
+                                if (t2 == reloadBlocker) {
+                                    reloadBlocker = null;
+                                }
+                            }
+                            t2.run();
+                        });
+                    });
+                    reloadBlocker = t2;
+                    return t2;
+                }
+            }
+        }
+    }
+    
     public RequestProcessor.Task fireProjectReload() {
+        return fireProjectReload(false);
+    }
+    
+    /**
+     * Schedules project reload. If `waitForBlockers` is true and {@link 
#scheduleProjectOperation} registered some task(s), project reload
+     * will be postponed until after those task(s) finish. The returned task 
completes after the project reload itself completes (after the potential
+     * delays).
+     * <p>
+     * As a result of project's reload, child projects may be reloaded, but 
the returned task does not wait for children reload to complete.
+     * 
+     * @param waitForBlockers
+     * @return the task that completes after project reloads. 
+     */
+    public RequestProcessor.Task fireProjectReload(boolean waitForBlockers) {
         //#227101 not only AWT and project read/write mutex has to be checked, 
there are some additional more
         //complex scenarios that can lead to deadlock. Just give up and always 
fire changes in separate RP.
         if (Boolean.getBoolean("test.reload.sync")) {
             reloadTask.run();
             //for tests just do sync reload, even though silly, even sillier 
is to attempt to sync the threads..
         } else {
+            RequestProcessor.Task t;
+            synchronized (this) {
+                if (reloadBlocker != null && waitForBlockers) {
+                    // avoid holding the lock while potentially executing the 
listener in-line
+                    t = reloadBlocker;
+                } else {
+                    t = null;
+                }
+            }
+            if (t != null) {
+                final RequestProcessor.Task t2 = RELOAD_RP.create(() -> {});
+                LOG.log(Level.FINER, "Scheduling project reload retry after 
blocker {0} completes, Returning task {1}", new Object[] { t, t2 });
+                t.addTaskListener((e) -> {
+                    synchronized (NbMavenProjectImpl.this) {
+                        if (t == reloadBlocker) {
+                            reloadBlocker = null;
+                        }
+                    }
+                    fireProjectReload(true).addTaskListener((e2) -> {
+                        // mark the t2 task finished.
+                        if (!t2.isFinished()) {
+                            t2.run();
+                        }
+                    });
+                });
+                return t2;
+            }
+            LOG.log(Level.FINER, "Scheduling prject reload {0}, no blocker 
found.", this);
+            LOG.log(Level.FINER, "Stack trace:", new Throwable());

Review Comment:
   potentially worth adding a `if (loggable)` check since stacks are likely not 
populated lazily



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to