Skip to content

Commit 818a10b

Browse files
committed
Add a persistent reference to JS objects during async operations to prevent premature garbage collection
1 parent f1290e1 commit 818a10b

File tree

12 files changed

+218
-147
lines changed

12 files changed

+218
-147
lines changed

lib/connection.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,6 @@ function release(releaseCb) {
176176
self._pool._onConnectionRelease();
177177
}
178178

179-
// Need to maintain a reference to the connection instance to ensure that the
180-
// garbage collector doesn't destroy it too soon.
181-
self = undefined;
182179
});
183180
}
184181

lib/resultset.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ function close(closeCb) {
4040
self._processingStarted = true;
4141

4242
self._close(function(err) {
43-
// Need to maintain a reference to the resultset instance to ensure that the
44-
// garbage collector doesn't destroy it too soon.
45-
self = undefined;
4643

4744
closeCb(err);
4845
});

src/njs/src/njsConnection.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,18 @@ Connection::~Connection()
101101
Initialize connection attributes after forming it.
102102
103103
PARAMETERS:
104-
DPI Connection, Oracledb reference
104+
DPI Connection, Oracledb reference, reference to js parent
105105
*/
106-
void Connection::setConnection(dpi::Conn* dpiconn, Oracledb* oracledb)
106+
void Connection::setConnection(dpi::Conn* dpiconn, Oracledb* oracledb, Local<Object> jsParentObj)
107107
{
108108
this->dpiconn_ = dpiconn;
109109
this->isValid_ = true;
110110
this->oracledb_ = oracledb;
111111
this->lobCount_ = 0;
112112
this->rsCount_ = 0;
113113
this->dbCount_ = 0;
114+
115+
this->jsParent_.Reset ( jsParentObj );
114116
}
115117

116118
/*****************************************************************************/
@@ -447,7 +449,8 @@ NAN_METHOD(Connection::Execute)
447449
/* If connection is invalid from JS, then throw an exception */
448450
NJS_CHECK_OBJECT_VALID2 ( connection, info ) ;
449451

450-
eBaton *executeBaton = new eBaton ( connection->DBCount (), callback );
452+
eBaton *executeBaton = new eBaton ( connection->DBCount (), callback,
453+
info.Holder () );
451454

452455
NJS_CHECK_NUMBER_OF_ARGS ( executeBaton->error, info, 2, 4, exitExecute );
453456

@@ -3181,7 +3184,7 @@ v8::Local<v8::Value> Connection::GetOutBindObject ( eBaton *executeBaton )
31813184
* Checks whther connection is busy with database call or not using counters
31823185
*
31833186
* PARAMETERS
3184-
* connection - connection object to check it's counters
3187+
* connection - connection object to check its counters
31853188
*
31863189
* Note: Currently this function can be used only in Release () method
31873190
*/
@@ -3217,10 +3220,17 @@ NAN_METHOD(Connection::Release)
32173220

32183221
connection = Nan::ObjectWrap::Unwrap<Connection>(info.Holder());
32193222

3220-
/* If connection is invalide from JS, then throw an exception */
3223+
/* If connection is invalid from JS, then throw an exception */
32213224
NJS_CHECK_OBJECT_VALID2 ( connection, info ) ;
32223225

3223-
eBaton *releaseBaton = new eBaton ( connection->DBCount (), callback );
3226+
eBaton *releaseBaton = new eBaton ( connection->DBCount (), callback,
3227+
info.Holder() );
3228+
3229+
/*
3230+
* When we release the connection, we have to clear the reference of
3231+
* its parent.
3232+
*/
3233+
releaseBaton->njsconn = connection;
32243234

32253235
NJS_CHECK_NUMBER_OF_ARGS ( releaseBaton->error, info, 1, 1, exitRelease );
32263236
if(!connection->isValid_)
@@ -3316,6 +3326,13 @@ void Connection::Async_AfterRelease(uv_work_t *req)
33163326
argv[0] = v8::Exception::Error(Nan::New<v8::String>((releaseBaton->error).c_str()).ToLocalChecked());
33173327
else
33183328
argv[0] = Nan::Undefined();
3329+
3330+
/*
3331+
* When we release the connection, we have to clear the reference of
3332+
* its parent.
3333+
*/
3334+
releaseBaton->njsconn->jsParent_.Reset ();
3335+
33193336
Local<Function> callback = Nan::New<Function>(releaseBaton->cb);
33203337
delete releaseBaton;
33213338
Nan::MakeCallback( Nan::GetCurrentContext()->Global(),
@@ -3346,7 +3363,8 @@ NAN_METHOD(Connection::Commit)
33463363
/* if connection is invalid from JS, then throw an exception */
33473364
NJS_CHECK_OBJECT_VALID2 ( connection, info ) ;
33483365

3349-
eBaton *commitBaton = new eBaton ( connection->DBCount (), callback );
3366+
eBaton *commitBaton = new eBaton ( connection->DBCount (), callback,
3367+
info.Holder() );
33503368

33513369
NJS_CHECK_NUMBER_OF_ARGS ( commitBaton->error, info, 1, 1, exitCommit );
33523370
if(!connection->isValid_)
@@ -3452,7 +3470,8 @@ NAN_METHOD(Connection::Rollback)
34523470
/* if connection is invalid from JS, then throw an exception */
34533471
NJS_CHECK_OBJECT_VALID2 ( connection, info );
34543472

3455-
eBaton *rollbackBaton = new eBaton ( connection->DBCount (), callback );
3473+
eBaton *rollbackBaton = new eBaton ( connection->DBCount (), callback,
3474+
info.Holder() );
34563475
NJS_CHECK_NUMBER_OF_ARGS ( rollbackBaton->error, info, 1, 1, exitRollback );
34573476

34583477
if(!connection->isValid_)
@@ -3556,7 +3575,8 @@ NAN_METHOD(Connection::Break)
35563575
/* If connection is invalid from JS, then throw an exception */
35573576
NJS_CHECK_OBJECT_VALID2 ( connection, info );
35583577

3559-
eBaton *breakBaton = new eBaton ( connection->DBCount (), callback );
3578+
eBaton *breakBaton = new eBaton ( connection->DBCount (), callback,
3579+
info.Holder() );
35603580

35613581
NJS_CHECK_NUMBER_OF_ARGS ( breakBaton->error, info, 1, 1, exitBreak );
35623582

src/njs/src/njsConnection.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,10 @@ typedef struct eBaton
165165
FetchInfo *fetchInfo; // Conversion meta data
166166
Nan::Persistent<Function> cb;
167167
RefCounter counter;
168+
Nan::Persistent<Object> jsConn;
168169

169-
eBaton( unsigned int& count, Local<Function> callback ) :
170+
eBaton( unsigned int& count, Local<Function> callback,
171+
Local<Object> jsConnObj ) :
170172
sql(""), error(""), dpienv(NULL), dpiconn(NULL), njsconn(NULL),
171173
rowsAffected(0), maxRows(0), prefetchRows(0),
172174
getRS(false), autoCommit(false), rowsFetched(0),
@@ -177,11 +179,13 @@ typedef struct eBaton
177179
counter ( count )
178180
{
179181
cb.Reset( callback );
182+
jsConn.Reset ( jsConnObj );
180183
}
181184

182185
~eBaton ()
183186
{
184187
cb.Reset ();
188+
jsConn.Reset ();
185189
if( !binds.empty() )
186190
{
187191
for( unsigned int index = 0 ;index < binds.size(); index++ )
@@ -255,8 +259,7 @@ typedef struct eBaton
255259
class Connection: public Nan::ObjectWrap
256260
{
257261
public:
258-
void setConnection (dpi::Conn*, Oracledb* oracledb);
259-
// Define Connection Constructor
262+
void setConnection ( dpi::Conn*, Oracledb* oracledb, Local<Object> obj );
260263
static Nan::Persistent<FunctionTemplate> connectionTemplate_s;
261264
static void Init (Handle<Object> target);
262265
static Local<Value> GetRows (eBaton* executeBaton);
@@ -325,6 +328,7 @@ class Connection: public Nan::ObjectWrap
325328
NJSErrorType errType,
326329
string property);
327330

331+
// Define Connection Constructor
328332
Connection ();
329333
~Connection ();
330334

@@ -460,9 +464,10 @@ class Connection: public Nan::ObjectWrap
460464
* Counters to see whether connection is busy or not with LOB, ResultSet or
461465
* DB operations. This counters used to prevent releasing busy connection.
462466
*/
463-
unsigned int lobCount_; // LOB operations counter
464-
unsigned int rsCount_; // ResultSet operations counter
465-
unsigned int dbCount_; // Connection or DB operations counter
467+
unsigned int lobCount_; // LOB operations counter
468+
unsigned int rsCount_; // ResultSet operations counter
469+
unsigned int dbCount_; // Connection or DB operations counter
470+
Nan::Persistent<Object> jsParent_;
466471

467472
};
468473

src/njs/src/njsIntLob.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ void ILob::setILob(eBaton *executeBaton, ProtoILob *protoILob)
210210
dpiconn_ = executeBaton->dpiconn;
211211
svch_ = executeBaton->dpiconn->getSvch();
212212

213+
this->jsParent_.Reset ( executeBaton->jsConn );
214+
213215
// error
214216
errh_ = protoILob->errh_;
215217
protoILob->errh_ = NULL;
@@ -368,6 +370,11 @@ NAN_METHOD(ILob::Release)
368370
return;
369371
}
370372

373+
/*
374+
* When we release the iLob, we have to clear the reference of
375+
* its parent jsConn.
376+
*/
377+
iLob->jsParent_.Reset ();
371378
iLob->cleanup();
372379

373380
info.GetReturnValue().SetUndefined();
@@ -831,15 +838,16 @@ NAN_METHOD(ILob::Read)
831838
{
832839

833840
Local<Function> callback;
834-
ILob *iLob;
841+
ILob *iLob;
835842

836843
NJS_GET_CALLBACK(callback, info);
837844
iLob = Nan::ObjectWrap::Unwrap<ILob>(info.Holder());
838845

839846
/* If iLob object is invalid from JS, then throw an exception */
840847
NJS_CHECK_OBJECT_VALID2 (iLob, info);
841848

842-
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (), callback );
849+
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (), callback,
850+
info.Holder() );
843851

844852
NJS_CHECK_NUMBER_OF_ARGS (lobBaton->error, info, 1, 1, exitRead);
845853

@@ -1030,16 +1038,16 @@ NAN_METHOD(ILob::Write)
10301038

10311039
Local<Function> callback;
10321040
Local<Object> buffer_obj = info[0]->ToObject();
1033-
ILob *iLob;
1041+
ILob *iLob;
10341042

10351043
NJS_GET_CALLBACK(callback, info);
10361044
iLob = Nan::ObjectWrap::Unwrap<ILob>(info.Holder());
10371045

10381046
/* If iLob is invalid from JS, then throw an exception */
10391047
NJS_CHECK_OBJECT_VALID2 ( iLob, info );
10401048

1041-
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (),
1042-
buffer_obj, callback );
1049+
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (), buffer_obj,
1050+
callback, info.Holder() );
10431051

