Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start building a searchable garbage collector in Delphi (2009-2010)

I'm looking for a way to control all business objects I create in my applications written in Delphi.

As an article on Embarcadero's EDN (http://edn.embarcadero.com/article/28217) states, there are basically three ways to do this. I'm mostly interested in the last one, using interfaces. That way, when the business object is no longer being referenced anywhere in the application, it will be dispose of memory wise (I'll get back on this part later).

When creating a new business object, it would be wise to ask that new object manager whether I already fetched it earlier in the program, thus avoid the need to refetch it from the database. I already have the business object in memory, so why not use that one? Thus I'll need the list of available objects in memory to be searchable (fast).

The provided code there uses an "array of TObject" to store the collected objects, which doesn't make it very performant concerning searches through the list of objects once you get to a certain amount. I would have to change that to either TObjectList or some sort of binary searchable tree. What would be the best choice here? I already found some useful code (I think) at http://www.ibrtses.com/delphi/binarytree.html. Didn't JCL have stuff on binary trees?

How would I handle "business objects" and "lists of business objects" in that tree? Would a business object, being part of a list be referenced twice in the tree?

Concerning the disposing of an object: I also want to set some sort of TTL (time to life) to that business object, forcing a refetch after an certain amount of time. Should the reference counter fall to 0, I still want to keep the object there for a certain amount of time, should the program still want it within the TTL. That means I'll need sort sort of threaded monitor looping the object list (or tree) to watch for to-be-deleted objects.

I also came across the Boehm Garbage Collector DLL (http://codecentral.embarcadero.com/Download.aspx?id=21646).

So in short, would it be wise to base my "object manager" on the source code provided in the EDN article? What kind of list would I want to store my objects in? How should I handle list of objects in my list? And should I still keep my object in memory for a while and have it dispose of by a threaded monitor?

Am I correct in my reasoning? Any suggestions, ideas or remarks before I start coding? Maybe some new ideas to incorporate into my code?

Btw, I'd be happy to share the result, for others to benefit, once some brilliant minds gave it a thought.

Thnx.

like image 213
Brave Cobra Avatar asked Jan 26 '10 06:01

Brave Cobra


2 Answers

If you are using Interfaces for reference counting, and then stick those in a collection of some sort, then you will always have a reference to them. If your objective is "garbage collection" then you only need one or the other, but you can certainly use both if necessary.

What it sounds like you really want is a business object cache. For that you will want to use one of the new generic TDictionary collections. What you might want to do is have a TDictionary of TDictionary collections, one TDictionary for each of your object types. You could key your main TDictionary on an enumeration, or maybe even on the type of the object itself (I haven't tried that, but it might work.) If you are using GUIDs for your unique identifiers then you can put them all in a single TDictionary.

Implement each of your business objects with an interface. You don't need to use Smart Pointers since you are designing your business objects and can descend them from TInterfacedObject. Then only reference it by its interface, so it can be reference counted.

If you want to expire your cache then you will need to have some sort of timestamp on your objects that gets updated each time an object is retrieved from the cache. Then when the cache gets over some specific size you can prune everything older then a certain timestamp. Of course that requires walking the entire cache to do that.

Since you are combining interfaces and a collection then if you have a reference to an object (via its interface), and it gets pruned during cache cleanup, then the object will remain alive until the reference goes away. This provides you an additional safety. Of course if you are still using the reference, then that means you kept the reference for a long time without retrieving it from the cache. In that case you may want to update the timestamp when you read or write to the properties too . . . A lot of that depends on how you will be using the business objects.

As far as refetching, you only want to do that if an object is retrieved from the cache that is older then the refetch limit. That way if it gets pruned before you use it again you are not wasting database trips.

You might consider just having a last modified time in each table. Then when you get an object from the cache you just check the time in memory against the time in the database. If the object has been changed since it was last retrieved, you can update it.

I would limit updating objects only to when they are being retrieved from the cache. That way you are less likely to modify the object while it is use. If you are in the middle of reading data from an object while it changes that can produce some really odd behavior. There are a few ways to handle that, depending on how you use things.

Word of warning about using interfaces, you should not have both object and interfaces references to the same object. Doing so can cause trouble with the reference counting and result in objects being freed while you still have an object reference.

I am sure there will be some feedback on this, so pick what sounds like the best solution for you. . . .

Of course now that I have written all of this I will suggest you look at some sort of business object framework out there. RemObjects has a nice framework, and I am sure there are others.

like image 175
Jim McKeeth Avatar answered Oct 14 '22 08:10

Jim McKeeth


You might want to start by looking at smart pointers. Barry kelly has an implimentation for D2009.

For your BI objects, I would use a guid as the key field, or an integer that is unique across the database. As you load objects into memory, you could store them in a dictionary using the guid as the key and a container object as the value.

The container object contains the bi object, the ttl etc.

Before loading an object, check the dictionary to see if it is already there. If it is there, check the ttl and use it, or reload and store it.

like image 34
SeanX Avatar answered Oct 14 '22 10:10

SeanX