Issue 299: Object Identity and Transaction Service (transactions) Source: (, ) Nature: Uncategorized Severity: Summary: Summary: Importance of the object identity issue Resolution: Revised Text: no change, Transaction Service does not rely on object identity Actions taken: October 22, 1996: received issue January 6, 1997: closed issue Discussion: End of Annotations:===== >From mail Tue Oct 22 18:54 EDT 1996 Return-Path: To: Michi Henning , "H.Lejeune" Cc: transactions-wg , tc , ab , om From: "Edward Cobb" Date: 22 Oct 96 14:44:16 Subject: Re: object Identity and the Transaction Service Content-Length: 10975 Michi, I did not mean to minimize the importance of the object identity issue -- I believe it is quite important, but I still believe the transaction service is not relying on it as a means to accomplish its function. However, from going through your last note, I've concluded that our example is at best confusing and should be changed as part of this revision. So far, however, I have not seen anything in the actual specification (chapter 10.3) which needs alteration. The biggest misunderstanding that you gleaned from the example (and I can understand from your note how you did so) is that the transaction service serializes a resource's access to a given transaction at registration time. As you so correctly point out, the only way OTS could do so is by comparing resource object references in some way, which is the essence of the identity discussion. The recoverable object is responsible for determining if it needs to register in the current transaction. The OTS provides assistance in the form of primatives which allow it to determine if it is already registered. This is analogous to the dynamic registration option of X/Open model where the database manager (analagous to what we call a Recoverable Server) decides whether a DB call is for a new or existing transaction and, if new, asks the transaction manager for a new transaction ID. The normal way to do this is to allocate a new resource object for each transaction a recoverable object needs to participate in (in other words a given resource object reference maps isomorphically to a given transaction ID for a specific recoverable object) and pass that resource reference to the OTS on register_resource AFTER determining that the current transaction is in fact a new one. The means to accomplish this are: 1. The recoverable object (e.g. the BankAccount in the example) keeps a list of Coordinator references for each transaction it has registered in previously. 2. When a method is invoked on BankAccount that requires registration, the BankAccount compares the current coordinator to his list of already-registered coordinators using the is_same_transaction operation on the current coordinator (the one determined by current.get_control followed by control.get_coordinator). 3. The OTS implements the comparisons by comparing XIDs, not the Coordinator references. The XID is part of the propagation_context which is created as a side effect of factory.create, 4. If all comparisons yield false (i.e. the BankAccount is not registered in the current transaction), then the register_resource operation is used to register a new resource for the new transaction. The example shows the BankAccount inheriting from resource and thus being its own resource object. This leads to the restriction (which the BankAccount must enforce), because the OTS cannot determine if two resource objects are equivalent. Herve's subsequent note observes that some failures can cause the BankAccount object to think it is not registered when in fact it is. This suggest that the act of registration needs to be durably recorded prior to issuing register_resource if the BankAccount intends to be its own resource object, or alternatively, we might preclude it. I'd welcome suggestions. One other point, if the transaction service is given two object references (via register_resource) which in fact are the same object, it will diligently poll both of them at prepare time and count each of their votes independently. I intend to clarify the example as part of the revision to eliminate your misconception. I have not found any other place where clarification is also needed, but will accept any and all input on the subject. Ed Cobb michi @ dstc.edu.au (Michi Henning) 10-22-96 02:00 PM To: transactions-wg @ omg.org @ SMTP cc: tc @ omg.org @ SMTP, ab @ omg.org @ SMTP, om @ omg.org @ SMTP (bcc: Edward Cobb) Subject: Re: object Identity and the Transaction Service Hi, This is in reply to Ed's and Herve's message. At the risk of publicly making a fool of myself, I'll restate the problem I see. I am no TP expert, so possibly I am wrong. If I am, then I would lay the blame at least in part on the current version of the OTS spec - if I misunderstand it, there is a chance other people will. I would also appreciate it very much if one of the experts could point out the error of my ways... Ed writes: > Not true. The BankAccount1 object inherits from TransactionalObject > to have the transaction context associated with its current thread. > That makes it a transactional object. If becomes a recoverable object > by registering a Resource object with the OTS (not the TP monitor; > that's something completely different). The Resource object is created > by the recoverable object and must be able to copy persistent state > associated with the current transaction from the recoverable object > to some durable media. How it does so is implementation defined. The OTS > defines only the operations it needs to support. Since the transaction > identity is not passed to the Resource object at prepare time, it must > encapsulate the current transaction with the Resource, perhaps by saving a > reference to the Coordinator. If the recoverable object is also a resource > object, it can participate in one and only one transaction at a time. My apologies for the sloppy terminology, I used "TP monitor" to mean something like "all the other bits in the machinery, outside the object implementation". Here is the problem as I see it: >From the spec: interface BankAccount1: CosTransactions::TransactionalObject, CosTransactions::Resource { // ... void makeDeposit(in float amt); // ... }; This says that a bank account implementation has the transaction context associated with the current thread, and that a back account is a recoverable resource. The C++ implementation in the spec shows: void makeDeposit(float amt) { CosTransactions::Control c CosTransactions::Coordinator co; c = txn_crt.get_control(); co = c->get_coordinator(); // ... At this point, the text says: "Before registering the resource the object should check whether it has already been registered for the same transaction." The text or code example do *not* state what the object should do if: - it *is* already in the same transaction - it is *not* already in the same transaction but in a *different* one. - it is not in *any* transaction at the moment. What follows is based on what I believe should have been said in the spec. Please correct me if my assumptions are wrong. Then the text goes on: "Note that this object registers itself as a resource. This imposes the restriction that the object may only be involved in one transaction at a time." To me this says: "The act of calling register_resource ensures that the object is only in one transaction at a time." The code then shows: RecoveryCoordinator r; r = co->register_resource(this); // performs some transactional activity locally blanace = balance + f; num_transactions++; ... // end of transactional operation }; To me, the example clearly demonstrates that the implementation does not need to do anything other than call register_resource. Once that call returns, it is OK to modify object state. So, this implies to me that register_resource will block until the object is no longer involved in any other transaction, and only return when it is safe to modify object state. Now, here is my problem: - Obviously, something must maintain the association of which resources are in what transaction. - The way I understand it, that is the job of the coordinator. It is also clear that locking is involved, and that the grain of locking is based on resource-per-transaction. In other words, if a resource is in a transaction, it must be locked against access by all other objects that are not in the same transaction. So, given the IDL interfaces in the OTS, how does the coordinator know which resources are in what transaction? The way I see it, it knows because objects call register_resource, passing the object reference to the resource as a parameter. Now, the Resource interface does not have any other operations that could supply identity to the coordinator, and the only time the coordinator gets to find out which resources are in what transaction is when register_resource is called. This leads me to believe that the coordinator uses the object reference of the resource as its identity (because as far as I can see, it can't use anything else). In the example in the spec, the recoverable object (bank account) inherits from resource, and the object reference of the object is the same as that of the resource. The crux is: What if the resource (bank account) is known by two different object references? This could happen if the bank account is proxied, for example. Assume two clients hold a reference to the bank account each (but the references are different): - Client1 calls makeDeposit which brings the bank account into the transaction. The code checks that the object is not in any transaction yet, calls register_resource which returns immediately and then updates the account state. - Client2 calls makeDeposit. The account implementation finds that it is in a different transaction already and calls register_resource, which should block. However, the coordinator is given a different reference and lets the object into the transaction (how could it possibly know that Client1 and Client2 are talking about the same object?) Unless I grossly misunderstand something, this leads to the same object being in two different transactions simultaneously. I cannot see a way to make this work other than have register_resource block until the object can safely be modified. In particular, the bank account implementation *cannot* return an error to its caller because the caller is using transactions so it does *not* have to bother with failure to acquire locks and the like. I believe that this scenario can occur even if the bank account does *not* inherit from Resource. Basically, I see this happening whenever a Resource can somehow end up with two references that do not compare equal (say because of proxying). Please, can one of the experts set me straight on whether what I have described above is nonsense or not? I'm happy to learn! However, even if the above scenario is wrong, and there is no problem in the TP spec, I still maintain that the identity problem is important. Object identity is not only important for TP, but for any service that stores object references and needs to maintain invariants that depend on object identity in some way. Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Although I previously said I would not make new changes to the OTS spec for this revision, I will respond to each of these in this note since I believe most of them have been resolved anyway without a change to the specification being necessary. 1. Issue 299 - Object identity and the transaction service. The OTS does not rely on object identity to implement its functionality. (See my series of notes to Michi Henning). No change to the spec required.