Resource Management

One of the more expensive things in any application is creating and loading objects into memory. A key way in which COM+ can help make applications work more efficiently is through resource management. COM+ provides resource management through the services of Object Pooling, Just-in-Time activation and deactivation, and State Management. These services, together with the stateless programming model COM+ enforces, can give your application better overall scalability.

Object Pooling and Construction

Object Pooling is one of the features that COM+ promised, but on which VB developers were never able to capitalize. This was the result of VB's tight integration with COM and its capability to support only the apartment-threading model. Now, with the .NET version of VB and its support for multithreading, you can use COM+ services to maintain pools of objects and thus increase your application's scalability.

Object Pooling is a service that keeps objects cached in a queue. Clients requesting these objects do not have to suffer the overhead of their creation. Instead, COM+ hands them the cached object, nearly eliminating the largest overhead involved with using COM+ objects. This provides faster access to objects and increases the number of requests that a server can process. Typically with pooling, just a few objects can handle hundreds of requests.

Objects are either loaded into the pool after a client request or can be preloaded into the pool. Preloading eliminates the lag the initial caller usually suffers because of object creation.

The class library provides the ObjectPoolingAttribute class to mark components as participants in an object pool. When tagging a component as taking advantage of Object Pooling, you are creating a new instance of this class. As such, you can set a number of properties on the class that will affect how COM+ services pool the object:

  • MinPoolSize enables you to control the minimum number of objects that are maintained in the pool. As objects are requested or on startup of the COM+ application, the pool reaches its minimum size and COM+ maintains at least this number of objects for use by additional callers.

  • MaxPoolSize sets the maximum number of objects that can exist in the pool. If all pool objects are in use and the pool has not reached its maximum size, COM+ creates an additional component for the caller. When the maximum pool size is reached, however, COM+ queues the client requests and each must wait in turn for an object to become available from the queue.

  • CreationTimeout sets the number of milliseconds COM+ should wait for an object from the pool when requesting an object. If the timeout value is reached, COM+ throws an exception.

COM+ manages an object's life cycle; as such, it calls methods of the IObjectControl interface exposed by the ServicedComponent class. You can override and intercept these calls for use by your application. The following are methods of IObjectControl that can be overridden:

  • Activate is called by COM+ when your object is removed from the pool (handed out to the calling client).

  • Deactivate is called when an object is placed back into the pool (released from the client).

  • When COM+ returns an object to the pool after deactivation, it first calls CanBePooled. This enables you to check your object to make sure it is okay to be returned to the pool. If so, you return True from the function call; if not, returning False causes COM+ to discard the object.

In Listing 17.3, we create a COM+ object called myPooledObject. We tag it as a pooled object and set the pooling parameters of minimum pool size to 5 and maximum pool size to 10.

Listing 17.3. Object Pooling
Imports System.EnterpriseServices

'indicate the COM+ application name
<Assembly: ApplicationName("myComApp")>

'indicate the key pair used to generate the strong name for the assembly
<Assembly: System.Reflection.AssemblyKeyFile("keyPair.snk")>

<Transaction(TransactionOption.Required), _
ObjectPoolingAttribute(MinPoolSize:=5, MaxPoolSize:=10)> _
Public Class myPooledObject
    'purpose:   provide pooled component example

    'class-level scope
    Inherits ServicedComponent

    <AutoComplete()> _
    Public Function doTask() As Boolean

        'purpose:   simulate a function

        Return True

    End Function

    Public Overrides Function CanBePooled() As Boolean

        'purpose:   called by COM+ after Deactivate
        '           used to decide if the object can be returned to the
        '           queue or should be discarded

        Return True

    End Function

    Public Overrides Sub Activate()

        'purpose:   called when an object is handed out to a client and
        '           removed from the pool

    End Sub

    Public Overrides Sub Deactivate()

        'purpose:   called before placing back in the pool on deactivation

    End Sub

End Class
						

How do you verify that COM+ is pooling your objects? One way is to view the components' real-time inside the COM+ Component Services management console application. This enables you to see the number of objects in a given pool at a specific time. Figure 17.4 is a screenshot of this interface as it is reporting resource-management statistics.

Figure 17.4. Component Services monitoring.


To make sure your components are tracked by the COM+ Component Service monitor, you must set the attribute EventTrackingEnabledAttribute to True. Additionally, your component must be running in a server and not in a library application.

