[ 
https://issues.apache.org/jira/browse/DERBY-2380?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12478685
 ] 

Daniel John Debrunner commented on DERBY-2380:
----------------------------------------------

In looking more at this issue (along with DERBY-2397) I think the dependency 
manager would be much cleaner if only persistent objects could be Providers.
Persistent objects are much better suited to the DependencyManager because 
there is a definite termination of the object, the DROP statement.

This would mean GenericPreparedStatement  (GPS) would not be a Provider, i.e. 
no -one could create a dependency on a compiled plan.  This causes problems 
because now some action must be taken when a GPS is no longer in use, to 
invalidate anything that depends on it. Not performing the invalidation would 
lead to a memory leak in the dependency manager. This need to know who is using 
a GPS has lead to the usage count, the partially valid state, generally not a 
clean way of handling its lifecycle. Not having GPS be a Provider would mean 
GPS would be like a typical java object, having a reference to the object 
allows it to be used.
GPS is also (I think) the only non-persistent object that is a Provider.

The only case where one plan depends on another  today is when a positioned 
update/delete plan (GPS) depends on the plan (GPS) for the open cursor.

I don't think this dependency is needed because the positioned update/delete 
will depend on the table being modified during its compilation.
Thus if the cursor changes due to any change in the base table, then the 
positioned statement will be invalidated anyway.
The positioned code already has a different mechanism to handle when the cursor 
changes to a different plan (which isn't triggered by an invalidation on the 
original cursor, since the original cursor plan may still be valid).
Cursor change/invalidations are  tested for in CurrentOfTest. I also added some 
new test fixtures to cover additional situations where the positioned statement 
needs to be invalidated or work against a different cursor.

I have changes where this GenericPreparedStatement is no longer implements 
Provider and thus the positioned update/delete - cursor dependency does not 
exist. This basically works though various errors change from "cursor not 
found" to "cursor is closed" and vice-versa. This would be a step to cleanup 
the life-cycle state of GenericPreparedStatement, thus leading to being able to 
null out its compile objects once it becomes invalid (ie. current plan is 
invalid but the object could be reprepared to make it valid again).

The change in errors is interesting, it's basically because the old code always 
threw 'cursor is closed' at runtime if the positioned update/delete could not 
find a matching cursor (having successfully compiled against one). I'm not sure 
this is correct, I tried to mimic the old behaviour by throwing 'cursor not 
found' if the connection does not have any open activations with that name, and 
'cursor is closed' if the connection has an open activation (ie. 
java.sql.PreparedStatement)  with that name, but no open result set. But I'm 
not sure if that is valid, one viewpoint could be that if there is no open 
cursor then the cursor doesn't exist and thus there is no such error as 'cursor 
is closed'. I couldn't see from the SQL spec any specific guidance on this 
(looking at DECLARE/OPEN and positioned UPDATE & DELETE), if anyone has any 
thoughts ...





> A statement plan holds onto resources such as its generated class even after 
> it has been invalidated.
> -----------------------------------------------------------------------------------------------------
>
>                 Key: DERBY-2380
>                 URL: https://issues.apache.org/jira/browse/DERBY-2380
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.0.2.0, 10.0.2.1, 10.1.1.0, 10.1.2.1, 10.1.3.1, 
> 10.2.1.6, 10.2.2.0, 10.3.0.0
>            Reporter: Daniel John Debrunner
>         Assigned To: Daniel John Debrunner
>
> An internal plan (instance of GenericPreparedStatement) can be invalidated by 
> other SQL operations such as DROP TABLE or DROP INDEX.
> When this happens the references to objects that are no longer useful such as 
> the generated class and saved objects are held onto and thus use memory.
> If the statement is re-compiled then these objects will be handled by garbage 
> collection.
> If the statement is not recompiled though, then these objects will remain 
> until the plan (GenericPreparedStatement) is garbage collected.
> The plan being garbage collected can be held up for two reasons:
>    1) The plan is in the statement cache. Note that only in some cases does 
> it make sense to remove an invalid plan from the statement cache, e.g. a DROP 
> TABLE should remove any plan that uses that table, but a DROP TRIGGER should 
> not remove an INSERT from the cache, as it is likely the plan will be re-used 
> and re-compiled. This  is a separate issue given that the memory usage can 
> occur even if the plan is not in the cache.
>    2) The application holds onto a JDBC PreparedStatement that uses the plan.
> Given an application should not be able to affect memory usage like this then 
> the GenericPreparedStatement.makeInvalid() call should null out fields that 
> hold references to objects that have become invalid.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to