Discussion:
[Firebird-devel] Memory Pool Question
Jim Starkey
2004-01-12 13:32:09 UTC
Permalink
Are destructors on objects allocated from memory pools called?
--
Jim Starkey
Netfrastructure, Inc.
978 526-1376
Samofatov, Nickolay
2004-01-12 17:48:01 UTC
Permalink
Hi, Jim!
Post by Jim Starkey
Are destructors on objects allocated from memory pools called?
No. If you kill the pool and need to adjust links/dependencies of pool
owner at the same time then you need to do this manually.
Post by Jim Starkey
Jim Starkey
Nickolay
Jim Starkey
2004-01-12 18:10:01 UTC
Permalink
Post by Samofatov, Nickolay
Hi, Jim!
Post by Jim Starkey
Are destructors on objects allocated from memory pools called?
No. If you kill the pool and need to adjust links/dependencies of pool
owner at the same time then you need to do this manually.
Nickolay, that isn't going to fly. A major strength of C++ is the idea
that objects clean up after themselves, automatically releasing memory
and other resources. This is excellent language design and excellent
software engineering. It encapsulates resource management, reducing
code size, bugs (as if the two were not intimately related!), and memory
leaks. The pool mechanism kills this.

I am using the destructor mechanism in Vulcan for its intended purpose,
which is clean and systematic dismantling of an object. Since I cannot
have both pools and destructors, I choose destructors.

This leaves me with two types of classes, those that conform to C++
usage and legacy classes that depend on pools. While I do not plan a
systematic shift of classes from legacy to C++, I am creating new
classes, including encapsulations of existing classes, outside the pool
structure so I can have the benefit of destructors. I expect syntax and
general language nodes to stay inside the pool structure until a major
overhaul, but other classes are coming out, probably sooner than later.

I appreciate the very hard work many people put into changing the code
base from C to C++. Now is the time to take advantage of the power that
C++ brings to the table.
--
Jim Starkey
Netfrastructure, Inc.
978 526-1376
John Bellardo
2004-01-12 22:29:01 UTC
Permalink
Jim,

Let me clarify Nickolay's point.
Post by Jim Starkey
Post by Samofatov, Nickolay
Post by Jim Starkey
Are destructors on objects allocated from memory pools called?
No. If you kill the pool and need to adjust links/dependencies of pool
owner at the same time then you need to do this manually.
Nickolay, that isn't going to fly. A major strength of C++ is the
idea that objects clean up after themselves, automatically releasing
memory and other resources. This is excellent language design and
excellent software engineering. It encapsulates resource management,
reducing code size, bugs (as if the two were not intimately related!),
and memory leaks. The pool mechanism kills this.
I am using the destructor mechanism in Vulcan for its intended
purpose, which is clean and systematic dismantling of an object.
Since I cannot have both pools and destructors, I choose destructors.
This leaves me with two types of classes, those that conform to C++
usage and legacy classes that depend on pools. While I do not plan a
systematic shift of classes from legacy to C++, I am creating new
classes, including encapsulations of existing classes, outside the
pool structure so I can have the benefit of destructors. I expect
syntax and general language nodes to stay inside the pool structure
until a major overhaul, but other classes are coming out, probably
sooner than later.
I appreciate the very hard work many people put into changing the code
base from C to C++. Now is the time to take advantage of the power
that C++ brings to the table.
If you delete an object using "delete <ptr>" the destructor will be
called, and then the memory will be reclaimed by the pool. If you
delete a pool, the pool will free all of its memory without regard to
the objects (and hence the destructors) contained within the pool. So
C++ destructors still work.

-John
Jim Starkey
2004-01-13 00:08:01 UTC
Permalink
Post by John Bellardo
If you delete an object using "delete <ptr>" the destructor will be
called, and then the memory will be reclaimed by the pool. If you
delete a pool, the pool will free all of its memory without regard to
the objects (and hence the destructors) contained within the pool. So
C++ destructors still work.
I was perhaps a little terse with Nickolay -- the discovery that DSQL
and the engine shared the same thread data slot kinda a loused up my
afternoon.

I think it's very important that destructors are reliably called. It
isn't reasonable to expect developers to remember which types of objects
have reliable destructors, which have unreliable destructors, and which
have destructors that are never called. You have to admit that it does
had a layer of muddle that would be better off avoiding.

But here is another problem with pools -- memory efficiency. As
originally designed, the temporary pools were short lived. Each request
had a dedicated pool that live only between compile_request and
release_request. DSQL added a second temporary pool, but with an
equivalent lifetime. Pools where never memory efficient. Memory was
allocated to pools in large hunks, so over allocate was a certainly, on
average, half the hunk size. Furthermore, request processing (both blr
and dsql) involved a parse tree, miscellaneous work products like
strings, and an execution tree. For dsql, a blr request was then
compiled. But when the statement was released, the whole shebang
evaporated, so the memory inefficiency was short lived.

