8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 04:03:04 +01:00

Better handling for the scratch pool and fixed CORE-5646.

CORE-5646 - Parse error when compiling a statement causes memory leak until attachment is disconnected.
This commit is contained in:
Adriano dos Santos Fernandes 2017-10-22 15:46:34 -02:00
parent 0abddf94e0
commit 5e1b5e172e
4 changed files with 58 additions and 38 deletions

View File

@ -586,7 +586,7 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr
}
void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult)
{
{ // scope
@ -671,9 +671,9 @@ void DsqlDmlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
if (status)
status_exception::raise(tdbb->tdbb_status_vector);
// Delete the scratch pool to reclaim memory.
// We don't need the scratch pool anymore. Tell our caller to delete it.
node = NULL;
req_dbb->deletePool(&scratch->getPool());
*destroyScratchPool = true;
}
// Execute a dynamic SQL statement.
@ -829,7 +829,7 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
trace.finish(have_cursor, ITracePlugin::RESULT_SUCCESS);
}
void DsqlDdlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
void DsqlDdlRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult)
{
internalScratch = scratch;
@ -914,7 +914,7 @@ void DsqlDdlRequest::rethrowDdlException(status_exception& ex, bool metadataUpda
}
void DsqlTransactionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
void DsqlTransactionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* /*traceResult*/)
{
node = Node::doDsqlPass(scratch, node);
@ -933,7 +933,7 @@ void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
}
void DsqlSessionManagementRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
void DsqlSessionManagementRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* /*traceResult*/)
{
node = Node::doDsqlPass(scratch, node);
@ -1400,24 +1400,24 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
// allocate the statement block, then prepare the statement
Jrd::ContextPoolHolder statementContext(tdbb, database->createPool());
MemoryPool& statementPool = *tdbb->getDefaultPool();
DsqlCompiledStatement* statement = FB_NEW_POOL(statementPool) DsqlCompiledStatement(statementPool);
MemoryPool* scratchPool = database->createPool(&statementPool);
DsqlCompilerScratch* scratch = FB_NEW_POOL(*scratchPool) DsqlCompilerScratch(*scratchPool, database,
transaction, statement);
scratch->clientDialect = clientDialect;
if (isInternalRequest)
scratch->flags |= DsqlCompilerScratch::FLAG_INTERNAL_REQUEST;
MemoryPool* statementPool = database->createPool();
MemoryPool* scratchPool = NULL;
dsql_req* request = NULL;
Jrd::ContextPoolHolder statementContext(tdbb, statementPool);
try
{
DsqlCompiledStatement* statement = FB_NEW_POOL(*statementPool) DsqlCompiledStatement(*statementPool);
scratchPool = database->createPool();
DsqlCompilerScratch* scratch = FB_NEW_POOL(*scratchPool) DsqlCompilerScratch(*scratchPool, database,
transaction, statement);
scratch->clientDialect = clientDialect;
if (isInternalRequest)
scratch->flags |= DsqlCompilerScratch::FLAG_INTERNAL_REQUEST;
string transformedText;
{ // scope to delete parser before the scratch pool is gone
@ -1429,6 +1429,7 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
// Parse the SQL statement. If it croaks, return
request = parser.parse();
request->liveScratchPool = scratchPool;
if (parser.isStmtAmbiguous())
scratch->flags |= DsqlCompilerScratch::FLAG_AMBIGUOUS_STMT;
@ -1473,12 +1474,12 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
transformedText.assign(temp.begin(), temp.getCount());
}
statement->setSqlText(FB_NEW_POOL(statementPool) RefString(statementPool, transformedText));
statement->setSqlText(FB_NEW_POOL(*statementPool) RefString(*statementPool, transformedText));
// allocate the send and receive messages
statement->setSendMsg(FB_NEW_POOL(statementPool) dsql_msg(statementPool));
dsql_msg* message = FB_NEW_POOL(statementPool) dsql_msg(statementPool);
statement->setSendMsg(FB_NEW_POOL(*statementPool) dsql_msg(*statementPool));
dsql_msg* message = FB_NEW_POOL(*statementPool) dsql_msg(*statementPool);
statement->setReceiveMsg(message);
message->msg_number = 1;
@ -1490,7 +1491,14 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
ntrace_result_t traceResult = ITracePlugin::RESULT_SUCCESS;
try
{
request->dsqlPass(tdbb, scratch, &traceResult);
bool destroyScratchPool = false;
request->dsqlPass(tdbb, scratch, &destroyScratchPool, &traceResult);
if (destroyScratchPool)
{
database->deletePool(scratchPool);
request->liveScratchPool = scratchPool = NULL;
}
}
catch (const Exception&)
{
@ -1510,6 +1518,14 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra*
request->req_traced = false;
dsql_req::destroy(tdbb, request, true);
}
else
{
if (scratchPool)
database->deletePool(scratchPool);
if (statementPool)
database->deletePool(statementPool);
}
throw;
}
@ -1577,6 +1593,7 @@ static void release_statement(DsqlCompiledStatement* statement)
dsql_req::dsql_req(MemoryPool& pool)
: req_pool(pool),
statement(NULL),
liveScratchPool(NULL),
cursors(req_pool),
req_dbb(NULL),
req_transaction(NULL),
@ -1772,7 +1789,12 @@ void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
// Release the entire request if explicitly asked for
if (drop)
{
request->req_dbb->deletePool(&request->getPool());
if (request->liveScratchPool)
request->req_dbb->deletePool(request->liveScratchPool);
}
}

View File

@ -163,9 +163,9 @@ public:
~dsql_dbb();
MemoryPool* createPool(MemoryPool* parent = NULL)
MemoryPool* createPool()
{
return dbb_attachment->createPool(parent);
return dbb_attachment->createPool();
}
void deletePool(MemoryPool* pool)
@ -490,8 +490,6 @@ public:
}
public:
MemoryPool& getPool() { return PermanentStorage::getPool(); }
Type getType() const { return type; }
void setType(Type value) { type = value; }
@ -573,7 +571,7 @@ public:
return statement;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult) = 0;
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
@ -611,6 +609,7 @@ private:
public:
const DsqlCompiledStatement* statement;
MemoryPool* liveScratchPool;
Firebird::Array<DsqlCompiledStatement*> cursors; // Cursor update statements
dsql_dbb* req_dbb; // DSQL attachment
@ -651,7 +650,7 @@ public:
{
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
@ -681,7 +680,7 @@ public:
{
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
@ -708,7 +707,7 @@ public:
req_traced = false;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
@ -730,7 +729,7 @@ public:
req_traced = false;
}
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool,
ntrace_result_t* traceResult);
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,

View File

@ -111,11 +111,10 @@ void Jrd::Attachment::destroy(Attachment* const attachment)
}
MemoryPool* Jrd::Attachment::createPool(MemoryPool* parent)
MemoryPool* Jrd::Attachment::createPool()
{
MemoryPool* const pool = MemoryPool::createPool(parent ? parent : att_pool, att_memory_stats);
if (!parent)
att_pools.add(pool);
MemoryPool* const pool = MemoryPool::createPool(NULL, att_memory_stats);
att_pools.add(pool);
return pool;
}

View File

@ -374,7 +374,7 @@ public:
Firebird::Array<MemoryPool*> att_pools; // pools
MemoryPool* createPool(MemoryPool* parent = NULL);
MemoryPool* createPool();
void deletePool(MemoryPool* pool);
/// former Database members - end