10441052
NJS_CHECK_NUMBER_OF_ARGS (lobBaton->error, info, 2, 2, exitWrite);
10451053

src/njs/src/njsIntLob.h

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -73,37 +73,44 @@ class ILob;
7373

7474
typedef struct LobBaton
7575
{
76-
uv_work_t req;
77-
std::string error;
78-
dpi::Env *dpienv;
79-
dpi::Conn *dpiconn;
80-
81-
ILob *iLob;
82-
char *writebuf;
83-
unsigned long long writelen;
84-
RefCounter counter;
85-
86-
Nan::Persistent<Function> cb;
87-
Nan::Persistent<Object> lobbuf;
88-
LobBaton( unsigned int& count, Local<Function> callback ):
76+
uv_work_t req;
77+
std::string error;
78+
dpi::Env *dpienv;
79+
dpi::Conn *dpiconn;
80+
81+
ILob *iLob;
82+
char *writebuf;
83+
unsigned long long writelen;
84+
RefCounter counter;
85+
86+
Nan::Persistent<Function> cb;
87+
Nan::Persistent<Object> lobbuf;
88+
Nan::Persistent<Object> jsLob;
89+
90+
LobBaton( unsigned int& count, Local<Function> callback,
91+
Local<Object> jsLobObj ):
8992
error(""), dpienv(NULL), dpiconn(NULL), iLob(NULL), writebuf(NULL),
9093
writelen(0), counter( count )
9194
{
9295
cb.Reset( callback );
96+
jsLob.Reset ( jsLobObj );
9397
}
9498

95-
LobBaton( unsigned int& count, Local<Object> buffer_obj, Local<Function> callback ):
99+
LobBaton( unsigned int& count, Local<Object> buffer_obj,
100+
Local<Function> callback, Local<Object> jsLobObj ):
96101
error(""), dpienv(NULL), dpiconn(NULL), iLob(NULL), writebuf(NULL),
97102
writelen(0), counter( count )
98103
{
99104
cb.Reset( callback );
100105
lobbuf.Reset(buffer_obj);
106+
jsLob.Reset ( jsLobObj );
101107
}
102108

103109
~LobBaton ()
104110
{
105111
cb.Reset();
106112
lobbuf.Reset();
113+
jsLob.Reset ();
107114
}
108115

109116
} LobBaton;
@@ -202,24 +209,25 @@ class ILob : public Nan::ObjectWrap
202209
static void Async_Write (uv_work_t *req);
203210
static void Async_AfterWrite (uv_work_t *req);
204211

