This is an automated email from the ASF dual-hosted git repository.
hulee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git
The following commit(s) were added to refs/heads/master by this push:
new 12f11a3 Fix ConcurrentModification exception in Workflow Garbage
Collection (#741)
12f11a3 is described below
commit 12f11a357d4ee8859a408357c57b1cad854ed841
Author: Ali Reza Zamani Zadeh Najari <[email protected]>
AuthorDate: Wed Feb 12 11:44:53 2020 -0800
Fix ConcurrentModification exception in Workflow Garbage Collection (#741)
In workflow Garbage collection, there is possibility that we encounter
ConcurrentMod exception while looping through the workflow contexts.
This commit fixes this issue by adding a try-catch.
---
.../main/java/org/apache/helix/task/TaskUtil.java | 37 ++++++++++++++++------
.../task/TestWorkflowContextWithoutConfig.java | 2 +-
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/helix-core/src/main/java/org/apache/helix/task/TaskUtil.java
b/helix-core/src/main/java/org/apache/helix/task/TaskUtil.java
index 6b36db4..5ae2f07 100644
--- a/helix-core/src/main/java/org/apache/helix/task/TaskUtil.java
+++ b/helix-core/src/main/java/org/apache/helix/task/TaskUtil.java
@@ -1043,23 +1043,40 @@ public class TaskUtil {
* @param dataProvider
* @param manager
*/
- public static void workflowGarbageCollection(WorkflowControllerDataProvider
dataProvider,
+ public static void workflowGarbageCollection(final
WorkflowControllerDataProvider dataProvider,
final HelixManager manager) {
// Garbage collections for conditions where workflow context exists but
config is missing.
- Map<String, ZNRecord> contexts = dataProvider.getContexts();
- HelixDataAccessor accessor = manager.getHelixDataAccessor();
- HelixPropertyStore<ZNRecord> propertyStore =
manager.getHelixPropertyStore();
+ Set<String> existingContexts;
+ /*
+ * Here try-catch is used to avoid concurrent modification exception while
doing deep copy.
+ * Map.keySet() can produce concurrent modification exception.
+ * Reason: If the map is modified while an iteration over the set is in
progress, concurrent
+ * modification exception will be thrown.
+ */
+ try {
+ existingContexts = new HashSet<>(dataProvider.getContexts().keySet());
+ } catch (Exception e) {
+ LOG.warn(
+ "Exception occurred while creating a list of all workflow/job
context names!",
+ e);
+ return;
+ }
+
+ // toBeDeletedWorkflows is a set that contains the name of the workflows
that their contexts
+ // should be deleted.
Set<String> toBeDeletedWorkflows = new HashSet<>();
- for (Map.Entry<String, ZNRecord> entry : contexts.entrySet()) {
- if (entry.getValue() != null
- && entry.getValue().getId().equals(TaskUtil.WORKFLOW_CONTEXT_KW)) {
- if (dataProvider.getWorkflowConfig(entry.getKey()) == null) {
- toBeDeletedWorkflows.add(entry.getKey());
- }
+ for (String entry : existingContexts) {
+ WorkflowConfig cfg = dataProvider.getWorkflowConfig(entry);
+ WorkflowContext ctx = dataProvider.getWorkflowContext(entry);
+ if (ctx != null && ctx.getId().equals(TaskUtil.WORKFLOW_CONTEXT_KW) &&
cfg == null) {
+ toBeDeletedWorkflows.add(entry);
}
}
+ HelixDataAccessor accessor = manager.getHelixDataAccessor();
+ HelixPropertyStore<ZNRecord> propertyStore =
manager.getHelixPropertyStore();
+
for (String workflowName : toBeDeletedWorkflows) {
LOG.warn(String.format(
"WorkflowContext exists for workflow %s. However, Workflow Config is
missing! Deleting the WorkflowConfig and IdealState!!",
diff --git
a/helix-core/src/test/java/org/apache/helix/integration/task/TestWorkflowContextWithoutConfig.java
b/helix-core/src/test/java/org/apache/helix/integration/task/TestWorkflowContextWithoutConfig.java
index b7d6016..d1102e1 100644
---
a/helix-core/src/test/java/org/apache/helix/integration/task/TestWorkflowContextWithoutConfig.java
+++
b/helix-core/src/test/java/org/apache/helix/integration/task/TestWorkflowContextWithoutConfig.java
@@ -170,7 +170,7 @@ public class TestWorkflowContextWithoutConfig extends
TaskTestBase {
Assert.assertTrue(contextDeleted);
}
- Workflow.Builder createSimpleWorkflowBuilder(String workflowName) {
+ private Workflow.Builder createSimpleWorkflowBuilder(String workflowName) {
final long expiryTime = 5000L;
Workflow.Builder builder = new Workflow.Builder(workflowName);