From 87f56b953925ae4f4c059844dd6057c89d0614ef Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sat, 14 Sep 2024 13:41:29 -0700 Subject: [PATCH] Free up memory when accessing non-existent sub columns. --- .../org/cojen/tupl/table/PathSplitter.java | 18 ++++++++++++++++++ .../org/cojen/tupl/table/RowMethodsMaker.java | 14 +++++++++++--- .../cojen/tupl/table/join/BasicJoinTest.java | 7 +++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/cojen/tupl/table/PathSplitter.java b/src/main/java/org/cojen/tupl/table/PathSplitter.java index a1c033a77..de1c77ad6 100644 --- a/src/main/java/org/cojen/tupl/table/PathSplitter.java +++ b/src/main/java/org/cojen/tupl/table/PathSplitter.java @@ -124,4 +124,22 @@ private Entry doFind(String path) { return e; } + + public synchronized void remove(Entry entry) { + Entry[] entries = mEntries; + int index = entry.mPath.hashCode() & (entries.length - 1); + for (Entry e = entries[index], prev = null; e != null; e = e.mNext) { + if (e == entry) { + if (prev == null) { + entries[index] = e.mNext; + } else { + prev.mNext = e.mNext; + } + mSize--; + return; + } else { + prev = e; + } + } + } } diff --git a/src/main/java/org/cojen/tupl/table/RowMethodsMaker.java b/src/main/java/org/cojen/tupl/table/RowMethodsMaker.java index 12d627d38..e09fe9869 100644 --- a/src/main/java/org/cojen/tupl/table/RowMethodsMaker.java +++ b/src/main/java/org/cojen/tupl/table/RowMethodsMaker.java @@ -373,14 +373,16 @@ private void nameSwitch(Lookup lookup, MethodType type, labels[i].here(); var subVar = rowVar.invoke(mColumns[i].name); - Label notNull = mm.label(); - subVar.ifNe(null, notNull); + Label ready = mm.label(); + + subVar.ifNe(null, ready); if (type.returnType().isPrimitive()) { mm.var(RowMethodsMaker.class).invoke("nullJoin", nameVar, tailVar).throw_(); } else { mm.return_(null); } - notNull.here(); + + ready.here(); String name = mm.name(); @@ -400,6 +402,12 @@ private void nameSwitch(Lookup lookup, MethodType type, mm.return_(rowMethodsVar.invoke(name, tailVar, subVar)); } } + + mm.catch_(ready, IllegalArgumentException.class, exVar -> { + // Remove a bogus entry from the PathSplitter to free up memory. + splitterVar.invoke("remove", entryVar); + exVar.throw_(); + }); } default_.here(); diff --git a/src/test/java/org/cojen/tupl/table/join/BasicJoinTest.java b/src/test/java/org/cojen/tupl/table/join/BasicJoinTest.java index 38ae9c41d..8a275f459 100644 --- a/src/test/java/org/cojen/tupl/table/join/BasicJoinTest.java +++ b/src/test/java/org/cojen/tupl/table/join/BasicJoinTest.java @@ -933,6 +933,13 @@ public void generated() throws Exception { assertEquals(1, row.get_int("dept.companyId")); assertEquals("Sales", row.getString("dept.name")); + try { + row.get("dept.fake.id"); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Column name isn't found: fake.id", e.getMessage()); + } + row.set("dept.id", 123L); row.set("dept.companyId", (Integer) null); row.set("dept.name", "none");