I am very familiar with the use of RDBMS transactions, but how can I make sure that the changes made to my data in memory are rolled back if the transaction failed? What if I don’t even use the database?
Here is a contrived example:
public void TransactionalMethod() { var items = GetListOfItems(); foreach (var item in items) { MethodThatMayThrowException(item); item.Processed = true; } }
In my example, I could require that the changes made to the items in the list be rolled back somehow, but how can I do this?
I know "software transactional memory", but I don’t know much about it, and it seems pretty experimental. I also know the concept of “countervailing transactions”, but this imposes the overhead of code execution / cancellation.
Subversion seems to be dealing with errors updating the working copy, forcing you to run the cleanup command.
Any ideas?
UPDATE:
Reed Copsi offers an excellent answer , including:
Work on a copy of the data, updating the original when committing.
This is my question on one level: what if an error occurs when committing ? We so often think of committing as an immediate operation, but in fact it can make a lot of changes to the data set. What happens if there are unavoidable things like OutOfMemoryException when commit is applied?
On the flip side, if someone goes for the rollback option, what happens if there is an exception during the rollback ? I understand things like Oracle RDBMS, it has the concept of rollback segments and UNDO logs, etc. But it does not mean serialization to disk (where, if it is not serialized to disk, this did not happen, but a failure means that you can investigate these magazines and recover from it), is it really possible?
UPDATE 2:
Answer from Alex made a good suggestion: it is the one who updates another object, then the commit phase is just changing the link to the new object from the current object. He went further to suggest that the object you are changing is actually a list of changed objects.
I understand what he says (I think), and I want to make the question more complicated as a result:
How, given this scenario, are you dealing with a lock? Imagine you have a list of customers:
var customers = new Dictionary<CustomerKey, Customer>();
Now you want to make changes to some of these clients, how do you apply these changes without blocking and replacing the entire list? For instance:
var customerTx = new Dictionary<CustomerKey, Customer>(); foreach (var customer in customers.Values) { var updatedCust = customer.Clone(); customerTx.Add(GetKey(updatedCust), updatedCust); if (CalculateRevenueMightThrowException(customer) >= 10000) { updatedCust.Preferred = true; } }
How do i do it? This (Alex suggestion) will mean blocking all clients when replacing a link to a list:
lock (customers) { customers = customerTx; }
While if I go in cycles, changing the link in the initial list, it is not atomic, and does not have a foul of a problem "what if it partially fails":
foreach (var kvp in customerTx) { customers[kvp.Key] = kvp.Value; }