In our brave new world, a dsql statement (a DStatement object) either
finds an existing compiled statement (CStatement) or creates and
prepares a new one. But where now the respective statements and
requests are immediately released for recycling, now the CStatement
along with its compiled BLR request takes up long term residence in the
compiled statement cache in hopes of being of service for a future
identical SQL string. Now the memory efficiency begins to hurt. The
last half used hunk is wasted. The unreleased dsql syntax and language
nodes are wasted. The last half hunk in the compiled blr hunk is
wasted. The generated blr string is wasted. The blr parse treee is
wasted. When all is said and done, 90% of the memory used during
preparation and compilation of the request is lost to save the precious
10% (or less) actually consumed by the exe and rsb trees.

It wasn't my intention to implement a compiled statement cache, but it
wasn't really possible to implement CStatement any other way. All
CStatement has to do is bump its use count and insert itself into a SQL
string hash table, and we're there. The existing request level
instantiation (one request, many impure areas) handles multiple
instantiations of the request.

Ann will tell you that I'm a child of the computing depression, that I
worried myself sick over every extra byte so my PDP-11 Datatrieve users
could have a little more space for their obsurdly complicated systems.
I do argue over and over than memory is huge and almost free, but I hate
the idea of wasting it.

OK, I suppose we could have separate compile and execute pools for both
dsql statements and blr requests. But if by reasonable use of
destructors we can signficantly reduce the amount of memory wasted by
cached compiled statements, we're way ahead of the game. As I said
before, no matter how fast the compiler is, not compiling will always be
much, much faster.
Arno Brinkman
2004-01-13 06:20:01 UTC
Permalink
Hi,

<snip>
Post by Jim Starkey
It wasn't my intention to implement a compiled statement cache, but it
wasn't really possible to implement CStatement any other way. All
CStatement has to do is bump its use count and insert itself into a SQL
string hash table, and we're there. The existing request level
instantiation (one request, many impure areas) handles multiple
instantiations of the request.
This meant statements below will still need to be compiled all and none can
use a previous compiled statement from the other? :

- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?


Regards,
Arno Brinkman
ABVisie

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Firebird links :
http://www.firebirdsql.com
http://www.firebirdsql.info
http://www.fingerbird.de/
http://www.comunidade-firebird.org/


Nederlandse firebird nieuwsgroep :
news://80.126.130.81
Dmitry Yemanov
2004-01-13 07:05:01 UTC
Permalink
Post by Arno Brinkman
This meant statements below will still need to be compiled all and none can
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?
I don't know any RDBMS that can use a single compiled request for these
statements. Even more, putting an extra whitespace character into either of
these statements will cause yet another compiled request to be generated.
The Oracle documentation explicitly states this fact.


Dmitry
Arno Brinkman
2004-01-13 10:34:01 UTC
Permalink
Post by Dmitry Yemanov
Post by Arno Brinkman
This meant statements below will still need to be compiled all and none
can
Post by Arno Brinkman
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?
I don't know any RDBMS that can use a single compiled request for these
statements. Even more, putting an extra whitespace character into either of
these statements will cause yet another compiled request to be generated.
The Oracle documentation explicitly states this fact.
I understand that data is different, but the "retrieve" part is the same for
both.
Possible it's to difficult to implement :-(

Regards,
Arno Brinkman
ABVisie

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Firebird open source database (based on IB-OE) with many SQL-99 features :
http://www.firebirdsql.org
http://www.firebirdsql.info
http://www.fingerbird.de/
http://www.comunidade-firebird.org/

Support list for Interbase and Firebird users :
firebird-***@yahoogroups.com

Nederlandse firebird nieuwsgroep :
news://80.126.130.81
Martijn Tonies
2004-01-13 10:43:01 UTC
Permalink
Post by Arno Brinkman
Post by Dmitry Yemanov
Post by Arno Brinkman
This meant statements below will still need to be compiled all and none
can
Post by Arno Brinkman
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?
I don't know any RDBMS that can use a single compiled request for these
statements. Even more, putting an extra whitespace character into either
of
Post by Dmitry Yemanov
these statements will cause yet another compiled request to be generated.
The Oracle documentation explicitly states this fact.
I understand that data is different, but the "retrieve" part is the same for
both.
Possible it's to difficult to implement :-(
Is it? Can data-compare literals be replaced by parameters internally?
And bind them after that?

What you would be doing then, is adding another layer that parses these
and then you can compare it to other "in the buffer" SQL statement.

Would the SQL text be compared, or the BLR? Or is generating the BLR
exactly what takes the most time?

With regards,

