Skip to content

Commit e7f731b

Browse files
authored
feat: DH-18423: add a systemic_obj_tracker module in the Py server API (deephaven#6577)
Added a systemic_obj_tracker.py module which allows users to enable/disable systemic object marking on the current thread.
1 parent d4d0a10 commit e7f731b

File tree

4 files changed

+147
-1
lines changed

4 files changed

+147
-1
lines changed

engine/updategraph/src/main/java/io/deephaven/engine/util/systemicmarking/SystemicObjectTracker.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public static void markThreadSystemic() {
4343
}
4444

4545
/**
46-
* Marks the current thread as systemically important. This can be changed with {@link #markThreadSystemic()} ()}
46+
* Marks the current thread as not systemically important. This can be changed with {@link #markThreadSystemic()}
47+
* ()}
4748
*/
4849
public static void markThreadNotSystemic() {
4950
if (SYSTEMIC_OBJECT_MARKING_ENABLED) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#
2+
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
3+
#
4+
"""This module allows user to enable/disable Deephaven systemic object marking. When enabled, Deephaven will mark
5+
all objects created in the current thread as systemic. These systemic objects will be tracked and if errors occur to
6+
them, the errors are deemed to be systemic and fatal.
7+
"""
8+
import contextlib
9+
10+
import jpy
11+
from deephaven import DHError
12+
13+
_JSystemicObjectTracker = jpy.get_type("io.deephaven.engine.util.systemicmarking.SystemicObjectTracker")
14+
15+
16+
def is_systemic_object_marking_enabled() -> bool:
17+
"""Returns True if the systemic object marking is enabled. When enabled, the current thread can be marked as
18+
systemic or not systemic.
19+
"""
20+
return _JSystemicObjectTracker.isSystemicObjectMarkingEnabled()
21+
22+
23+
def is_systemic() -> bool:
24+
"""Returns whether the current thread is systemic. If true, objects created on this thread are treated as
25+
systemic."""
26+
return _JSystemicObjectTracker.isSystemicThread()
27+
28+
29+
def set_systemic(systemic: bool) -> None:
30+
"""Sets whether the current thread is systemic. If true, objects created on this thread are treated as systemic.
31+
32+
Args:
33+
systemic (bool): True to mark the current thread as systemic, False to mark it as not systemic.
34+
35+
Raises:
36+
DHError: If the systemic object marking is not enabled.
37+
"""
38+
if is_systemic_object_marking_enabled():
39+
if systemic:
40+
_JSystemicObjectTracker.markThreadSystemic()
41+
else:
42+
_JSystemicObjectTracker.markThreadNotSystemic()
43+
else:
44+
raise DHError(message="Systemic object marking is not enabled.")
45+
46+
47+
@contextlib.contextmanager
48+
def systemic_object_marking() -> None:
49+
"""A Context manager to ensure the current thread is marked as systemic for the execution of the enclosed code
50+
block. On exit, the thread is restored to its previous systemic state.
51+
52+
Raises:
53+
DHError: If the systemic object marking is not enabled.
54+
"""
55+
if is_systemic_object_marking_enabled():
56+
if not is_systemic():
57+
try:
58+
_JSystemicObjectTracker.markThreadSystemic()
59+
yield
60+
finally:
61+
_JSystemicObjectTracker.markThreadNotSystemic()
62+
else:
63+
yield
64+
else:
65+
raise DHError(message="Systemic object marking is not enabled.")
66+
67+
68+
@contextlib.contextmanager
69+
def no_systemic_object_marking() -> None:
70+
"""A Context manager to ensure the current thread is marked as not systemic for the execution of the enclosed code
71+
block. On exit, the thread is restored to its previous systemic state.
72+
73+
Raises:
74+
DHError: If the systemic object marking is not enabled.
75+
"""
76+
if is_systemic_object_marking_enabled():
77+
if is_systemic():
78+
try:
79+
_JSystemicObjectTracker.markThreadNotSystemic()
80+
yield
81+
finally:
82+
_JSystemicObjectTracker.markThreadSystemic()
83+
else:
84+
yield
85+
else:
86+
raise DHError(message="Systemic object marking is not enabled.")

py/server/test_helper/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def start_jvm_for_tests(jvm_props: Dict[str, str] = None):
3737

3838
'Calendar.default': 'USNYSE_EXAMPLE',
3939
'Calendar.importPath': '/test_calendar_imports.txt',
40+
'SystemicObjectTracker.enabled': 'true',
4041
}
4142

4243
if jvm_props:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#
2+
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
3+
#
4+
import unittest
5+
from unittest.mock import patch
6+
from deephaven import DHError, empty_table
7+
import deephaven.systemic_obj_tracker as tracker
8+
9+
10+
class TestSystemicObjectTracker(unittest.TestCase):
11+
12+
def test_is_systemic_object_marking_enabled(self):
13+
self.assertTrue(tracker.is_systemic_object_marking_enabled())
14+
15+
def test_is_systemic(self):
16+
# user thread is not systemic by default
17+
self.assertFalse(tracker.is_systemic())
18+
19+
def test_set_systemic(self):
20+
tracker.set_systemic(True)
21+
self.assertTrue(tracker.is_systemic())
22+
t = empty_table(10)
23+
self.assertTrue(t.j_object.isSystemicObject())
24+
25+
tracker.set_systemic(False)
26+
self.assertFalse(tracker.is_systemic())
27+
t = empty_table(10)
28+
self.assertFalse(t.j_object.isSystemicObject())
29+
30+
with patch("deephaven.systemic_obj_tracker._JSystemicObjectTracker") as mock_tracker:
31+
mock_tracker.isSystemicObjectMarkingEnabled.return_value = False
32+
with self.assertRaises(DHError) as cm:
33+
tracker.set_systemic(True)
34+
self.assertIn("Systemic object marking is not enabled", str(cm.exception))
35+
36+
def test_systemic_object_marking(self):
37+
with tracker.systemic_object_marking():
38+
self.assertTrue(tracker.is_systemic())
39+
t = empty_table(10)
40+
self.assertTrue(t.j_object.isSystemicObject())
41+
42+
def test_systemic_object_marking_error(self):
43+
with patch("deephaven.systemic_obj_tracker._JSystemicObjectTracker") as mock_tracker:
44+
mock_tracker.isSystemicObjectMarkingEnabled.return_value = False
45+
with self.assertRaises(DHError) as cm:
46+
with tracker.systemic_object_marking():
47+
pass
48+
self.assertIn("Systemic object marking is not enabled", str(cm.exception))
49+
50+
def test_no_systemic_object_marking(self):
51+
with tracker.no_systemic_object_marking():
52+
self.assertFalse(tracker.is_systemic())
53+
t = empty_table(10)
54+
self.assertFalse(t.j_object.isSystemicObject())
55+
56+
57+
if __name__ == '__main__':
58+
unittest.main()

0 commit comments

Comments
 (0)