-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DROOLS-7589] ansible-rulebook : Throw Exception when heap reaches to… (
#90) * [DROOLS-7589] ansible-rulebook : Throw Exception when heap reaches to threshold * - check memory every N events to avoid performance overhead * More efficient counter to check memory occupation * fix compilation * wip --------- Co-authored-by: Mario Fusco <[email protected]>
- Loading branch information
1 parent
ab5e067
commit e3a6c73
Showing
9 changed files
with
236 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
.../main/java/org/drools/ansible/rulebook/integration/api/rulesengine/MemoryMonitorUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package org.drools.ansible.rulebook.integration.api.rulesengine; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class MemoryMonitorUtil { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(MemoryMonitorUtil.class.getName()); | ||
|
||
public static final String MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD_PROPERTY = "drools.memory.occupation.percentage.threshold"; | ||
private static final int DEFAULT_MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD = 90; | ||
private static final int MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD; | ||
|
||
// check memory per configured number of events are consumed | ||
public static final String MEMORY_CHECK_EVENT_COUNT_THRESHOLD_PROPERTY = "drools.memory.check.event.count.threshold"; | ||
private static final int DEFAULT_MEMORY_CHECK_EVENT_COUNT_THRESHOLD = 64; | ||
private static final int MEMORY_CHECK_EVENT_COUNT_MASK; | ||
private static int COUNTER = 0; | ||
|
||
static { | ||
String memoryThresholdEnvValue = System.getenv("DROOLS_MEMORY_THRESHOLD"); | ||
if (memoryThresholdEnvValue != null && !memoryThresholdEnvValue.isEmpty()) { | ||
// Environment variable takes precedence over system property | ||
System.setProperty(MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD_PROPERTY, memoryThresholdEnvValue); | ||
} | ||
MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD = Integer.getInteger(MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD_PROPERTY, DEFAULT_MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD); // percentage | ||
LOG.info("Memory occupation threshold set to {}%", MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD); | ||
|
||
String eventCountThresholdEnvValue = System.getenv("DROOLS_MEMORY_CHECK_EVENT_COUNT_THRESHOLD"); | ||
if (eventCountThresholdEnvValue != null && !eventCountThresholdEnvValue.isEmpty()) { | ||
// Environment variable takes precedence over system property | ||
System.setProperty(MEMORY_CHECK_EVENT_COUNT_THRESHOLD_PROPERTY, eventCountThresholdEnvValue); | ||
} | ||
|
||
int eventCountThreshold = Integer.getInteger(MEMORY_CHECK_EVENT_COUNT_THRESHOLD_PROPERTY, DEFAULT_MEMORY_CHECK_EVENT_COUNT_THRESHOLD); // number of events | ||
MEMORY_CHECK_EVENT_COUNT_MASK = roundToPowerOfTwo(eventCountThreshold) - 1; | ||
LOG.info("Memory check event count threshold set to {}", MEMORY_CHECK_EVENT_COUNT_MASK); | ||
} | ||
|
||
private MemoryMonitorUtil() { | ||
// do not instantiate | ||
} | ||
|
||
public static void checkMemoryOccupation() { | ||
if ((COUNTER++ & MEMORY_CHECK_EVENT_COUNT_MASK) == 0) { | ||
// check memory occupation only once in 64 calls | ||
return; | ||
} | ||
int memoryOccupationPercentage = getMemoryOccupationPercentage(); | ||
if (memoryOccupationPercentage > MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD) { | ||
// give GC a chance to free some memory | ||
System.gc(); // NOSONAR | ||
memoryOccupationPercentage = getMemoryOccupationPercentage(); | ||
if (memoryOccupationPercentage > MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD) { | ||
LOG.error("Memory occupation is above the threshold: {}% > {}%. MaxMemory = {}, UsedMemory = {}", | ||
memoryOccupationPercentage, MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD, Runtime.getRuntime().maxMemory(), Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); | ||
throw new MemoryThresholdReachedException(MEMORY_OCCUPATION_PERCENTAGE_THRESHOLD, memoryOccupationPercentage); | ||
} | ||
} | ||
} | ||
|
||
private static int getMemoryOccupationPercentage() { | ||
return (int) ((100 * (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())) / Runtime.getRuntime().maxMemory()); | ||
} | ||
|
||
private static int roundToPowerOfTwo(final int value) { | ||
if (value > Integer.MAX_VALUE) { | ||
throw new IllegalArgumentException("There is no larger power of 2 int for value:" + value + " since it exceeds 2^31."); | ||
} | ||
if (value < 0) { | ||
throw new IllegalArgumentException("Given value:" + value + ". Expecting value >= 0."); | ||
} | ||
return 1 << (32 - Integer.numberOfLeadingZeros(value - 1)); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
.../drools/ansible/rulebook/integration/api/rulesengine/MemoryThresholdReachedException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package org.drools.ansible.rulebook.integration.api.rulesengine; | ||
|
||
public class MemoryThresholdReachedException extends RuntimeException { | ||
|
||
private final int threshold; | ||
private final int actual; | ||
|
||
public MemoryThresholdReachedException(int threshold, int actual) { | ||
this.threshold = threshold; | ||
this.actual = actual; | ||
} | ||
|
||
@Override | ||
public String getMessage() { | ||
return "Memory threshold reached: " + actual + "% > " + threshold + "%"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...egration-main/src/test/resources/1m_event_with_20kb_payload_match_multiple_rules_ast.json
Large diffs are not rendered by default.
Oops, something went wrong.
53 changes: 53 additions & 0 deletions
53
...le-rulebook-integration-main/src/test/resources/1m_event_with_20kb_payload_rules_ast.json
Large diffs are not rendered by default.
Oops, something went wrong.