[odb-users] Sessions are not useful for application-wide purposes

Boris Kolpackov boris at codesynthesis.com
Thu Nov 8 10:04:46 EST 2012


Hi Rene,

Rene Jensen <rene at catatonic.dk> writes:

> Such demands doesn't rhyme well with ODB's concept of sessions. Again, the
> problems sessions solve are:
>
> 1) They provide a way to ensure the same entity is not loaded twice.
> 2) They keep objects cached in memory.

Well, the second just follows from the first. I.e., we need to keep
objects around if we want to avoid loading them from the database
all the time.


> The latter presents a problem: The obvious way to control uniqueness of
> classes in memory would be to use an application-wide session. But that
> would keep all touched objects alive forever.

The session as implemented in ODB (i.e., odb::session) wasn't designed
for this purpose. Rather, its goal is to help with the so-called
"application transactions", i.e., an application unit of work that
can span multiple database transactions. For example: 

1. Start a db transaction and load the Plane object.
2. Show the use available seats and wait for selection.
3. Start another transaction and update the Plane object (sitting
   in the cache) with selected seats.

In this example we would create a session at the beginning and
then destroy it at the end. So session is normally longer-lived
than a single transaction but is still relatively short-lived.

Specifically, odb::session is not particularly suitable as an
application-wide, long-lived object cache because:

1. as you have mentioned, there is no control over how long objects
   are retained in the cache,

2. but also, odb::session is not thread-safe

So it looks to me that instead of trying to re-purpose odb::session
for what it wasn't made, it would be easier to just provide your
own application-wide cache where you can control object lifetime,
etc.

In fact, there is nothing that prevents you from doing this right now.
You can always check such a cache before calling database::load(). The
only potential issue that I see is recursive object loading.

To address this we could probably provide a way to integrate such custom
cache into ODB so that it is automatically queried from within load()
(i.e., we can define a session interface and make odb::session just one
possible implementation).

Another option would be to provide another variant of session that is
thread-safe and allows for user control of object retention (e.g., a
callback that is called before every insertion that allows you to
evict some objects).

> FIRST SOLUTION:
> Invent a "weak session cache", i.e. one that consists of weak pointers
> (raising issues of atomicity of checks etc... but usually GUI programs has
> just one GUI thread and a bunch of isolated workers). With such a session,
> you could achieve (1) but leave it to the model AND view classes to handle
> (2).

We cannot assume (a) that all smart pointers used as object pointers have
weak counterparts and (b) there are no multi-threading issued (i.e., that
all applications are like yours ;-)).


> SECOND SOLUTION:
> Let ODB use external factories for creating objects. Those factories could
> communicate with an application-wide pool of weak pointers that was under
> user control

Well, that sounds pretty much the same as the custom session approach.


> THIRD SOLUTION:
> Use inner structs for database data and only store pointers to those in the
> model classes. That way the application code can keep its own tables for
> converting those proxy-objects to real model classes when needed.
> This is the solution I was forced to go with. I don't like it because there
> is a huge maintenance burden and only a small gain in freedom.

Yes, that doesn't sound very clean. I assume you looked at the pimpl
example which would probably make this a bit more palatable.

Boris



More information about the odb-users mailing list