RamTx : A Resource Dispenser for the Millenium
OK, so a super cheesy title, but it got your attention eh ? RamTx is a MTS Resource Dispenser + Resource Manager that provides an
in memory transactional property bag. It provides a transaction based lock manager, and so handles locking just like a database,
and is effectively a transactional version of the SPM (Shared Property Manager)
Using the RD
The RD exposes the following interface, which is fairly a fairly typical looking interface for a property bag with the exception of
the bIntendsToWrite flag, which allows the caller to specify a hint to the lock manager.
interface IRamTxBag : IDispatch
HRESULT Read ( [in] BSTR Key,
[in, defaultvalue(0)] VARIANT_BOOL bIntendsToWrite,
[out,retval] VARIANT * pVal) ;
HRESULT Write ( [in] BSTR Key, [in] VARIANT newVal) ;
helpstring("RamTx Resource Dispenser 1.0 Type Library")
helpstring("RamTx Resource Dispenser Class")
[default] interface IRamTxBag;
Your transactional MTS components can create an instance of the RamTx resource dispenser, and the RD is automatically enlisted
on the transaction.
You can also use the property bag from a non-transactional component as well (so effectively the RD Supports Transactions).
Each item in the property bag has its own lock manager, so one or more updates to the property bag (to the same or different keys)
can be managed by a single transaction, if the transaction is aborted, the changes are not made. Keys are not case sensitive so
the keys "Foo", "foo" and "FOO" all refer to the same item. As with the SPM the data in the property bag
is still there, even if you release all your references to the resource dispenser. (Although if MTS shuts the package down because
of the idle timeout, then its gone)
As stated earlier, each item has a lock manager, the lock manager enforces the following policy, based on the caller's transaction.
If you mix tx and non-tx access, non-tx access uses transistory locks (the locks are released as soon as the read / write is finished),
and is still subject to the above lock rules.
- A transaction can take a read lock, if there is no write lock on the item, or if the transaction has a write lock.
- A transaction can take a write lock, if there are no read locks, or if the transaction is the only read lock.
- When the transaction commits or aborts, the locks are released.
- Requests for locks which are not available are queued until they are.
- If you set bIntendsToWrite to true when doing a read, it will first acquire a write lock, then a read lock.
- The lock manager only supports the serializable isolation level, even if the transaction is running at a lower isolation level you
still get serializable isolation.
- Lock promotion is supported (via the bIntendsToWrite parameter), but lock demotion is not supported, i.e. there is no way to do a NOLOCK read.
- I'm sure that each LockQueueItem doesn't need its own Win32 Event, it should be possible to manage the Lock Queue with a single Win32 Event, but I haven't tried this yet.
An example MTS component and client app are included in the download, so that you can play around with the different transaction settings,
lock promotion etc. Just drop the mtxcomp.dll in a MTS Server package, and register the Resource Dispenser with regsvr32 ramtx.dll
Notes on Usage and Redistribution
Feel free to redistribute ramtx.dll with your product. Feel free to borrow the idea and use some of the code in your product.
Do not build a modified version of ramtx.dll and ship it. This component was written carefully and robustly, and I expect that
many people will find it useful, so please don't misuse the source code by tweaking it a little, leaving the GUIDs the same,
and shipping a slightly modified version. The source code is for informational and debugging purposes only.
If you find bugs (or just have comments), please send email to: Simon Fell
NO WARRANTIES ARE EXTENDED. USE AT YOUR OWN RISK.
Download the latest source & binaries
Back to Simons COM stuff
(c) 1999 Simon Fell, this page last updated 10 May 1999