Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Properly close stmt and conn when using idb #232

Merged
merged 3 commits into from
Apr 9, 2020
Merged

Conversation

kadler
Copy link
Member

@kadler kadler commented Apr 6, 2020

Deleting the statement object doesn't free the underlying resources,
causing memory leaks. Instead, we need to close both the connection and
the statement to free these resources. We can let the runtime delete the
objects as well.

Fixes #230

Deleting the statement object doesn't free the underlying resources,
causing memory leaks. Instead, we need to close both the connection and
the statement to free these resources. We can let the runtime delete the
objects as well.

Fixes #230
@kadler kadler requested a review from abmusse April 6, 2020 15:49
@kadler
Copy link
Member Author

kadler commented Apr 6, 2020

This might not be 100% correct for sync mode, since I don't know how errors are returned in that case (exceptions?)

@abmusse
Copy link
Member

abmusse commented Apr 6, 2020

This might not be 100% correct for sync mode, since I don't know how errors are returned in that case (exceptions?)

Yup prepareSync would throw an error here.

This won't give you the chance to properly close things out with cleanup().

Looks we can get around this by passing a callback to prepareSync. That way we can check for an error just like the async case

lib/istoredp.js Outdated Show resolved Hide resolved
lib/istoredp.js Outdated Show resolved Hide resolved
@kadler
Copy link
Member Author

kadler commented Apr 6, 2020

I've changed the whole design. Since everything throws errors, wrap the whole thing in try/finally blocks. This way we don't eve need the function, since the clean up code only happens in one place.

The only downfall with this design is that cleanup will not be done until after the user's callback chain has returned to us.

@kadler kadler requested a review from abmusse April 6, 2020 16:32
@abmusse
Copy link
Member

abmusse commented Apr 6, 2020

I tried running through the tests with:

$ npm test test/functional/commandsFunctional.js

    Uncaught Error: SQLSTATE=PAERR SQLCODE=8013 The SQL Statment handler is not initialized.
      at ../istoredp.js:77:16

I'm trying to figure out why.

@abmusse
Copy link
Member

abmusse commented Apr 6, 2020

@kadler

The JavaScript try…catch mechanism cannot be used to intercept errors generated by asynchronous APIs.

See https://nodejs.org/api/errors.html#errors_error_first_callbacks

Running the command test with verbose mode on we can see:

============
INPUT XML
============
<?xml version='1.0'?><myscript><cmd exec='rexx' error='fast'>RTVJOBA USRLIBL(?) SYSLIBL(?)</cmd></myscript>
============
OUTPUT XML
============
SQLConnect(0): conn obj [1805037d0] handler [2]
creating statement
stmt is dbstmt {}
Prepare().
SQLFreeStmt: stmth 3 [SQL_DROP]
SQLFreeStmt(0)
SQLDisconnect: conn obj [1805037d0] handler [2]
SQLFreeConnect: conn obj [1805037d0] handler [2]
SQLFreeConnect[0]
SQLPrepare(-2): call QXMLSERV.iPLUG512K(?,?,?,?)
calling bind
BindParamAsync().
      1) calls CL command using idb transport


  0 passing (114ms)
  1 failing

  1) iSh, iCmd, iQsh, Functional Tests
       iCmd()
         calls CL command using idb transport:
     Uncaught Error: SQLSTATE=PAERR SQLCODE=8013 The SQL Statment handler is not initialized.
      at ../istoredp.js:83:16

Looks like the finally block runs before prepare finishes causing the statement handle to be invalid SQLPrepare(-2).

Copy link
Member

@abmusse abmusse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we avoid try..catch mechanism when in async mode.

@kadler
Copy link
Member Author

kadler commented Apr 6, 2020

Ugh, that makes sense. The fact that the whole thing is wrapped in an exception handler and the code throws is what lead me to that. Now I wonder if the code is currently broken.

@kadler
Copy link
Member Author

kadler commented Apr 6, 2020

I moved the try/finally around the sync mode block and in the async block I used the same way I had before.

@abmusse
Copy link
Member

abmusse commented Apr 6, 2020

Ugh, that makes sense. The fact that the whole thing is wrapped in an exception handler and the code throws is what lead me to that. Now I wonder if the code is currently broken.

Throwing an error withing the async callback is definitely wrong.

Furthermore v0.x did not report errors back to the user at all in the iConn.run() callback.

Having error first callbacks in Connection.run() is one of the key features of 1.x.

@abmusse
Copy link
Member

abmusse commented Apr 6, 2020

I moved the try/finally around the sync mode block and in the async block I used the same way I had before.

Those changes fixed the issue.

@kadler
Copy link
Member Author

kadler commented Apr 6, 2020

Ugh, that makes sense. The fact that the whole thing is wrapped in an exception handler and the code throws is what lead me to that. Now I wonder if the code is currently broken.

Throwing an error withing the async callback is definitely wrong.

Furthermore v0.x did not report errors back to the user at all in the iConn.run() callback.

Yeah, I think that's all it's doing in this case: the exception is thrown and then caught and printed out. The exception shouldn't get back to the user - if they use async mode, they either they didn't get an error and the callback is called or they did and the callback is not. This is bonkers, but I don't know how to fix it without changing behavior, which is why we did what we did in v1.0. My goal wasn't to change that, but to fix the problem at hand.

@abmusse abmusse self-requested a review April 6, 2020 20:40
Copy link
Member

@abmusse abmusse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kadler kadler merged commit b638de8 into v0.1 Apr 9, 2020
@kadler kadler deleted the idb-memory-leak-v0.1 branch April 9, 2020 15:08
@kadler
Copy link
Member Author

kadler commented Apr 9, 2020

@abmusse can you please make a v0.1.7 release?

@abmusse
Copy link
Member

abmusse commented Apr 9, 2020

@kadler

I believe you meant v0.1.7 right?

After making the release on github also publish on npm?

@kadler
Copy link
Member Author

kadler commented Apr 9, 2020

Yep. Caught my mistake a hair too late.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants