From 361dc79ede2f48586b18cfbbaa0266bc16c058a7 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 22 Dec 2021 19:31:44 +0000 Subject: [PATCH] Fixed bug caused by multiple concurrent builds of the same resource. Several parts of the code request resources to be loaded/built, and these separate threads were tripping over each other and causing build failures. This has been avoided by making sure the resource isn't already building before requesting it. --- .../api/gateway/resource/GatewayResource.java | 4 +++- .../api/resource/ArbitraryResource.java | 23 +++++++++++-------- .../qortal/arbitrary/ArbitraryDataReader.java | 4 ++++ .../arbitrary/ArbitraryDataRenderer.java | 21 +++++++++++++++-- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/qortal/api/gateway/resource/GatewayResource.java b/src/main/java/org/qortal/api/gateway/resource/GatewayResource.java index 61aa1aec..0433ec5b 100644 --- a/src/main/java/org/qortal/api/gateway/resource/GatewayResource.java +++ b/src/main/java/org/qortal/api/gateway/resource/GatewayResource.java @@ -56,7 +56,9 @@ public class GatewayResource { if (build != null && build == true) { ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null); try { - reader.loadSynchronously(false); + if (!reader.isBuilding()) { + reader.loadSynchronously(false); + } } catch (Exception e) { // No need to handle exception, as it will be reflected in the status } diff --git a/src/main/java/org/qortal/api/resource/ArbitraryResource.java b/src/main/java/org/qortal/api/resource/ArbitraryResource.java index 50ee5a68..5825b010 100644 --- a/src/main/java/org/qortal/api/resource/ArbitraryResource.java +++ b/src/main/java/org/qortal/api/resource/ArbitraryResource.java @@ -938,17 +938,18 @@ public class ArbitraryResource { // Loop until we have data while (!Controller.isStopping()) { attempts++; - try { - arbitraryDataReader.loadSynchronously(rebuild); - break; - } catch (MissingDataException e) { - if (attempts > 5) { - // Give up after 5 attempts - throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data unavailable. Please try again later."); + if (!arbitraryDataReader.isBuilding()) { + try { + arbitraryDataReader.loadSynchronously(rebuild); + break; + } catch (MissingDataException e) { + if (attempts > 5) { + // Give up after 5 attempts + throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data unavailable. Please try again later."); + } } - - Thread.sleep(3000L); } + Thread.sleep(3000L); } java.nio.file.Path outputPath = arbitraryDataReader.getFilePath(); @@ -986,7 +987,9 @@ public class ArbitraryResource { if (build != null && build == true) { ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null); try { - reader.loadSynchronously(false); + if (!reader.isBuilding()) { + reader.loadSynchronously(false); + } } catch (Exception e) { // No need to handle exception, as it will be reflected in the status } diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java index c95224ed..69112ae8 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java @@ -107,6 +107,10 @@ public class ArbitraryDataReader { return false; } + public boolean isBuilding() { + return ArbitraryDataBuildManager.getInstance().isInBuildQueue(this.createQueueItem()); + } + private ArbitraryDataBuildQueueItem createQueueItem() { return new ArbitraryDataBuildQueueItem(this.resourceId, this.resourceIdType, this.service, this.identifier); } diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataRenderer.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataRenderer.java index 252833af..bc710fe7 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataRenderer.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataRenderer.java @@ -6,7 +6,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.api.HTMLParser; import org.qortal.arbitrary.ArbitraryDataFile.*; +import org.qortal.arbitrary.exception.MissingDataException; import org.qortal.arbitrary.misc.Service; +import org.qortal.controller.Controller; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -72,8 +74,23 @@ public class ArbitraryDataRenderer { return this.getLoadingResponse(service, resourceId); } - // Otherwise, hang the request until the build completes - arbitraryDataReader.loadSynchronously(false); + // Otherwise, loop until we have data + int attempts = 0; + while (!Controller.isStopping()) { + attempts++; + if (!arbitraryDataReader.isBuilding()) { + try { + arbitraryDataReader.loadSynchronously(false); + break; + } catch (MissingDataException e) { + if (attempts > 5) { + // Give up after 5 attempts + return ArbitraryDataRenderer.getResponse(response, 404, "Data unavailable. Please try again later."); + } + } + } + Thread.sleep(3000L); + } } } catch (Exception e) {