| List: | Falcon Storage Engine | « Previous MessageNext Message » | |
| From: | Jim Starkey | Date: | March 16 2009 6:18pm |
| Subject: | Re: New Transaction State object (Was: Problems with record visibility and how it is computed) | ||
| View as plain text | |||
I think TransactionState will also need:
* Transaction id (for validation and sanity control)
* Transaction state
* syncPending (so it can be waited on)
This makes TransactionState the primary operational object and
Transaction mostly for bookkeeping. I think this also eliminates the
need for TransactionManager::activeTransactions.
Olav Sandstaa wrote:
> Subj: New TransactionState object
>
> Hi,
>
> In our Athens meeting I went through the alternatives for how to solve
> the issues with the "RecordVersion to Transaction object pointer". We
> agreed on that introducing a "transaction state object" (proposal 9
> quoted below) seemed to be the best and least intrusive alternative.
>
> I have not looked into the actual existing code yet but here is an
> initial overview of how my current plan for the "transaction state
> object" is (it might changes as I look more at the existing code and
> use of it):
>
> A. New data structure:
> ======================
>
> A new class called TransactionState will be introduced. This will as
> a minimum store the following members:
>
> class TransactionState
> {
> TransId commitId;
> volatile INTERLOCKED useCount; }
>
> It is also likely that we will move the transaction id to this
> class (could save us from storing this in each RecordVersion
> object). The transaction state of the transaction might also be
> moved to this object.
>
> Changes to existing classes:
>
> 1. The Transaction object will have a pointer to a TransactionState
> object. When committing the transaction the commitId will be
> stored in the TransactionState object, not in the transaction
> object.
>
> 2. The RecordVersion object will have a pointer to a
> TransactionState object (replacing the existing pointer to the
> Transaction object) (if there is need for accessing the
> Transaction object from the RecordVersion object we will either
> keep the transaction pointer or have a transaction pointer from
> the TransactionState object back to its Transaction object)
>
> Goal with this new TransactionState object is to let it "live" as
> long as there is RecordVersion objects refering to it (and let the
> "real" transaction object be "purged" at "any time").
>
> B. Controlling the "life span" of TransactionState objects
> ==========================================================
>
> We will use a reference counter in the Transaction state object for
> controlling when a Transaction state object can be deleted.
> Operations on this reference counter will be done by using
> interlocked operations (if would probably be possible to implement
> this without interlocked instruction but that would make the
> implementation a bit more complex and harder to maintain and the
> discussion in Athens concluded that the cost of using interlocked
> operations for this case should not be a performance problem).
>
> The reference counter will be incremented the following places:
>
> 1. In the Transcation's constructor when the TransactionState
> object is created (we can also delay this until the first
> Record is attached to a Transaction (Transaction::addRecord())
> but it is simpler to just create it when we create the
> Transaction object)
> 2. For every RecordVersion having a pointer to it (most likely in
> the RecordVersion's constructor - have not looked at the code
> yet)
>
> The reference counter will be decremented the following places:
>
> 1. In the Transaction's destructor
> 2. When the RecordVersion is deleted (most likely in the
> destructor)
>
> There should be no objects using the TransactionState object
> without having incremented the reference counter (or accessing it
> indirectly via the a Transaction object or a RecordVersion object).
>
> C. Usage of the TransactionState object:
> ========================================
>
> The initial usage of the TransactionState objects will be as
> follows:
>
> 1. Each time when creating a transaction object, we create a
> transaction state object and a pointer to the transaction state
> object from the transaction object.
>
> 2. When we commit: the commitId is written to the transaction
> state object (not the transaction object). So the commit is the
> update to the transaction state object (not that it is possible
> that we also will store the state of the Transaction in the
> TransactionState object)
>
> 3. Each time we create a record version object it has a pointer to
> the transaction state object - and the reference count is
> incremented (if needed also a pointer to the
> transaction object (hopefully not, alternatively have a pointer
> from the TransactionState object back to the transaction)
>
> 4. When we need to compute visibility of records we only need to
> use the transaction state object. This will have at least the
> same life span as the record version objects pointing to it
> (thus the pointer is guaranteed to be valid)
>
> 5. When the scavenger removes a recordversion it decrement the
> reference counter in the transaction state object
>
> 6. When we purge old Transaction objects we decrement the referece
> counter in the Transaction State object
>
> 7. When the reference counter reaches 0 we delete the transaction
> state object (by "self destruction")
>
>
> That is the current plan - and as most plans it might change :-)
>
> Please let me know if you have any feedback or suggestions.
>
> Olav
>
> Olav Sandstaa wrote:
>> In addition to these I also have two new possible solutions:
>>
>> 9. (This is partly based on something Ann wrote: Make the
>> transasction pointer indirect combined with my original proposal
>> number 5: let the transaction objects live as long as there are
>> record version pointing to them): Introduce a new "Transaction state
>> object" that contains as a minimum the "commitId" but most likely
>> also the "transactionId" and "state":
>>
>> 1. Each time when creating a transaction object, we create a
>> transaction state object and a pointer to the transaction state
>> object from the transaction object.
>> 2. When we commit: the commitId is written to the transaction
>> state object (not the transaction object). So the commit is the
>> update to the transaction state object.
>> 3. Each time we create a record version object it has a pointer
>> to the transaction state object (and if needed also to the
>> transaction object)
>> 4. Each time we add a record to a transaction (ie. update a
>> record) we increment a useCount in the transaction state object: This
>> should not need any extra locking (I think)
>> 5. When we need to compute visibility of records we only need to
>> use the transaction state object. This will have at least the same
>> life span as the record version objects pointing to it (thus the
>> pointer is guaranteed to be valid)
>> 6. When the scavenger removes a recordversion it decrement the
>> useCount in the transaction state object (I think this can be done
>> safely without locking given that we have one scavenger)
>> 7. When the useCount reaches 0 we delete the transaction state
>> object.
>>
>> Issue/question: is there any other places in the code that will
>> access this transaction state object than by accessing it from the
>> record version object?
>>
>> I assume when normal transactions accesses record version objects
>> they are "locked" and this will implicitely also lock the transaction
>> state object when normal transactions access it?
>
>
--
Jim Starkey
President, NimbusDB, Inc.
978 526-1376
