Transactional Objects in AjTalk, a quick intro

I want to describe a short example, showing the management of transactional objects in AjTalk, my open source Smalltalk-like VM written in C#.

What is a transactional object? It’s an object that, when running inside an in-memory transaction, can manage their instance variable values, monitoring their changes. If the transaction if commited, the new values of the object are visible to the rest of the system. If the transaction if rollbacked, the affected transactional objects restore their original values, at the time of the start of the transaction. Note: these transactions are in memory, and they are not related to transactions in databases.

How to create an AjTalk object transactional? I added a method to Object protocol:

Object methods!

    ^@AjTalk.Transactions.TransactionalObject new: self with: (@AjTalk.Machine current transactionManager)
! !

The object is wrapped by a decorator, a native object of type TransactionalObject. This object receives all the petitions for get and set instance variable values, and manage them for the current transaction, and for any other transaction running in the system, that access the same object. I should write a blog describing the internal implementation. Note: if an instance variable in a transactional object is modified by two transactions, the first wins, and the second fails.

Given a Rectangle class:

Object subclass: #Rectangle instanceVariableNames: ‘width height’
!Rectangle methods!
width: newWidth
    width := newWidth
height: newHeight
    height := newHeight
! !

You can create an instance, set some values, and create a transactional decorator:

rect := Rectangle new.
rect width: 500!
rect := rect asTransactional

Now, rect variable points to an instance that is transactional. But if there is no open transaction, its behavior is like any other object. How to start a transaction? The current Machine has a new property, holding a TransactionManager object:

tm := @AjTalk.Machine current transactionManager.
console := @System.Console out

tm beginTransaction!

The instance rect has a reference pointing to the decorated object, named innerObject. You can check their values:

console write: ‘rect width is ‘.
console writeLine: rect width!

console write: ‘inner rect width is ‘.
console writeLine: rect innerObject width!

The output will be:

rect width is 500
inner rect width is 500

Now, let’s set the width of the transactional object:

rect width: 700!

and check again the values, as above. The ouput will be:

rect width is 700
inner rect width is 500

Usually, you use the instance rect (the decorator) in all the running process. If you check the rect width value in another thread/process (with or without its own transaction), you will get 500. The new value 700 is not published yet: it’s only visible from the current transaction.

You can rollback the transaction:

tm rollbackTransaction!

The new values will be:

rect width is 500
inner rect width is 500

If you were committed the transaction, the result would be:

rect width is 700
inner rect width is 700

You can run the example, from the current trunk. There is a RunTransaction.cmd command in AjTalk.Console project.

Next steps: write a blog describing the implementation of this feature; improve the transactional management to have automatically retries in failed transaction.

Keep tuned!

Angel “Java” Lopez

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s