diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java index 049c5f755c..776db1723f 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java @@ -219,7 +219,8 @@ private static final ThreadPoolExecutor makeBinaryStorageExecutor() { * Unfortunately, we have to duplicate the loading logic here in order to make it better extendable. Parent class lacks a factory method for loading and * creating the initial ResourceDescriptionsData. We use an {@link IResourceDescriptionsDataProvider} for that. */ - private volatile boolean isLoaded; // NOPMD; PMD doesn't like "volatile"... + @SuppressWarnings({"PMD.AvoidFieldNameMatchingMethodName", "PMD.AvoidUsingVolatile"}) + private volatile boolean isLoaded; /** * Don't use a PesistedStateProvider, but use a target platform manager that gives us directly an appropriate ResourceDescriptionsData. The point here is that @@ -424,7 +425,8 @@ public synchronized ImmutableList clean(final Set doUpdate(final BuildData buildData, final ResourceDescriptionsData newData, final IProgressMonitor monitor) { // NOPMD + @SuppressWarnings("PMD.AvoidInstanceofChecksInCatchClause") + protected Collection doUpdate(final BuildData buildData, final ResourceDescriptionsData newData, final IProgressMonitor monitor) { final SubMonitor progress = SubMonitor.convert(monitor, 100); // Step 1: Clean the set of deleted URIs. If any of them are also added, they're not deleted. @@ -583,7 +585,7 @@ public boolean isCanceled() { } catch (final Exception ex) { // CHECKSTYLE:CHECK-ON IllegalCatch pollForCancellation(monitor); - if (ex instanceof LoadOperationException) { // NOPMD + if (ex instanceof LoadOperationException) { LoadOperationException loadException = (LoadOperationException) ex; if (loadException.getCause() instanceof TimeoutException) { // Load request timed out, URI of the resource is not available @@ -778,38 +780,88 @@ protected void deleteBinaryResources(final Set toBeDeleted) { /** * Waits until binary models are stored. + * Uses default parameters for timeout and retries, kept for backward compatibility. */ - @SuppressFBWarnings("AT_STALE_THREAD_WRITE_OF_PRIMITIVE") protected void awaitBinaryStorageExecutorTermination() { - LOGGER.info("Waiting for binary resource storage tasks to complete"); //$NON-NLS-1$ + awaitBinaryStorageExecutorTermination(1, TimeUnit.MINUTES, 0); + } + + /** + * Waits until binary models are stored. Waits for a given time and makes a given number of attempts. + * + * @param timeout + * time to wait for shutdown + * @param unit + * {@link TimeUnit} for timeout + * @param retryCount + * number of retries to attempt + */ + @SuppressWarnings("nls") + @SuppressFBWarnings("AT_STALE_THREAD_WRITE_OF_PRIMITIVE") + protected void awaitBinaryStorageExecutorTermination(final int timeout, final TimeUnit unit, final int retryCount) { + LOGGER.info("Waiting for binary resource storage tasks to complete: timeout {} {}, retryCount {}", timeout, unit, retryCount); //$NON-NLS-1$ if (hwmTimeStamp != null) { LOGGER.info("high water mark was {} at {}", binaryStorageHighWaterMark, hwmTimeStamp); //$NON-NLS-1$ } // Stop accepting additional work binaryStorageExecutor.shutdown(); - long queuedTaskCount = binaryStorageExecutor.getQueue().size(); - long activeTaskCount = binaryStorageExecutor.getActiveCount(); - // Attempt to wait for queued work to complete + int retries = 0; + boolean terminated; + boolean stuck = false; + + long prevQueuedTaskCount = binaryStorageExecutor.getQueue().size(); + long prevActiveTaskCount = binaryStorageExecutor.getActiveCount(); + try { - if (!binaryStorageExecutor.awaitTermination(1, TimeUnit.MINUTES)) { - throw new InterruptedException(); + do { + terminated = binaryStorageExecutor.awaitTermination(timeout, unit); + if (!terminated) { + // check whether if there is progress + long currQueuedTaskCount = binaryStorageExecutor.getQueue().size(); + long currActiveTaskCount = binaryStorageExecutor.getActiveCount(); + + if (currQueuedTaskCount < prevQueuedTaskCount || currActiveTaskCount < prevActiveTaskCount) { + LOGGER.warn("Binary resource storage tasks not completed in time, start with {} queued / {} active; now have {} / {}", prevQueuedTaskCount, prevActiveTaskCount, currQueuedTaskCount, currActiveTaskCount); + if (retries < retryCount) { + retries += 1; + LOGGER.warn("retrying shutdown, attempt {} of {}", retries, retryCount); + prevQueuedTaskCount = currQueuedTaskCount; + prevActiveTaskCount = currActiveTaskCount; + } + } else { + LOGGER.warn("Binary resource storage tasks not completed in time, not making progress, stuck on {} / {} queued / active tasks", currQueuedTaskCount, currActiveTaskCount); + stuck = true; + } + } + + } while (!terminated && !stuck && retries < retryCount); + + if (terminated) { + LOGGER.info("Binary resource storage executor completed."); + } else { + LOGGER.warn("Binary resource storage executor shutdown not successful, terminating"); + terminateBinaryStorageExecutor(); } - } catch (InterruptedException e) { // NOPMD ExceptionAsFlowControl - LOGGER.warn(String.format("Binary resource storage tasks not completed in time, start with %d queued / %d active; now have %d / %d", //$NON-NLS-1$ - queuedTaskCount, activeTaskCount, binaryStorageExecutor.getQueue().size(), binaryStorageExecutor.getActiveCount())); - binaryStorageExecutor.shutdownNow(); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted waiting for binaryStorageExecutor shutdown, terminating. Had {} queued / {} active before interrupd; now have {} / {}", prevQueuedTaskCount, prevActiveTaskCount, binaryStorageExecutor.getQueue().size(), binaryStorageExecutor.getActiveCount()); + terminateBinaryStorageExecutor(); } - LOGGER.info("Binary resource storage executor completed."); //$NON-NLS-1$ - // Be ready to accept additional work binaryStorageExecutor = makeBinaryStorageExecutor(); binaryStorageHighWaterMark = 0; hwmTimeStamp = null; } + @SuppressWarnings("nls") + private void terminateBinaryStorageExecutor() { + LOGGER.warn("Terminating binaryStorageExecutor"); + List tasks = binaryStorageExecutor.shutdownNow(); + LOGGER.warn("{} tasks not processed", tasks.size()); + } + /** * Updates the markers on a single resource. * @@ -873,8 +925,8 @@ protected IResourceDescription getSavedResourceDescription(final Map writeResources(final Collection toWrite, final BuildData buildData, final IResourceDescriptions oldState, final CurrentDescriptions newState, final IProgressMonitor monitor) { // NOPMD - // NPath - // Complexity + @SuppressWarnings("PMD.AvoidInstanceofChecksInCatchClause") + private List writeResources(final Collection toWrite, final BuildData buildData, final IResourceDescriptions oldState, final CurrentDescriptions newState, final IProgressMonitor monitor) { + // NPath + // Complexity ResourceSet resourceSet = buildData.getResourceSet(); IProject currentProject = getBuiltProject(buildData); List toBuild = Lists.newLinkedList(); @@ -1029,7 +1082,7 @@ private List writeResources(final Collection toWrite, final BuildData } } catch (final WrappedException ex) { pollForCancellation(monitor); - if (uri == null && ex instanceof LoadOperationException) { // NOPMD + if (uri == null && ex instanceof LoadOperationException) { uri = ((LoadOperationException) ex).getUri(); } LOGGER.error(NLS.bind(Messages.MonitoredClusteringBuilderState_CANNOT_LOAD_RESOURCE, uri != null ? uri : "unknown uri"), ex); //$NON-NLS-1$ diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java index a881e65a27..1ac724dc50 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/ParseTreeUtil.java @@ -138,8 +138,11 @@ public static String getParsedString(final EObject object, final String featureN public static void ensureNodeModelLoaded(final Resource resource) { if (resource instanceof LazyLinkingResource2 lazyLinkinResource && lazyLinkinResource.isLoadedFromStorage()) { EObject root = resource.getContents().get(0); - if (root != null && NodeModelUtils.getNode(root) instanceof ICompositeNode composite) { - composite.getText(); // side-effect on removing com.avaloq.tools.ddk.xtext.resource.persistence.ProxyCompositeNode + if (root != null) { + ICompositeNode rootNode = NodeModelUtils.getNode(root); + if (rootNode != null) { + rootNode.getText(); // side-effect on removing com.avaloq.tools.ddk.xtext.resource.persistence.ProxyCompositeNode + } } } }