Martijn Tonies
Database Workbench - developer tool for InterBase, Firebird, MySQL & MS SQL
Server.
Upscene Productions
http://www.upscene.com
Arno Brinkman
2004-01-13 10:56:01 UTC
Permalink
Hi Martijn,

<snip>
Post by Martijn Tonies
Post by Arno Brinkman
I understand that data is different, but the "retrieve" part is the same
for
Post by Arno Brinkman
both.
Possible it's to difficult to implement :-(
Is it? Can data-compare literals be replaced by parameters internally?
And bind them after that?
I'm afraid it isn't that simple.
Post by Martijn Tonies
What you would be doing then, is adding another layer that parses these
and then you can compare it to other "in the buffer" SQL statement.
Would the SQL text be compared, or the BLR? Or is generating the BLR
exactly what takes the most time?
Suggested was SQL-text, because this saves compile and prepare time.

Maybe this needs an other cache between compiler and optimizer?

Regards,
Arno Brinkman
ABVisie

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Firebird open source database (based on IB-OE) with many SQL-99 features :
http://www.firebirdsql.org
http://www.firebirdsql.info
http://www.fingerbird.de/
http://www.comunidade-firebird.org/

Support list for Interbase and Firebird users :
firebird-***@yahoogroups.com

Nederlandse firebird nieuwsgroep :
news://80.126.130.81
Jim Starkey
2004-01-13 13:42:06 UTC
Permalink
Post by Martijn Tonies
Post by Arno Brinkman
both.
Possible it's to difficult to implement :-(
Is it? Can data-compare literals be replaced by parameters internally?
And bind them after that?
What you would be doing then, is adding another layer that parses these
and then you can compare it to other "in the buffer" SQL statement.
Would the SQL text be compared, or the BLR? Or is generating the BLR
exactly what takes the most time?
A full semantic analysis is a pretty expenseive way to search a cache,
and buys very little. Programs present the same SQL strings time after
time (unless they generate them with embedded data). It's far cheaper
to retain two insignificant variants than to perform a semantic
analysis. The point, remember, is to avoid parsing the SQL statement.
--
Jim Starkey
Netfrastructure, Inc.
978 526-1376
Ann W. Harrison
2004-01-13 17:35:03 UTC
Permalink
A full semantic analysis is a pretty expenseive way to search a cache, and
buys very little. Programs present the same SQL strings time after time
(unless they generate them with embedded data). It's far cheaper to
retain two insignificant variants than to perform a semantic
analysis. The point, remember, is to avoid parsing the SQL statement.
Would it be possible to replace double spaces, tabs, line feeds, etc. with
a single white space before caching the request or checking the cache?

Regards,


Ann
Jim Starkey
2004-01-13 13:29:03 UTC
Permalink
Post by Arno Brinkman
Hi,
<snip>
Post by Jim Starkey
It wasn't my intention to implement a compiled statement cache, but it
wasn't really possible to implement CStatement any other way. All
CStatement has to do is bump its use count and insert itself into a SQL
string hash table, and we're there. The existing request level
instantiation (one request, many impure areas) handles multiple
instantiations of the request.
This meant statements below will still need to be compiled all and none can
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?
That's correct.

Netfrastructure uses a very simple heustistic to decide whether to
retain a compiled statement: If it has a parameter ('?"), it saves it.
Otherwise it throws it away. Although it transparent to programmers,
they get the message after on explanation.

Netfrastructure goes out of its way to make it convenient to use the
parameter form rather than generating a unique SQL statement.
Netfrastructure also uses JDBC as it's only API, including all internal
usage. Parameters are much easier to use in JDBC than the "native" DSQL
interface or ODBC, which is a pity or an opportunity, depending on your
mindset.

But programmers are very performance oriented, and generally more than
willing to conform to a reasonable practice if their systems go faster
as a result.
--
Jim Starkey
Netfrastructure, Inc.
978 526-1376
Samofatov, Nickolay
2004-01-13 00:54:01 UTC
Permalink
Hi, Jim!
Post by Jim Starkey
I think it's very important that destructors are reliably called. It
isn't reasonable to expect developers to remember which types of
objects
Post by Jim Starkey
have reliable destructors, which have unreliable destructors, and
which
Post by Jim Starkey
have destructors that are never called. You have to admit that it
does
Post by Jim Starkey
had a layer of muddle that would be better off avoiding.
I cannot agree about destructors. I think you may have objects that may
be dropped out of memory with their pools. All container templates that
were written by me and Alex allow this plus most other objects can be
used this way. There is some muddle, true, but in fact this is mostly
obvious. Any stand-alone object designed for firebird pools should be
possible to drop without destructor.
Post by Jim Starkey
OK, I suppose we could have separate compile and execute pools for
both
Post by Jim Starkey
dsql statements and blr requests. But if by reasonable use of
destructors we can signficantly reduce the amount of memory wasted by
cached compiled statements, we're way ahead of the game.
Pool used by DSQL compiler is temporary by nature so it is out of the
memory efficiency question. Pools help to isolate memory leaks and give
performance benefits (since you don't need to walk over the nodes to
delete them).

Presence of executable requests pools is, in turn, critical for
performance. Request pool is used to hold transient data related to
request (currently, all instances of it, but this may need to be changed
to per-connection assignment if requests cache is introduced). Since
this data is tightly packed together cache-hit ratio is high. This is
one of the reasons why 1.5 engine works fast. Remember about millions
allocations/deallocations performed during execution of queries? In
addition, pools help to minimize contention on allocator locks.
Post by Jim Starkey
As I said
before, no matter how fast the compiler is, not compiling will always
be
Post by Jim Starkey
much, much faster.
I can also add that no matter how fast computers are not making them
doing unnecessary work will make them work faster. There is no need to
walk over DSQL node tree to delete it. :)

