Page 1 of 1

Zeos connection library caching

Posted: 02.02.2024, 18:38
by aehimself
I know we already talked about this but this time I'm bringing a solution proposal too.

The thing is, Zeos is automatically caching driver libraries, leaving the handles open even after a connection to a database is closed. You can reproduce the "issue" quite easily: drop a TZConnection on a form, set it to a database of your choice, finally call ZConnection1.Connect and ZConnection1.Disconnect right after it. Once the application is running, try to delete the driver .dll - it won't work as your program is still using it.

Caching is done in the TZAbstractDriver level and the cache can manually be cleared (therefore handles released) like this:

Code: Select all

Type
  THackAbstractDriver = Class(TZAbstractDriver);

Var
  drivers: IZCollection;
  driver: TZAbstractDriver;
  a: Integer;
Begin
  drivers := DriverManager.GetDrivers;

  For a := 0 To drivers.Count - 1 Do
  Begin
    driver := drivers[a] As TZAbstractDriver;

    THackAbstractDriver(driver).FCachedPlainDrivers.Clear;
  End;
End;
To be honest I don't know why this was implemented at the first place as loading the library will only be a fraction of the time spent compared to actually establisthing the connection but as I'm not questioning the viability of such cache. As I can not imagine a scenario when switching between cached and non-cached mode is actually needed I suggest to create a conditional directive like ZEOS_DISABLE_DRIVER_CACHE. When defined, I'd not even create the FCachedPlainDrivers instances to save some more resources.

What do you guys think about this solution? If agreed I can create a pull request even tonight with the changes.

Re: Zeos connection library caching

Posted: 02.02.2024, 19:46
by aehimself
As it turns out FCachedPlainDrivers has to stay as the initial ones are stored here too.
So the only thing the conditional directive would do is to disable line 977 in ZDbcConnection.pas

Code: Select all

      {$IFNDEF ZEOS_DISABLE_DRIVER_CACHE}AddPlainDriverToCache(Result, Protocol, LibLocation);{$ENDIF}
Tested, works as planned.

Re: Zeos connection library caching

Posted: 02.02.2024, 21:01
by aehimself
I opened two pull requests on GitHub: one for master branch, one for 7.2-patches.

Changes are exactly the same, but this feature can be ported to 7.2 - that's why the second one :)

Re: Zeos connection library caching

Posted: 08.02.2024, 22:41
by Scalmax
aehimself wrote: 02.02.2024, 18:38 As I can not imagine a scenario when switching between cached and non-cached mode is actually needed I suggest to create a conditional directive like ZEOS_DISABLE_DRIVER_CACHE. When defined, I'd not even create the FCachedPlainDrivers instances to save some more resources.

What do you guys think about this solution? If agreed I can create a pull request even tonight with the changes.
1. More elastic solution would be to pass parameter on function/procedure call or even add procedure to clean the cache from what is clean-able.
2. You will never know all of the wet dark dreams of the managers of the Zeos users :)

Despite this obvious whining you have a working solution, which is good.

Re: Zeos connection library caching

Posted: 08.02.2024, 23:46
by aehimself
Scalmax wrote: 08.02.2024, 22:411. More elastic solution would be to pass parameter on function/procedure call or even add procedure to clean the cache from what is clean-able.
You definetly can clear the cache on-demand, see the snipplet in my first post. The reason I did not include this is I did not find a way to determine whether a driver is still in use or not - either I kill all or none.
We safely can purge the cache even every second though - due to how interfaces work an active connection will always keep it's refcount high and won't cause any connection drops (tested).
Scalmax wrote: 08.02.2024, 22:412. You will never know all of the wet dark dreams of the managers of the Zeos users :)
As I mentioned previously I simply can not imagine a project which sometimes need library caching, sometimes not. Your app either:
- Connects to a DB, does it's work and quits: doesn't matter as handles are released upon exit anyway
- Connects to the same DB, does it's work and disconnects: caching would make sense however loading the library is extremely quick. I doubt there would be a real performance drop without caching
- Connects to different DBs, does it's work and disconnects: caching makes no sense as each connection might be using a different library, rendering caching effectively irrelevant
- Connects to the same set of DBs, does it's work and disconnects: same arguement as #2

In any case I already mentioned I'm not questioning the existence of a library cache. We have a way to manually clear the cache in case of more complicated approaches, now Zeos can provide a way to disable it alltogether for simple cases. With these two available we can cover all scenarios I suppose.