Appendix C. Object Pooling

Creating and destroying objects is expensive. Allocations, initialization, and deallocations all take a good deal of processor time that would be much better spent servicing functional requests from clients. COM+ seeks to reduce this overhead by implementing object pooling. If an object supports pooling (we talk about the requirements shortly), it has the option not to be destroyed when it is deactivated.Deactivation, as we discussed in Chapter 8, "Transactions," occurs when Just-In-Time Activation (JITA) is enabled for that object and one of the following occur:

  • An object's Done bit is set to true, and a method invocation made on it returns.

  • The client terminates or otherwise releases the object instance.

Deactivation does not meantermination for poolable objects as it does for non-poolable objects. Quite the contrary; pooled objects are sent to a kind of purgatory (the pool) where they remain alive and functional, albeit in a deactivated state. When COM+ receives a creation request for an object instance matching that in the pool, COM+ activates the pooled object and returns an interface to the client. The client might believe it created a new instance of the object, and even though this isn't the case, the client has no cause for complaint; a reactivated object does not retain any state from its previous caller and functions in a manner identical to a newly instantiated object.

Unfortunately, not every development environment can create poolable objects. VB 6 objects cannot be pooled. This is because to be pooled, an object must have the following characteristics:

  • Be aggregatable. COM+'s pooling mechanism involves the use of an outer wrapping object that aggregates the pooled object within itself. Objects that do not support aggregation, therefore, cannot be created in the manner required by the COM+ pooling architecture.

  • Support the MTA or TNA threading model. STA objects cannot be pooled due to the severe performance limitations of requiring all method calls to be serialized through one thread.

VB 6 is capable of neither. For the time being then, you must use C++ (preferably with Active Template Library [ATL]) to write poolable objects. That said, if you write a free or neutral threaded object in C++ that supports aggregation, it is automatically poolable. Although not strictly necessary, it is a good idea to implement theIObjectControl interface. The methods of IObjectControl are straightforward, as follows:

  • Activate. COM+ calls this method to notify your object it has been activated and is currently engaged.

  • CanBePooled. Your object returns true if it wants to give COM+ the permission to put it in the pool when it is deactivated; otherwise, it returns false. If your object returns false, it is destroyed when deactivated and causes a transaction (if it is in one) to be aborted.

  • Deactivate. COM+ calls this method to let the object know it has been deactivated and is no longer servicing a client.

You are not strictly required to implement IObjectControl except in the case where you are writing a transactional pooled object. In this scenario, it is important for the object to know when it is being activated so that it can do the following:

  • Get an interface to its new context by calling CoGetObjectContext().

  • Determine the transaction ID and/or interface of the transaction it is now participating in.

  • Manually enlist its connection in this transaction.

CanBePooled: How Can It Return a Boolean?

This method actually returns a Boolean, as opposed to passing one by reference. Thus, in stark contrast to the protocol governing every established interface method in all of COM, the Deactivate and CanBePooled methods of IObjectControl do not return HRESULTs.

The first two points are self-explanatory. The final point, manually enlisting in the transaction, sounds complicated but isn't. You might remember from Chapter 8 (in the section "Resource Dispensers, A First Look") that when an object gets a connection to a Resource Manager (RM) via a Resource Dispenser (RD), such as the Open Database Connectivity (ODBC) driver manager, the Dispenser Manager (DispMan) investigates the context of the object. If a transaction is present in the object's context, DispMan then tells the RD to enlist the connection in a distributed transaction. COM+ performs this enlistment automatically for non-pooled objects but cannot do this for a pooled object; the same instance of a pooled object might participate in any number of transactions but likely uses the same database connection in every case. Thus, a poolable object must assume responsibility for enlisting the same database connection in the different transactions it finds itself participating in.

Normally, a pooled object does the following in its Activate() method:

  • Gets its IObjectContextInfo interface.

  • Calls IObjectContextInfo's GetTransaction() method to get an interface to the transaction it is in.

  • Calls SQLSetConnectOption() passing in the database connection handle and transaction interface. (Assuming it is using ODBC, this step differs depending on the RD used.)

The COM+ Platform SDK contains a good example of how the preceding actions might be implemented in the Account.Vc sample application. Assuming you have installed the Platform SDK (and you should), you can find this and other pooling examples in the following:

<install drive>:Platform
SDK Samples COM Services Object_Pooling

Chapter 8 also includes an explanation of this process with a code example. See Listing 8.2.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.58.155