205-
Descriptor *lobLocator_;
206-
unsigned short fetchType_;
207-
208-
Connection *njsconn_;
209-
dpi::Conn *dpiconn_;
210-
DpiHandle *svch_;
211-
DpiHandle *errh_;
212-
bool isValid_;
213-
State state_;
214-
215-
char *buf_;
216-
unsigned int bufSize_;
217-
unsigned int chunkSize_;
218-
unsigned long long length_;
219-
unsigned long long offset_;
220-
unsigned long amountRead_;
221-
unsigned long long amountWritten_;
222-
unsigned int type_;
212+
Descriptor *lobLocator_;
213+
unsigned short fetchType_;
214+
215+
Connection *njsconn_;
216+
dpi::Conn *dpiconn_;
217+
DpiHandle *svch_;
218+
DpiHandle *errh_;
219+
bool isValid_;
220+
State state_;
221+
222+
char *buf_;
223+
unsigned int bufSize_;
224+
unsigned int chunkSize_;
225+
unsigned long long length_;
226+
unsigned long long offset_;
227+
unsigned long amountRead_;
228+
unsigned long long amountWritten_;
229+
unsigned int type_;
230+
Nan::Persistent<Object> jsParent_;
223231
};
224232

225233
#endif /** __NJSILOB_H__ **/

