With traditional concurrency control you can do a timed wait on some resource (a lock for example) to come available. If the resources
doesn’t come available within a certain limit, the operation fails and this needs to be handled in the code. There are a few problems with
this approach:
- no convenient way to pass the total timeout to each blocking call
- you need to have several versions of blocking methods (with or without timeout, interruptible or not) and often there is no easy abstraction higher up. So you keep getting almost identical methods, that only differ in the type of blocking method they call
- no easy way to roll back changes. If you decide to abort an operation because of a timeout, it could be hard to restore the system in the original state (so no atomicity)
With software transactional memory these problems can be solved. I have just added support for timed blocking methods, so you can say something like:
@TransactionalObject
class BankAccount{
private int balance;
public int balance(){
return balance;
}
public void setBalance(int balance){
this.balance = balance;
}
}
@TransactionalMethod(timeout = 1, timeoutTimeUnit = TimeUnit.SECONDS)
public static void tryRemove(Account a, int amount){
a.setBalance(a.getBalance()-amount);//is rolled back in case of a failure
if(a.getBalance()<0{
retry();
}
}
When the tryRemove is called (and no transaction is running), and the balance is not sufficient, the call blocks until a timeout occurs or the balance is increased and the money withdrawn. And if you want the call to be interruptible, you just need to add the InterruptedException:
@TransactionalMethod(timeout = 1)
public void tryRemoveInterruptibly(int amount)throws InterruptedException{
balance = balance - amount;//is rolled back in case of a failure
if(balance<0{
retry();
}
}
And the timeunit defaults to SECONDS, so no need to configure that.
In Multiverse you only need to specify multiple blocking versions of a method if that method is exposed to non transactional methods. Transactional methods calling transactional methods, will always lift on the transaction of the outermost transactional call (Multiverse provides a flattened transaction model for nested transactions for now). This also means that it is very easy to create a timed blocking method on datastructures you don’t own.