What constitutes a transaction layer when talking about database systems?

4k views Asked by At

For example, LevelDB doesn't support multi-statement transactions. I read somewhere that you would have to deal with those in a "transactional layer".

What would this layer have to do to add transaction support to a lower-level library that doesn't support transactions?

2

There are 2 answers

0
Kiril On

There are various ways to define transactions and there are various ways to implement them. A common property of a transaction is that it's ACID:

  • Atomicity - all or nothing. All of the tasks of a database transaction must be completed; If incomplete due to any possible reasons, the database transaction must be aborted.
  • Consistency - serializability and integrity. The database must be in a consistent or legal state before and after the database transaction. It means that a database transaction must not break the database integrity constraints.
  • Isolation Data used during the execution of a database transaction must not be used by another database transaction until the execution is completed. Therefore, the partial results of an incomplete transaction must not be usable for other transactions until the transaction is successfully committed. It also means that the execution of a transaction is not affected by the database operations of other concurrent transactions.
  • Durability All the database modifications of a transaction will be made permanent even if a system failure occurs after the transaction has been completed.

A transaction may have several states:

  • Active State: It is divided into two phases. Initial Phase: a database transaction is in this phase while its statements start to be executed. Partially Committed Phase: a database transaction enters this phase when its final statement has been executed. At this phase, the database transaction has finished its execution, but it is still possible for the transaction to be aborted because the output from the execution may remain residing temporarily in main memory - an event like hardware failure may erase the output.
  • Failed State: A database transaction enters the failed state when its normal execution can no longer proceed due to hardware or program errors).
  • Aborted State: A database transaction, if determined by the DBMS to have failed, enters the aborted state. An aborted transaction must have no effect on the database, and thus any changes it made to the database have to be undone, or in technical terms, rolled back. The database will return to its consistent state when the aborted transaction has been rolled back. The DBMS's recovery scheme is responsible to manage transaction aborts.
  • Committed State: A database transaction enters the committed state when enough information has been written to disk after completing its execution with success. In this state, so much information has been written to disk that the effects produced by the transaction cannot be undone via aborting; even when a system failure occurs, the changes made by the committed transaction can be re-created when the system restarts.

LevelDB does not support transactions, however it does have some of the ACID properties:

  • Batch writes are atomic.
  • Consistency is up to you.
  • There is limited isolation support.
  • Durability is a configurable option.

So... back to your question:

Q:

What would this layer have to do to add transaction support to a lower-level library that doesn't support transactions?

A: It depends on how you define a transaction. If you define a transaction with the above-mentioned properties and if you want your transactions to be ACID, then you'd have to figure out if that's possible with LevelDB (most of the ACID properties are integrated) and then you'd have to write a wrapper around LevelDB which ensures that the states of the transactions are maintained properly. However, I'm not entirely sure that a wrapper alone would do it, so you may have to actually take the source code and modify it to truly support transactions.

0
amirouche On

Given your database is single threaded you can do the following:

  1. Using leveldb batch feature: Instead of overriding old key, create a new one. Also log key's old and new value.

  2. If the database crash at this point, lookup the log records and rollback the transaction by restate keys that were part of the transaction to their old value. Delete the log to complete the rollback.

  3. If the transaction is committed, delete old keys and delete log entries to complete commit.

Then you have a transaction for single threaded key/value store using multiple versions.

If the database is multithread you have to use MVCC (see Yahoo's Omid, PostgreSQL, Wiredtiger, bsddb...) and something like Precisely Serializable Snapshot Isolation (PSSI).