Michael Zonczyk
Microsoft Developer Network
November 1998
Summary: Examines how the modified Duwamish components interact with the MTS run time to provide remotability and scalability. (8 printed pages) Covers:
Note Duwamish Books Phase 3.5 assumes you're running Microsoft Windows NT® version 4.0, with MTS 2.0. Complete details are provided in Steve Kirk's article "Installing a Distributed Application."
The primary motivation for hoisting Duwamish Books into MTS is to gain remote capability for our Component Object Model (COM) components. This enables us to distribute our components across multiple computers in a network.
By Phase 3 the original set of monolithic Duwamish Books applications had been factored into a set of thinner top-level (we'll refer to these again as base clients) applications relying on the services of a common Business Logic Layer (BLL) component running on top of a shared Data Access Layer (DAL) component accessing an SQL Server™ database. Phase 3 was a logical three-tier implementation, but Phase 3.5 is a distributed three-tier implementation—completing the evolution to the three-tier architectural model discussed in the sample overview, "Duwamish Books."
For detailed information about remoting the Duwamish Books components, see Dale Smith's article "Remoting Duwamish Components" (which uses examples from our Visual Basic components).
This article is concerned with the second motivation for moving to MTS—gaining the scalability features of just-in-time (JIT) activation, connection pooling, and automatic transactions. By scalability, we're referring to the degree to which a system architecture or implementation can efficiently adapt to accommodate a wide range of external demands. In particular, with good scalability, our implementation should support a large increase in concurrent Duwamish Books users with a much smaller increase in additional system resources.
To streamline the discussion in this article, I'll occasionally direct you to specific technical information in the MTS documentation in the Platform SDK on the MSDN Library Online. You can begin exploring the MTS documentation with the "MTS Documentation Roadmap".
Just-in-time activation is where MTS scalability starts. JIT activation impacts the binding between a client and a server component. It offers the client the capability of holding a durable reference to a server component while optimizing system resources used on behalf of the server. In Phase 3.5 JIT activation affects the BLL objects bound by our base clients as illustrated in Figure 1. The graphic labeled "Duwamish Base Client" represents any of our top-level applications: Point Of Sale, Catalog, Shipping, Receiving, or Orders. (An overview of JIT activation is provided in "Scenario: Adding Just-In-Time Activation to the Account Component" in the MTS documentation.)
Figure 1. JIT activation in the Phase 3.5 BLL
Figure 1 shows the MTS context object managing the object lifetime of its encapsulated BLL component. Activation and deactivation consist of real instantiation and destruction for the BLL object. However, MTS optimizes the usual COM creation protocol by, among other things, caching the BLL class factory so that instantiation is burdened neither by registry lookup on the client side nor by typical network round trips when the base client and the BLL are on separate machines. All this is completely transparent to the base client, which is free to hold indefinitely what is functionally a durable BLL reference.
Unfortunately, the benefits of JIT activation do not carry through to the DAL components. Do you see why? JIT activation depends on the client object (a BLL instance) maintaining a reference to the (virtual) DAL object—but when the BLL instance is deactivated the reference is automatically released. The result is that a DAL object is both created and activated each time a BLL object is just activated and a DAL object is both deactivated and destroyed each time a BLL object is just deactivated. MTS provides a mechanism called the Shared Property Manager that may allow us to extend the benefits of JIT activation to the DAL, which we will explore in Phase 4.
With Phase 3.5 we trade explicit connection management for MTS's implicit resource management, known as resource pooling. MTS resource pooling caches ADO/ODBC connection(s) for us between uses. In Duwamish Books, connections are the only kind of resource being pooled. In general, MTS resource pooling is limited to resource types instantiated through a resource dispenser—for example, the ODBC driver. Using this MTS feature is even more transparent than automatic transactions—we just instantiate the resource when we need it and release it as soon as possible.
Offloading connection management onto MTS allows us to simplify interaction between the BLL and the DAL. Therefore, we can drop the DAL methods OpenConnection and CloseConnection. For more information on changes to the DAL for Phase 3.5, see Robert Coleridge's article "Moving a Data Access Layer into Microsoft Transaction Server."
With MTS resource pooling, the actual lifetime of ODBC connections created and released by our DAL is controlled by MTS. In managing connection lifetimes, MTS takes into account whether a connection is in use and/or associated with a transaction in progress (enlisted). MTS does not terminate in use or enlisted connections, but moves them into the Unenlisted Inventory category once their associated transaction ends. MTS terminates not in use, unenlisted connections if they remain unused beyond their timeout interval—a property initialized by the ODBC driver when the connection is created. (This timeout is configurable from the ODBC Data Source Administrator in Windows Control Panel—select the SQL Server driver and click the Connection Pooling tab.)
Enlisted Inventory is one of four MTS resource states; these are documented in "Resource Pooling" in the MTS documentation.
You can view connection activity using SQL Enterprise Manager. Viewing instructions are available in the SQL Enterprise Manager online Help—select the Search tab, enter the search keyword viewing, and then click server activities. (SQL Enterprise Manager can be independently installed by selecting Install Utilities Only during SQL Server 6.5 Setup.)
Transactions are central to the role of MTS—but strictly speaking, MTS only brokers transactions on behalf of components. One or more Microsoft Distributed Transaction Coordinators (MSDTC) actually implement the two-phase commit semantics underlying MTS transactions. Nevertheless, as will be clear shortly, MTS drastically changes the programming model from the perspective of middle-tier components by exposing the IObjectContext interface and automatic transactions.
In Phase 3.5 we trade our familiar client/server explicit transaction paradigm for MTS's implicit transactions, known as automatic transactions. This paradigm fuses component activation with transaction initiation or propagation and then, upon component deactivation, posts a transaction vote, possibly a veto. The posted transaction vote is received by the local MSDTC, which in turn coordinates with all other MSDTCs involved with that particular transaction. MTS transactions obey ACID (atomicity, consistency, isolation, durability) semantics both in simple cases such as ours (a single database) as well as when transactions span databases. MTS enables this paradigm by standing in as a proxy for the component and coordinating with a resource dispenser, the ODBC driver in our case, and an MSDTC—all typically on the component's local machine.
Offloading transaction management to MTS allows us to simplify interaction between the BLL and the DAL. Therefore, we can drop the DAL methods BeginTrans, CommitTrans, RollbackTrans, and IsInTransaction. For more information on changes to the DAL for Phase 3.5, see Robert Coleridge's article "Moving a Data Access Layer into Microsoft Transaction Server."
Lets take a conceptual look at how to control a transaction and how to propagate a transaction, and then compare this to the traditional paradigm we used in Phase 3. Our point of reference is the BLL method InsertOrder().
Table 1.
Action | Phase 3 | Phase 3.5 (Alternative 'A') |
Phase 3.5 (Alternative 'B') |
Start a transaction |
|
Not an issue: Transactions are automatically bound to the BLL's context object at BLL creation.
(In our application the transaction originates with the BLL—but the transaction propagates to the DAL.) |
No transaction context is bound to the BLL's context object—so instantiate a transaction context object and use it instead of a context object to create the DAL. |
Propagate a transaction | Not an issue: The transaction is bound to the connection cached inside the DAL component. | The BLL must use the IObjectContext::CreateInstance() method when instantiating a DAL for the DAL method's work to be part of the same transaction as the BLL. | The BLL must use the ITransactionContext::CreateInstance() method when instantiating a DAL. This way all work by this DAL will be in one transaction. |
Commit a transaction |
|
Call the IObjectContext::SetComplete() method.
(Because the transaction originated with the BLL object, the transaction will complete upon exit from InsertOrder().) |
Call the ITransactionContext.Commit() method.
(The transaction will complete upon return from commit.) |
Rollback a transaction |
|
Call the IObjectContext::SetAbort() method.
(Because the transaction originated with the BLL object, the transaction will roll back upon exit from InsertOrder().) |
Call the ITransactionContext.Abort() method.
(The transaction will complete upon return from commit.) |
Apart from the semantic differences suggested by the different syntax in the two columns, you should note the prominence of the "Object Context" in Phase 3.5 (MTS) transactions. This is the same Object Context depicted earlier in Figure 1. The Object Context contains a reference to the transaction context that MTS uses to communicate with the MSDTC on the object's behalf (and to maintain transaction continuity as our BLL and the DAL come in and out of de facto existence during activation and deactivation).
An object obtains access to its associated ObjectContext::IObjectContext interface by calling the global function GetObjectContext, and propagates the transaction context using the IObjectContext::CreateInstance method to instantiate downstream components. This enlists the new object in the instantiator's transaction.
Let me reemphasize that a component need not access its own transaction context in order to propagate it. This fact is a realization of how MTS fuses transactions with instantiation. The Object Context abstraction allows a component to transparently create downstream objects regardless of whether it is itself enlisted in a transaction.
An instantiated object is either enlisted in a transaction or it is not. If it is enlisted, the transaction is either the one propagated from the instantiator or it is a new transaction established by MTS. (These facts underlie the Phase 3.5 version 1.1 Microsoft Visual Basic® BLL implementation.)
Finally, the MTS model also supports explicitly creating a transaction context, but only to be propagated forward. The transaction cannot be enlisted-in by its creator. (This feature is used in the Phase 3.5 Microsoft Visual C++® implementation.)
Moving to MTS automatic transactions requires that we administratively set transaction attributes on each of our components. Transaction attributes establish the transaction to instantiation binding policy. Our goal is for each business logic method to behave as it had in Phase 3 when we used explicit transactions. Recall that automatic transactions associate either transaction initiation or propagation with object activation. With this key concept, it makes sense that the BLL component should initiate transactions while the DAL should propagate transactions. Given the four MTS-defined transaction attribute values: "Requires a transaction," "Requires a new transaction," "Supports transactions," or "Does not support transactions," the appropriate BLL attribute can be either "Requires a transaction" or "Requires a new transaction," while for the DAL it must be "Supports transactions."
The easiest way to set transaction attributes is through the MTS Explorer via property pages. For more detailed information about transaction attributes and how to set or edit them, see "Setting MTS Transaction Properties" in the MTS documentation.
In the evolution from Phase 3 to Phase 3.5, the Business Logic Layer has so far remained intact as a single COM component. As it turns out, the semantic effect of automatic transactions forces us to rethink the BLL's design. Naively keeping the BLL as one component imposes unnecessary transactions—every call of a BLL method causes an MSDTC transaction, a relatively expensive operation that we want to avoid for operations that don't require transactions. Before explaining the final Phase 3.5 implementation(s) we should distinguish two categories of BLL methods in light of automatic transactions under MTS.
The first category contains most of the BLL methods, which, like GetEmployees, did not require transactions in Phase 3. Lets call this the non-transacted category. The other category, we'll call it the transacted category, contains the three remaining methods: InsertOrder, InsertSale, and UpdateOrder.
In our naive BLL design, we would over transact. Our transaction attributes would have been assigned like this:
Two alternate designs that don't over transact:
Assign transaction attributes as follows:
(Take note that in InsertOrder and InsertSale a call is made from Bll_T to Bll_N with the desirable result that during the call the (now) Bll_N method participates in a transaction propagated from Bll_T, so it works just as in Phase 3.)
Assign transaction attributes as follows:
For Phase 3.5 of the Duwamish Books sample, either alternative is reasonable. We have implemented the first alternative in our Visual Basic implementation, and the second alternative in our Visual C++ implementation.
We have installed a "bug book" trap door in Phase 3.5 so that a transaction failure is easily triggered and observed using MTS Explorer's transaction activity monitor.
To trigger the bug book feature, include the book titled "The Iliad" (ID: 748) as part of a sale or as part of a purchase order. The Duwamish Books store procedures that insert the details of a sale or of an order check for this key value and return an error. This causes the DAL ExecQuery() method to invoke SetAbort instead of SetComplete, which will roll back the entire InsertSale or InsertOrder operation.
See "Monitoring MTS Transactions" in the MTS documentation.
MTS is both a run-time environment and a programming model for COM components. The first benefits of using MTS come easily—we can get remotability without any changes to our DLLs. As we use MTS JIT activation and automatic transactions, we realize that gaining actual benefits requires accommodation to the MTS programming model, which we have only partly done. For example, in Phase 3.5 we're getting JIT activation benefits only with respect to the BLL component and not the DAL. Also, consider that automatic transactions provide no benefit beyond simplifying the data access layer at this stage—and arguably at the cost of complicating the BLL. The most essential lesson is that using MTS features at a naive level is easy, but sophisticated use of MTS services requires a major review of the application's purpose, performance requirements, and underlying design.
We recognize that scalability is a tool for total system performance optimization—individual components implemented for scalability (as in our case) will typically be slower because of higher execution overhead. This is counterbalanced by a new ability to scale-out by adding machines without creating resource bottlenecks. MTS features provide an infrastructure for high-scalability applications, but building scalable applications requires the application of an expanded set of software engineering principles. Phase 3.5 has explored the technology of MTS scalability features, but we can't claim that we have a scalable application because we haven't quantified what that means, nor addressed performance tradeoffs.
For a comprehensive introduction to MTS performance issues, consider downloading the MTS Performance tool suite from ftp://ftp.microsoft.com/bussys/viper/Unsup-ed/MTSPTool.