This comes from my 8086 4.77 Mhz times... :)

Nickolay Samofatov
Nando Dessena
2004-01-13 11:06:00 UTC
Permalink
Martijn et al,
Post by Arno Brinkman
I understand that data is different, but the "retrieve" part is the same
M> for
Post by Arno Brinkman
both.
Possible it's to difficult to implement :-(
M> Is it? Can data-compare literals be replaced by parameters internally?
M> And bind them after that?

M> What you would be doing then, is adding another layer that parses these
M> and then you can compare it to other "in the buffer" SQL statement.

M> Would the SQL text be compared, or the BLR? Or is generating the BLR
M> exactly what takes the most time?

I may be completely off track here, but perhaps a two level caching
system would help here. Or, better, a caching system with two access
points. Look for your compiled statement starting with the (hash of
the) SQL text and, if you don't find it, then parse the text and look
for the <whatever> in the cache. If not found then compile anew.

Now, I have no idea what the <whatever> would look like. Comparing
trees does not strike me as a very efficient practive, nor I can
imagine how to hash a tree. Perhaps others can.

Ciao
--
Nando mailto:***@dedonline.com
Steven Shaw
2004-01-13 12:28:01 UTC
Permalink
Post by Jim Starkey
Are destructors on objects allocated from memory pools called?
I'm not sure but if placement-new is used then no. If placement new is used
then destructor can be called manually if required.

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
Samofatov, Nickolay
2004-01-13 14:14:00 UTC
Permalink
Hi, Dmitry, Jim!
Post by Dmitry Yemanov
Post by Arno Brinkman
This meant statements below will still need to be compiled all and
none
Post by Dmitry Yemanov
can
Post by Arno Brinkman
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 1
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = 2
- SELECT FieldA, FieldB FROM TableX WHERE FieldC = ?
I don't know any RDBMS that can use a single compiled request for
these
Post by Dmitry Yemanov
statements. Even more, putting an extra whitespace character into
either
Post by Dmitry Yemanov
of
these statements will cause yet another compiled request to be
generated.
Post by Dmitry Yemanov
The Oracle documentation explicitly states this fact.
DB2/400 can, for sure. I tested it. But DB2 optimizer does that because
some of its optimizations are highly expensive.
Post by Dmitry Yemanov
Dmitry
Nickolay
Paul Beach
2004-01-13 14:21:03 UTC
Permalink
<<DB2/400 can, for sure. I tested it. But DB2 optimizer does that because
some of its optimizations are highly expensive.>>

Is that generic for DB2 or just specific to DB2/400? And by referring to
DB2/400
are we referring to DB2 running on an AS400?

Regards
Paul
Sergio Samayoa
2004-01-13 17:54:02 UTC
Permalink
I second the motion.
It could be pre-compile phase of the SQL compiler.
-----Mensaje original-----
Harrison
Enviado el: Martes, 13 de Enero de 2004 01:40 p.m.
Para: Jim Starkey; Martijn Tonies
CC: Firebird-devel
Asunto: Re: [Firebird-devel] Memory Pool Question
Post by Jim Starkey
A full semantic analysis is a pretty expenseive way to search a
cache, and
Post by Jim Starkey
buys very little. Programs present the same SQL strings time after time
(unless they generate them with embedded data). It's far cheaper to
retain two insignificant variants than to perform a semantic
analysis. The point, remember, is to avoid parsing the SQL statement.
Would it be possible to replace double spaces, tabs, line feeds, etc. with
a single white space before caching the request or checking the cache?
Regards,
Ann
-------------------------------------------------------
This SF.net email is sponsored by: Perforce Software.
Perforce is the Fast Software Configuration Management System offering
advanced branching capabilities and atomic changes on 50+ platforms.
Free Eval! http://www.perforce.com/perforce/loadprog.html
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel
Loading...