Of course, you can use the Component Services manager application to mark Object Pooling attributes directly or to override the attributes your component has set at the time of install. Your object should still override the CanBePooled method and mark this value to True to indicate that COM+ can pool your object. Figure 17.5 illustrates the interface.

Figure 17.5. Object Pooling Component Services interface.


Just-in-Time Activation

COM+ provides the service of Just-in-Time (JIT) activation and deactivation of components. Components that take advantage of this service are instantiated as context-only objects on request. That is, the objects are not activated (and locked) by calling the client at the time of creation. COM+ activates the JIT object on a method call from a client. When the method returns, COM+ deactivates the component. This allows COM+ to pass out these expensive resources only when they are really needed (on the method call) rather than when they are created.

As an example of the benefits this service can provide, suppose you have an application that creates a number of COM+ objects in the declaration section at the top of your procedure. Now suppose that as your procedure executes, it uses some of the objects some of the time and deactivates all the objects after the procedure has completed. Without JIT activation, COM+ would be forced to hand your application an instance of each object on its creation. These objects would be blocked from access by other requesting applications until your application is finished with them, regardless of when or if your application actually uses them. Thus, COM+ would have to create another instance for a second requesting client. With JIT activation, COM+ knows that you may want the resource, but until you actually use it by calling one of its methods, it is available to be used by other clients. After they are used, on method call return, COM+ deactivates the object and makes it again available to others, regardless of whether your application is finished using it.

Of course, this model—and COM+ in general—requires that your object architecture is a stateless design. Stateless objects are those that do not maintain object state or data between method calls. A stateless object fires up at method call, gets its work done, passes results to the client call, and then dies. Therefore, even though your application holds a reference to a JIT object, the object does not maintain state between method calls. It is deactivated, and thus all data from the method call is wiped out. This design prevents objects from blocking or holding expensive resources open and thereby increases the scalability of your application.

To indicate that your object is ready for deactivation, you set the doneness bit (a flag value indicating that your method has completed). This is automatically set for you when using AutoComplete or calling SetComplete or SetAbort of the ContextUtil class. Additionally, setting DeactivateOnReturn = True indicates that your object is ready to be deactivated.

To mark a class as taking advantage of JIT activation and deactivation, you simply use the JustInTimeActivationAttribute class, as in

<JustInTimeActivation(True)> Public Class myJITClass

Note that components marked as AutoComplete automatically set the JIT attribute to True.

Shared Property Manager

Because of the stateless nature of COM+ programming, your objects cannot retain data between method calls. That is, if you set a number of property values on your object at the time of a method call, after the method completes, the object deactivates and flushes all its data—even though your application still maintains a contextual reference. Working within such a programming model requires that you design your system state management very carefully.

One solution is to push all state out to the data store. This requires your objects to constantly poll the database for state information. This solution is often very effective, provided it is designed correctly.

Sometimes it's preferable to store your user-specific state somewhere within the user-interface tier. You can push state out to the client in the form of cookies or session variables in the case of a Web application. In the case of a client/server application, you could store state out to locally executing code inside the client.

But what if you need to manage a global value between objects, and you want neither to return the data to the calling client nor store it to (or access it from) the database?

COM+ provides the Shared Property Manager (SPM) for precisely this occasion. The SPM is a resource dispenser that allows you to share state between objects executing in the same server process. The SPM state is transient—that is, shared state does not survive system failures, reboots, or application shutdowns. The SPM is meant to be accessed across a transaction and not across a process. Because of this transient nature, it is important for you to ensure the execution sequence of your methods that require shared data. Alternatively, you should implement your method in such a way that on shared property access exceptions, your method knows how to create and populate the shared property values.

Shared properties are available only to objects running in the same process. Therefore, objects that require access to global data must be installed inside the same COM+ application.

To create a shared property, you must first create a SharedPropertyGroupManager object. This object enables you to create and access property groups. One of the problems with global data that the shared property manager solves is naming collisions among global variables. For example, if Object A creates a value called mySharedValue, Object B should be restricted from creating the same shared variable or a collision will occur—or worse, Object B could simply overwrite Object A's value. Object B and Object A know nothing about each other and therefore could easily create this collision. The SharedPropertyGroup class and the SharedPropertyGroupManager solve this problem by enforcing unique namespaces for properties to use.