src/njs/src/njsOracle.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ NAN_METHOD(Oracledb::GetConnection)
717717
NJS_GET_CALLBACK ( callback, info );
718718

719719
Oracledb* oracledb = Nan::ObjectWrap::Unwrap<Oracledb> ( info.Holder() );
720-
connectionBaton *connBaton = new connectionBaton ( callback );
720+
connectionBaton *connBaton = new connectionBaton ( callback, info.Holder() );
721721

722722
NJS_CHECK_OBJECT_VALID3 (oracledb, connBaton->error, exitGetConnection);
723723

@@ -835,7 +835,8 @@ void Oracledb::Async_AfterGetConnection (uv_work_t *req)
835835
Local<Object> connection = lft->GetFunction()-> NewInstance();
836836
(Nan::ObjectWrap::Unwrap<Connection> (connection))->
837837
setConnection( connBaton->dpiconn,
838-
connBaton->oracledb );
838+
connBaton->oracledb,
839+
Nan::New( connBaton->jsOradb ) );
839840
argv[1] = connection;
840841
}
841842
Local<Function> callback = Nan::New<Function>(connBaton->cb);
@@ -867,7 +868,7 @@ NAN_METHOD(Oracledb::CreatePool)
867868
NJS_GET_CALLBACK ( callback, info );
868869

869870
Oracledb* oracledb = Nan::ObjectWrap::Unwrap<Oracledb> ( info.Holder() );
870-
connectionBaton *poolBaton = new connectionBaton ( callback );
871+
connectionBaton *poolBaton = new connectionBaton ( callback, info.Holder() );
871872

872873
NJS_CHECK_OBJECT_VALID3(oracledb, poolBaton->error, exitCreatePool);
873874

@@ -992,14 +993,16 @@ void Oracledb::Async_AfterCreatePool (uv_work_t *req)
992993
argv[0] = Nan::Undefined();
993994
Local<Object> njsPool = Nan::New(Pool::poolTemplate_s)->
994995
GetFunction() ->NewInstance();
995-
(Nan::ObjectWrap::Unwrap<Pool> (njsPool))-> setPool ( poolBaton->dpipool,
996-
poolBaton->oracledb,
997-
poolBaton->poolMax,
998-
poolBaton->poolMin,
999-
poolBaton->poolIncrement,
1000-
poolBaton->poolTimeout,
1001-
poolBaton->stmtCacheSize,
1002-
poolBaton->lobPrefetchSize);
996+
(Nan::ObjectWrap::Unwrap<Pool> (njsPool))-> setPool (
997+
poolBaton->dpipool,
998+
poolBaton->oracledb,
999+
poolBaton->poolMax,
1000+
poolBaton->poolMin,
1001+
poolBaton->poolIncrement,
1002+
poolBaton->poolTimeout,
1003+
poolBaton->stmtCacheSize,
1004+
poolBaton->lobPrefetchSize,
1005+
Nan::New( poolBaton->jsOradb ) );
10031006
argv[1] = njsPool;
10041007
}
10051008
Local<Function> callback = Nan::New(poolBaton->cb);

0 commit comments

Comments
 (0)