Talk:Transactions

Revision as of 11:12, 6 April 2007 by Clemahieu (Talk | contribs) (External example)

Discussion of the feasibility and desirability of implementing transactional concurrency in Eiffel.

Examples please

I think we need to see some examples (well, I do for one).

Examples

The main thing to remember is that the proposal states that all features calls are asynchronous.

Transactions are assured with transactional memory, probably implemented as software transactional memory.


Example of transaction:
feature
correct_removal(container: DISPENSER) is
 transaction -- This is a transaction so it is assured to be atomic and isolated
  if
   not(container.is_empty)
  then
   container.remove
  end
 end

This feature is assured to be correct because is is isolated and atomic with respect to the system. If the container has been modified between the call to is_empty and remove, the feature would be aborted and retried.


feature
incorrect_removal(container: DISPENSER) is
 do
  if
   not(container.is_empty)
  then
   container.remove
  end
 end

This is the standard example of concurrency issues with preconditions. The container can change between the call to is_empty and remove. Using transactions avoids this.


Example of concurrency:
feature
write_all_files is
 do
  write_file_1
  write_file_2
  write_file_3
  write_file_4
 end

Since all feature calls would be asynchronous, the four write_file features could be executed in parallel if the runtime decides to do so. This is not a transaction so isolation across these calls is not assured.


feature
write_file is
 external
  "operating_system_write"
 abort
  "operating_system_abort"
 commit
  "operating_system_commit"

This is how transactional features can be mapped on to external function calls that support transactional operations


feature
source: DISPENSER[ANY] --Where items are taken from
destination: DISPENSER[ANY] -- where items are put after processing
running: BOOLEAN -- Flag to stop processing

consumer is
 do
  from
  until
   not (running)
  loop --This loop will spawn multiple threads, microthreads, hyperthreads, or whatever the implementation is and runtime chooses, all processing a single item.
   process_single_item
  end
 end

process_single_item is
 local
  item: ANY
 transaction --Since this is a transaction, accessing the container is safe even when run concurrently.
  if
   not source.is_empty
  then
   item := source.item
   source.remove
   io.put_string(item.to_string)
   destination.put(item)
  end
 end


Legacy externals example

feature
use_legacy_external(item: LEGACY_ITEM) is
 do
  print_item(item)
  log_item(item)
  --At this point the runtime will block until print_item and log_item have both committed, it will ensure nothing is running in the system and then run the external item serially. This is the non-concurrent way to ensure something executes as a transaction, isolated and atomic.
  use_item(item)
 end

use_item(item: LEGACY_ITEM) is
 external
  "..."
 end

print_item(item: LEGACY_ITEM) is
 do
  ...
 end

log_item(item: LEGACY_ITEM) is
 do
  ...
 end