Skip to content

Commit d85439e

Browse files
authored
perf: DH-21883: RetainedReferenceManager empty and singleton Impls (deephaven#7777)
1 parent a57109c commit d85439e

File tree

4 files changed

+499
-14
lines changed

4 files changed

+499
-14
lines changed

engine/table/src/main/java/io/deephaven/engine/table/impl/BaseTable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ public final void addParentReference(@NotNull final Object parent) {
491491
private Collection<Object> ensureParents() {
492492
// noinspection unchecked
493493
return FieldUtils.ensureField(this, PARENTS_UPDATER, EMPTY_PARENTS,
494-
() -> new KeyedObjectHashSet<>(IdentityKeyedObjectKey.getInstance()));
494+
() -> new KeyedObjectHashSet<>(1, 0.5f, IdentityKeyedObjectKey.getInstance()));
495495
}
496496

497497
@Override

engine/table/src/main/java/io/deephaven/engine/table/impl/QueryTable.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,11 @@ public FilteredTable(final TrackingRowSet currentMapping, final QueryTable sourc
10671067
this.source = source;
10681068
}
10691069

1070+
@Override
1071+
public String toString() {
1072+
return "FilteredTable(" + whereListener + ")";
1073+
}
1074+
10701075
@Override
10711076
public void requestRecompute() {
10721077
refilterMatchedRequested = refilterUnmatchedRequested = true;

engine/table/src/test/java/io/deephaven/engine/liveness/TestLiveness.java

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
import org.junit.Rule;
1313
import org.junit.Test;
1414

15+
import java.util.ArrayList;
16+
import java.util.List;
17+
import java.util.stream.Stream;
18+
19+
import static org.junit.Assert.assertFalse;
20+
import static org.junit.Assert.assertTrue;
21+
1522
/**
1623
* Unit tests for liveness code.
1724
*/
@@ -76,4 +83,259 @@ public void testTryManageFailure() {
7683
expected.printStackTrace();
7784
}
7885
}
86+
87+
private static class NamedLivenessArtifact extends LivenessArtifact {
88+
public String name;
89+
90+
public NamedLivenessArtifact(String name, boolean strong) {
91+
super(strong);
92+
this.name = name;
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return name;
98+
}
99+
}
100+
101+
@Test
102+
public void testMultipleReferences() {
103+
testMultipleReferences(false);
104+
testMultipleReferences(true);
105+
}
106+
107+
private void testMultipleReferences(boolean strong) {
108+
final LivenessArtifact a1, a2, a3;
109+
final LivenessScope scope = new LivenessScope();
110+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
111+
a1 = new NamedLivenessArtifact("a1", strong);
112+
a2 = new NamedLivenessArtifact("a2", strong);
113+
a3 = new NamedLivenessArtifact("a3", strong);
114+
a1.manage(a3);
115+
a1.manage(a2);
116+
scope.manage(a1);
117+
}
118+
119+
final LivenessArtifact a4;
120+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
121+
a4 = new NamedLivenessArtifact("a4", strong);
122+
a4.manage(a1);
123+
a4.manage(a2);
124+
a4.manage(a3);
125+
}
126+
127+
if (a4.tryManage(a1)) {
128+
TestCase.fail("Expected not to manage a1");
129+
}
130+
131+
scope.release();
132+
133+
final LivenessArtifact a5;
134+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
135+
a5 = new NamedLivenessArtifact("a5", strong);
136+
if (a5.tryManage(a1)) {
137+
TestCase.fail("Expected not to manage a1");
138+
}
139+
if (a5.tryManage(a2)) {
140+
TestCase.fail("Expected not to manage a2");
141+
}
142+
if (a5.tryManage(a3)) {
143+
TestCase.fail("Expected not to manage a3");
144+
}
145+
}
146+
}
147+
148+
@Test
149+
public void testSingletonLivenessManager() {
150+
testSingletonLivenessManager(false);
151+
testSingletonLivenessManager(true);
152+
}
153+
154+
private void testSingletonLivenessManager(final boolean strong) {
155+
final LivenessArtifact a1, a2, a3;
156+
final SingletonLivenessManager slm;
157+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
158+
a1 = new NamedLivenessArtifact("a1", strong);
159+
a2 = new NamedLivenessArtifact("a2", strong);
160+
a3 = new NamedLivenessArtifact("a3", strong);
161+
a2.manage(a1);
162+
a3.manage(a1);
163+
a3.manage(a2);
164+
slm = new SingletonLivenessManager(a3);
165+
}
166+
167+
assertTrue(a1.tryRetainReference());
168+
a1.dropReference();
169+
assertTrue(a2.tryRetainReference());
170+
a2.dropReference();
171+
assertTrue(a3.tryRetainReference());
172+
a3.dropReference();
173+
174+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
175+
final LivenessArtifact a4 = new NamedLivenessArtifact("a4", strong);
176+
a4.manage(a3);
177+
}
178+
179+
slm.release();
180+
181+
assertFalse(a1.tryRetainReference());
182+
assertFalse(a2.tryRetainReference());
183+
assertFalse(a3.tryRetainReference());
184+
}
185+
186+
@Test
187+
public void testSingletonDrop() {
188+
testSingletonDrop(false);
189+
testSingletonDrop(true);
190+
}
191+
192+
private void testSingletonDrop(final boolean strong) {
193+
final LivenessArtifact a0, a1, a2, a3;
194+
final SingletonLivenessManager slm;
195+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
196+
a0 = new NamedLivenessArtifact("a0", strong);
197+
a1 = new NamedLivenessArtifact("a1", strong);
198+
a2 = new NamedLivenessArtifact("a2", strong);
199+
a3 = new NamedLivenessArtifact("a3", strong);
200+
201+
202+
a1.manage(a0);
203+
a2.manage(a1);
204+
a3.manage(a1);
205+
a3.manage(a2);
206+
207+
// negative test for a referent that isn't managed
208+
a1.unmanage(Stream.of(a3));
209+
a2.unmanage(a3);
210+
211+
// drop the single value
212+
a1.unmanage(Stream.of(a0));
213+
a2.unmanage(a1);
214+
215+
a3.unmanage(a1);
216+
a3.unmanage(a2);
217+
218+
slm = new SingletonLivenessManager(a3);
219+
}
220+
221+
assertFalse(a0.tryRetainReference());
222+
assertFalse(a1.tryRetainReference());
223+
assertFalse(a2.tryRetainReference());
224+
assertTrue(a3.tryRetainReference());
225+
a3.dropReference();
226+
227+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
228+
final LivenessArtifact a4 = new NamedLivenessArtifact("a4", strong);
229+
a4.manage(a3);
230+
}
231+
232+
slm.release();
233+
234+
assertFalse(a1.tryRetainReference());
235+
assertFalse(a2.tryRetainReference());
236+
assertFalse(a3.tryRetainReference());
237+
}
238+
239+
@Test
240+
public void testSillyDrops() {
241+
testSillyDrops(false);
242+
testSillyDrops(true);
243+
}
244+
245+
private void testSillyDrops(final boolean strong) {
246+
final LivenessArtifact a0, a1, a2;
247+
try (final SafeCloseable ignored = LivenessScopeStack.open()) {
248+
a0 = new NamedLivenessArtifact("a0", strong);
249+
a1 = new NamedLivenessArtifact("a1", strong);
250+
a2 = new NamedLivenessArtifact("a2", strong);
251+
252+
// empty implementations drops a thing, which obviously does not exist ...
253+
a0.unmanage(a1);
254+
a0.unmanage(Stream.of(a1, a2));
255+
256+
a0.manage(a1);
257+
a0.unmanage(a1);
258+
259+
// singleton implementation, but with an empty reference drops a thing, which also obviously does not exist
260+
a0.unmanage(a2);
261+
a0.unmanage(Stream.of(a1, a2));
262+
}
263+
264+
assertFalse(a0.tryRetainReference());
265+
assertFalse(a1.tryRetainReference());
266+
assertFalse(a2.tryRetainReference());
267+
}
268+
269+
@Test
270+
public void testTransferTo() {
271+
testTransferTo(false);
272+
// If the liveness scope enforced strong reachability, it does not permit transfer; so we cannot test it.
273+
// testTransferTo(true);
274+
}
275+
276+
private void testTransferTo(final boolean strong) {
277+
final LivenessArtifact a0, a1, a2;
278+
279+
final LivenessScope ls = new LivenessScope(strong);
280+
final LivenessScope ls2 = new LivenessScope(strong);
281+
282+
LivenessScopeStack.push(ls);
283+
// for empty
284+
ls.transferTo(ls2);
285+
a0 = new NamedLivenessArtifact("a0", strong);
286+
// for single
287+
ls.transferTo(ls2);
288+
a1 = new NamedLivenessArtifact("a1", strong);
289+
a2 = new NamedLivenessArtifact("a2", strong);
290+
// for double
291+
ls.transferTo(ls2);
292+
LivenessScopeStack.pop(ls);
293+
ls.release();
294+
295+
assertTrue(a0.tryRetainReference());
296+
a0.dropReference();
297+
assertTrue(a1.tryRetainReference());
298+
a1.dropReference();
299+
assertTrue(a2.tryRetainReference());
300+
a2.dropReference();
301+
ls2.release();
302+
303+
assertFalse(a0.tryRetainReference());
304+
assertFalse(a1.tryRetainReference());
305+
assertFalse(a2.tryRetainReference());
306+
}
307+
308+
@Test
309+
public void testMakePermanent() {
310+
testMakePermanent(false);
311+
// cannot transfer a liveness scope with strong reachability
312+
// testMakePermanent(true);
313+
}
314+
315+
private void testMakePermanent(final boolean strong) {
316+
final LivenessArtifact a0, a1, a2;
317+
318+
final LivenessScope ls = new LivenessScope(strong);
319+
final PermanentLivenessManager permanentLivenessManager = new PermanentLivenessManager();
320+
321+
LivenessScopeStack.push(ls);
322+
// for empty
323+
ls.transferTo(permanentLivenessManager);
324+
a0 = new NamedLivenessArtifact("a0", strong);
325+
// for single
326+
ls.transferTo(permanentLivenessManager);
327+
a1 = new NamedLivenessArtifact("a1", strong);
328+
a2 = new NamedLivenessArtifact("a2", strong);
329+
// for double
330+
ls.transferTo(permanentLivenessManager);
331+
LivenessScopeStack.pop(ls);
332+
ls.release();
333+
334+
assertTrue(a0.tryRetainReference());
335+
a0.dropReference();
336+
assertTrue(a1.tryRetainReference());
337+
a1.dropReference();
338+
assertTrue(a2.tryRetainReference());
339+
a2.dropReference();
340+
}
79341
}

0 commit comments

Comments
 (0)