The CreatePropertyGroup method of SharedPropertyGroupManager is used to define a new property group and returns a SharedPropertyGroup instance. This method call requires that you indicate the following parameters:

  • name— The property group name. This is a string value that you use to reference the property group when returning property values.

  • dwIsoMode— The property group isolation (or lock) mode. The value is of the type PropertyLockMode enumeration, whose values include Method and SetGet. Setting the lock mode to SetGet indicates that after you set or return the value of the property group, you are finished using it and it can be released for others to share. If you make a call that sets a value, this call is atomic. Setting the value to Method indicates that the property access locking should correspond with the execution of your method. When the method is complete, you can unlock the property value.

  • dwRelMode— The release mode requested. The value is of the type PropertyReleaseMode enumeration, whose values include Process and Standard. If the value is Process, the property values are maintained for the lifetime of the process. If the value Standard exists as the default mode for COM object, it indicates that when all objects have released their references to the shared property, the object will automatically be destroyed.

  • fExist— A parameter indicating what to do if the property group already exists. You set this Boolean parameter to True if the property group already exists and you simply want access to it, or set it to False if you want the property group to be created by the method call.

After you have a defined SharedProperty group, you use its method, CreateProperty, to define a new property. This method call returns a SharedProperty instance. You pass the property name and fExists as parameters to the method call. fExists is a Boolean value that you set to True if you are returning a preexisting property or False if you are creating a new property. You use the Value property of the SharedProperty object to set the shared value.

In Listing 17.4, we create two classes: classSet and classGet. Our classSet creates a shared property inside the custom method setProp. This method uses the objects SharedPropertyGroupManager, SharedPropertyGroup, and SharedProperty. The property's value is set based on the method's parameter, propVal. Our classGet creates the custom function getProp which finds the property group and property and returns the property value from the function.

Listing 17.4. Shared Properties
Imports System.EnterpriseServices

<Assembly: ApplicationName("myApp")>

'indicate the key pair used to generate the strong name for the assembly
<Assembly: System.Reflection.AssemblyKeyFile("sharedProp.snk")>

Public Class classSet

    'purpose: sets a value in the shared property group

    Inherits ServicedComponent

    <AutoComplete()> _
    Public Sub setProp(ByVal propVal As String)

        'local scope
        Dim spGroupMgr As SharedPropertyGroupManager
        Dim spGroup As SharedPropertyGroup
        Dim sharedProp As SharedProperty

        'create a property group manager object
        spGroupMgr = New SharedPropertyGroupManager()

        'create a shared property group
        spGroup = spGroupMgr.CreatePropertyGroup( _
            name:="spGroup", dwIsoMode:=PropertyLockMode.SetGet, _
            dwRelMode:=PropertyReleaseMode.Standard, fExist:=False)

        'create a property
        sharedProp = spGroup.CreateProperty(name:="spProp", fExists:=True)

        'set the property value to the passed string value
        sharedProp.Value = propVal

    End Sub

End Class

Public Class classGet

    'purpose: retrieves a value in the shared property group

    Inherits ServicedComponent

    <AutoComplete()> _
    Public Function getProp() As String

        'local scope
        Dim spGroupMgr As SharedPropertyGroupManager
        Dim spGroup As SharedPropertyGroup
        Dim sharedProp As SharedProperty

        'create a property group manager object
        spGroupMgr = New SharedPropertyGroupManager()

        'find our shared property group
        spGroup = spGroupMgr.CreatePropertyGroup( _
            name:="spGroup", dwIsoMode:=PropertyLockMode.SetGet, _
            dwRelMode:=PropertyReleaseMode.Standard, fExist:=True)

        'get our property
        sharedProp = spGroup.Property(name:="spProp")
        'return the property value
        getProp = sharedProp.Value

    End Function

End Class

Module Module1

    Sub Main()

        'local scope

        'create the class that sets the shared prop
        Dim mySet As New classSet()

        'set the shared property
        mySet.setProp(propVal:="This is a shared property!")

        'create a class that reads the property
        Dim myGet As New classGet()

        'get the property and write out to the console
        Console.WriteLine(myGet.getProp())

        'wait
        Do While Console.ReadLine <> "s" : Loop

    End Sub

End Module
						

Suggestions for Further Exploration

  • Check out the System.EnterpriseServices.CompensatingResourceManager namespace. This set of classes enables you to create resource managers that use nontransactional objects inside of a Distributed Transaction Coordinator (DTC) transaction.

  • For some useful content on COM+ in general and some specifics on Object Pooling and other services, read: MSDN/ MSDN Library/Component Development/COM+/Technical Articles.

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

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