17.1.1 I/O Operations

One can execute I/O operations within a lock-based critical section, and, at least in principle, from within an RCU read-side critical section. What happens when you attempt to execute an I/O operation from within a transaction?

The underlying problem is that transactions may be rolled back, for example, due to conflicts. Roughly speaking, this requires that all operations within any given transaction be idempotent, so that executing the operation twice has the same effect as executing it once. Unfortunately, I/O is in general the prototypical non-idempotent operation, making it difficult to include general I/O operations in transactions.

Here are some options for handling of I/O within transactions:

  1. Restrict I/O within transactions to buffered I/O with in-memory buffers. These buffers may then be included in the transaction in the same way that any other memory location might be included. This seems to be the mechanism of choice, and it does work well in many common cases of situations such as stream I/O and mass-storage I/O. However, special handling is required in cases where multiple record-oriented output streams are merged onto a single file from multiple processes, as might be done using the ``a+'' option to fopen() or the O_APPEND flag to open(). In addition, as will be seen in the next section, common networking operations cannot be handled via buffering.
  2. Prohibit I/O within transactions, so that any attempt to execute an I/O operation aborts the enclosing transaction (and perhaps multiple nested transactions). This approach seems to be the conventional TM approach for unbuffered I/O, but requires that TM interoperate with other synchronization primitives that do tolerate I/O.
  3. Prohibit I/O within transactions, but enlist the compiler's aid in enforcing this prohibition.
  4. Permit only one special ``inevitable'' transaction [SMS08] to proceed at any given time, thus allowing inevitable transactions to contain I/O operations. This works in general, but severely limits the scalability and performance of I/O operations. Given that scalability and performance is a first-class goal of parallelism, this approach's generality seems a bit self-limiting. Worse yet, use of inevitability to tolerate I/O operations seems to prohibit use of manual transaction-abort operations.17.1
  5. Create new hardware and protocols such that I/O operations can be pulled into the transactional substrate. In the case of input operations, the hardware would need to correctly predict the result of the operation, and to abort the transaction if the prediction failed.

I/O operations are a well-known weakness of TM, and it is not clear that the problem of supporting I/O in transactions has a reasonable general solution, at least if ``reasonable'' is to include usable performance and scalability. Nevertheless, continued time and attention to this problem will likely produce additional progress.

Paul E. McKenney 2011-12-16