Skip Headers
Oracle® TimesTen In-Memory Database Operations Guide
Release 11.2.1

Part Number E13065-03
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

8 Transaction Management and Recovery

TimesTen supports transactions that provide atomic, consistent, isolated and durable (ACID) access to data.

TimesTen transactions support ANSI Serializable and ANSI Read_Committed levels of isolation. ANSI Serializable isolation is the most stringent transaction isolation level. ANSI Read_Committed allows greater concurrency. Read_Committed is the default and is an appropriate isolation level for most applications. These isolation levels can be combined with each other and with a range of durability options.

TimesTen allows applications to choose the transaction features they need so they do not incur the performance overhead of features they do not need. See "Data Store Attributes" in Oracle TimesTen In-Memory Database Reference for details on how to set isolation levels and durability options.

The main topics in this chapter are:

TimesTen commit behavior

TimesTen closes cursors on commit and rollback. The Oracle Database supports cursors that stay open across transaction boundaries.

In TimesTen releases before 11.2.1, DDL statements were executed as part of the current transaction and were committed or rolled back along with the rest of the transaction. DDL statements include the following:

In contrast, the Oracle Database issues an implicit commit before and after any DDL statement.

Beginning with release 11.2.1, TimesTen issues an implicit commit before and after any DDL statement by default. This behavior is controlled by the DDLCommitBehavior attribute, which is set to 0 (Oracle behavior) by default. See "DDLCommitBehavior" in the Oracle TimesTen In-Memory Database Reference.

Consequences of TimesTen default commit behavior beginning with release 11.2.1 include:

Transaction semantics

TimesTen maintains user-specified levels of isolation, atomicity and durability. As a transaction modifies data in a data store, locking, versioning and logging are used to ensure ACID properties:

The following table shows how TimesTen uses locks and logs:

If Then
Transaction is terminated successfully (committed)
  • Log is posted to disk if the DurableCommits attribute is turned on.
  • Newly modified values of data are made available for other transactions to read and to modify.

  • Locks that were acquired on behalf of the transaction are released and the corresponding data becomes available to other transactions.

Transaction is rolled back
  • Log is used to undo the effects of the transaction and to restore any modified data items to the state they were before the transaction began.
  • Locks that were acquired on behalf of the transaction are released.

System fails (data not committed)
  • On first connect, TimesTen automatically performs data store recovery by reading the latest checkpoint image and applying the log to restore the data store to its latest transactionally consistent state. See "Checkpoints".
Application fails
  • Transaction is rolled back.

TimesTen supports temporary data stores, which have essentially no checkpoints. Recovery is never done for such data stores. They will be destroyed after a data store or application shuts down or fails.

Transactions are started automatically on behalf of an application as needed. Virtually all operations on the data store, even those that do not modify or access application data, require transactional access. For example, compaction and checkpoint operations begin a transaction if one has not already been started. An application can commit a transaction by calling the ODBC SQLTransact (henv, hdbc, SQL_COMMIT) function or JDBC Connection.commit method, or abort it by calling the ODBC SQLTransact (henv, hdbc, SQL_ROLLBACK) function or Connection.rollback method. Any subsequent data store operation will automatically cause a new transaction to be started.

In compliance with ODBC standards, the default AUTOCOMMIT setting is ON. Commits are costly for performance and can be intrusive if they are implicit.TimesTen recommends that you turn AUTOCOMMIT off so that commits are intentional. Use the ODBC SQLSetConnectOption function or JDBC Connection.setAutoCommit(false) method in your TimesTen application to set SQL_AUTOCOMMIT_OFF.

When using ODBC or JDBC batch operations to INSERT, UPDATE or DELETE several rows in one call, when AUTOCOMMIT is on, a commit occurs after the entire batch operation has completed. If there is an error during the batch operation, those rows that have been successfully modified will be committed. If an error occurs due to a problem on a particular row, the preceding rows are committed. The pirow parameter to the ODBC SQLParamOptions function contains the number of the row in the batch that had the problem.

Even with durable commits and autocommit enabled, you could lose work if there is a failure or the application exits without closing cursors. An open cursor under AUTOCOMMIT means that you are in effect running with AUTOCOMMIT off but without the ability to rollback. Write locks from DDL or DML are held until all cursors are closed.

Note:

Autocommit is the default mode for ODBC applications. Applications must explicitly turn autocommit off to avoid it.

Transaction atomicity and durability

The TimesTen Data Manager provides durability with checkpointing. See "Checkpoints" and "Log files" for more information.

Because transaction support adds overhead to execution time, TimesTen allows applications to choose from the following options:

The following table summarizes the guarantees and limitations of the atomicity and durability options:

Attribute Setting Non-blocking checkpoints possible? Row-level locking possible? Transaction rollback possible? Recovery procedure Committed transactions vulnerable to loss
Durable Commits = 1 Yes Yes Yes Read most recent checkpoint image.

Apply log.

None
Durable Commits = 0 Yes Yes Yes Read most recent checkpoint image.

Apply log.

Transactions that committed after the last checkpoint or durable commit

The following sections describe these options in greater detail:

Guaranteed atomicity and durability

When you set the attribute DurableCommits=1, then durable commits are implemented and the log is written to disk at transaction commit. By default, all TimesTen transactions are durable. The effects of the transaction are persistent and will not be lost in the event of system failure.

Durability is implemented with a combination of checkpointing and logging. See "Checkpoints" and "Log files". A checkpoint operation writes the current data store image to a checkpoint file on disk, which has the effect of making all transactions that committed before the checkpoint durable. For transactions that committed after the last checkpoint, TimesTen uses conventional logging techniques to make them durable. As each transaction progresses, it records its data store modifications in an in-memory log. At commit time, the relevant portion of the log is flushed to disk. This log flush operation makes that transaction, and all previously-committed transactions, durable.

In the case of a system failure, recovery uses the last checkpoint image together with the log to reconstruct the latest transaction-consistent state of the data store.

In addition to being durable, by default all TimesTen transactions are also atomic. Either all or none of the effects of the transaction is applied to the data store.

Atomicity is implemented by using the log to undo the effects of a transaction if it is rolled back. Rollback can be caused explicitly by the application, using the ODBC SQLTransact function or JDBC Connection.rollback method, or during data store recovery because the transaction was not committed at the time of failure.

In order to have guaranteed atomicity and durability, applications must set the DurableCommit attributes to 1.

Guaranteed atomicity, delayed durability

When you set the attribute DurableCommits=0, then durable commits are not implemented and the log is not written to disk at transaction commit. It is possible to connect to a data store with guaranteed durability disabled. In this case, the atomicity of a transaction is guaranteed, but not its durability. This mode is known as delayed durability mode.

In delayed durability mode, as in guaranteed durability mode, each transaction enters records into the in-memory log as it makes modifications to the data store. However, when a transaction commits in delayed durability mode, it does not wait for the log to be posted to disk before returning control to the application. Since the content of the in-memory log would be lost in a system failure, transactions committed in this mode are not durable.

Non-durable committed transactions have much better response time than durable-committed transactions, because no I/O is required to commit the transaction. A non-durable committed transaction can be made durable either by checkpointing or by committing a subsequent transaction durably. See "Checkpoints" for more information. As with guaranteed durability mode, a checkpoint makes all transactions that committed before the checkpoint durable. Committing a transaction durably commits that transaction and makes all previously committed transactions durable.

Applications that wish to take advantage of the performance benefits of delayed durability mode but which can only tolerate the loss of a small number of transactions can perform periodic durable commits in a background process - only those transactions that committed non-durably after the last durable commit are vulnerable to loss in the event of a system failure.

Applications request delayed durability mode by setting the DurableCommits attribute to 0. When in this mode, applications can call the ttDurableCommit built-in procedure to force the current transaction to commit durably when it commits.

Controlling durability and logging

Applications can control whether a transaction is durable; however, log files are always created.

Using durable commits

The performance cost of durable commits can be mitigated if many threads are running at the same time, due to an effect called "group commit." Under group commit, a single disk write commits a group of concurrent transactions durably. Group commit does not improve the response time of any given commit operation, as each durable commit must wait for a disk write to complete, but it can significantly improve the throughput of a series of concurrent transactions.

When durable commits are used frequently, TimesTen can support more connections than there are CPUs, as long as transactions are short. This is true because each connection spends more time waiting to commit than it spends using the CPU. This is in contrast to applications that do infrequent durable commits, in which case each connection tends to be very CPU-intensive for the TimesTen portion of its workload. In the latter case, using more connections than there are processors will tend to give worse performance, due to CPU contention.

Applications that require lower response time and can tolerate some transaction loss may elect to perform periodic durable commits. By committing only every nth transaction durably, or performing a durable commit every n seconds typically in a background process, an application can achieve quick response time while maintaining a small window of vulnerability to transaction loss.

Because a durable commit commits not only itself but all previously-committed transactions durably - even those performed by other threads or other processes, an application that commits every n transactions durably only risks the loss of the last n transactions.

Similarly, an application that performs a durable commit every n seconds, risks only the transactions that committed during the last n seconds.

To enable periodic durable commits, an application connects with DurableCommits=0, so transactions commit non-durably by default. When a durable commit is needed, the application calls the ttDurableCommit built-in procedure before committing. As with all SQL statements, it is best to prepare the call to ttDurableCommit if it will be used frequently. The ttDurableCommit built-in procedure does not actually commit the transaction; it merely causes the commit to be durable when it occurs.

Another option for avoiding data loss is to use TimesTen replication instead of durable commits to maintain a copy of the data in two memories. Although two memories are not as durable as disk, replication can provide higher data availability by allowing for failover without data store recovery. This type of trade-off is common in high-performance systems. For more details on TimesTen replication, see the Oracle TimesTen In-Memory Database TimesTen to TimesTen Replication Guide.

Log files

All log files are created in the same directory as the data store files unless the LogDir attribute specifies a different location. The log file names have the form ds_name.logn, where ds_name is the data store path name given in the data store's DSN and n is the log file number, starting at zero.

To retain archived log files, set the LogPurge attribute to 0. When the LogPurge attribute is not set for the data store connection, TimesTen renames log files no longer needed to perform recovery to ds_name.logn.arch. In this case, the application is responsible for removing these unneeded log files. See "LogPurge" in the Oracle TimesTen In-Memory Database Reference for details on purging log files.

Concurrency control

Transaction isolation allows each active transaction to operate as if there were no other transactions active in the system. TimesTen supports two transaction isolation levels: ANSI Serializable and ANSI Read_Committed isolation.

Transaction isolation levels

  • In ANSI Serializable isolation, each transaction acquires locks on all data items that it reads or writes. It holds these locks until it commits or rolls back. As a result, a row that has been read by one transaction cannot be updated or deleted by another transaction until the original transaction terminates. Similarly, a row that has been inserted, updated or deleted by one transaction cannot be accessed in any way by another transaction until the original transaction terminates.

    Repeatable reads are assured: a transaction that executes the same query multiple times is guaranteed to see the same result set each time. Other transactions cannot UPDATE or DELETE any of the returned rows, nor can they INSERT a new row that satisfies the query predicate.

    In this isolation level, readers can block writers and writers can block readers and other writers.

  • In ANSI Read Committed isolation, each transaction acquires locks only on the items that it writes. Items read by SELECT statements, the SELECT portion of INSERT SELECT statements and MERGE statements, are not locked. This is the default isolation level for TimesTen.

    In this isolation level, readers do not block writers, nor do writers block readers, even when they read and write the same data items. To allow readers and writers to access the same items without blocking, writers create private copies of the items that they update. These private copies become public when the transaction commits, or are discarded if the transaction rolls back. Therefore, when a transaction reads an item that has been updated by another in-progress transaction, it sees the state of that item before it was updated. It cannot see an uncommitted state.

    Non-repeatable reads are possible in this isolation level. If a read committed transaction executes the same query multiple times, the commit of an updater transaction may cause it to see different results.

Using read committed isolation level can lead to duplicates in a result set. A SELECT statement selects more or less rows than the total number of rows in the table if some rows were added or removed and committed in the range that the SELECT scan is happening. This may happen when an UPDATE, INSERT or DELETE adds or deletes a value from an index and the SELECT scan is using this index. This can also happen when an INSERT or DELETE adds or deletes rows from the table and the SELECT operation is using an all-table scan.

This happens because index values are ordered and an UPDATE of an index value may delete the old value and insert the new value into a different place. In other words it moves a row from one position in the index to another position. If an index scan sees the same row in both positions, it returns the same row twice. This does not happen with a serial scan because table pages are unordered and rows do not need to be moved around for an UPDATE. Hence once a scan passes a row, it will not see that same row again.

The only general way to avoid this problem is for the SELECT to use serializable isolation. This prevents a concurrent INSERT, DELETE or UPDATE operation. There is no reliable way to avoid this problem with INSERT or DELETE by forcing the use of an index because these operations affect all indexes. With UPDATE, this problem can be avoided by forcing the SELECT statement to use an index that is not being updated.

All data access in TimesTen uses locking or copying to provide isolation. Applications set the transaction isolation level either using the SQLSetConnectOption ODBC function with the SQL_TXN_ISOLATION flag, or by setting the Isolation connection attribute.

To ensure that materialized views are always in a consistent state, all view maintenance operations are effectively performed under Serializable isolation, even when the transaction is otherwise in Read_Committed isolation. This means that the transaction will obtain read locks for any data items read during view maintenance. However, the transaction will release these read locks at the end of the INSERT, UPDATE or CREATE VIEW statement that triggered the view maintenance instead of holding them until it terminates.

Locking granularities

TimesTen supports row-level locks, table-level locks and data store-level locks:

  • With row-level locking, transactions usually obtain locks on the individual rows that they access, although a transaction may obtain a lock on an entire table if TimesTen determines that doing so would result in better performance. Row-level locking is the default and is the best choice for most applications, as it provides the finest granularity of concurrency control. To use row-level locking, applications must set the LockLevel connection attribute to 0 (the default value) or call the ttLockLevel built-in procedure with the lockLevel parameter set to Row.

    In order to CREATE, DROP, or ALTER a user, you can only use row-level locking and thus, the Locklevel must be set to 0 before you can perform any of these operations.

  • Table-level locking is useful for queries that access a significant portion of the rows of a table or when there are very few concurrent transactions that access a table. Enable the optimizer to choose table-level locking by calling the ttOptSetFlag built-in procedure and setting the TbleLock flag to 1. If both table-level and row-level locking are disabled, TimesTen chooses row-level locking. If both table-level and row-level locking are enabled, TimesTen chooses the locking scheme that is more likely to have better performance. Typically, table-level locking provides better performance than row-level locking because of reduced locking overhead. For more information, see "ttOptSetFlag" in Oracle TimesTen In-Memory Database Reference.

  • With data store-level locking, every transaction obtains an exclusive lock on the entire data store, thus ensuring that there is no more than one active transaction in the data store at any given time. Data store-level locking often provides better performance than row-level locking, due to reduced locking overhead. However, its applicability is limited to applications that never need to execute multiple concurrent transactions. With data store-level locking, every transaction effectively runs in ANSI Serializable isolation, since concurrent transactions are disallowed. To use data store-level locking, applications set the LockLevel connection attribute to 1 or call the ttLockLevel built-in procedure with the lockLevel parameter set to set to DS.

Coexistence of different locking levels

Different connections can coexist with different levels of locking, but the presence of even one connection using data store-level locking leads to reduced concurrency. For performance information, see "Choose the best method of locking".

Checkpoints

A checkpoint is an operation that saves the state of a data store to disk files, known as checkpoint files. By default, TimesTen performs "background" checkpoints at regular intervals. Alternatively, applications can programmatically initiate checkpoint operations. See "Setting and managing checkpoints" for more details.

Each TimesTen data store has two checkpoint files, named dsname.ds0 and dsname.ds1, where dsname is the data store path name specified in the data store's DSN. A checkpoint operation identifies the checkpoint file to which the last checkpoint was written and writes its checkpoint to the other file. Therefore, the two files always contain the two most recent data store images.

Data store recovery uses these files to recover the most recent transaction-consistent state of the data store after a data store shutdown or system failure. It identifies the file that contains the more recent of the two checkpoint images and applies the log to that file's data store image, as appropriate, to recover the up-to-date data store state. If any errors occur during this process, or if the more recent checkpoint image is incomplete, then recovery restarts, using the other checkpoint file. For example, if a system failure occurred while that checkpoint was begin written.

TimesTen also creates dsName.resn files for each data store. These files are pre-allocated space to the same size as a log file used by TimesTen for maintaining log files. The .res files allow the data store to remain operational when the log directory is full. If the log directory becomes full, an error is recorded and new transactions are prevented. Existing operations that cannot be recorded in a new log file are written to the .res files. When space becomes available in the log directory, the information in the .res files is copied to the log files and transactions can begin again.

A checkpoint operation has two primary purposes. First, it decreases the amount of time required for data store recovery, because it provides a more up-to-date data store image for recovery to begin with. Second, it makes a portion of the log unneeded for any future data store recovery operation, typically allowing one or more log files to be deleted. Both of these functions are very important to TimesTen applications. The reduction in recovery time is important, as the amount of log needed to recover a data store has a direct impact on the amount of downtime seen by an application after a system failure. The removal of unneeded log files is important because it frees disk space that can then be used for new log files. If these files were never removed, they would eventually consume all available space in the log directory's file system, causing data store operations to fail due to log space exhaustion.

For these reasons, either TimesTen applications should checkpoint their data stores periodically or you should set the data store first connection attributes CkptFrequency or CkptLogVolume, which determine how often TimesTen performs a "background" checkpoint.

Checkpointing may generate a large amount of I/O activity and have a long execution time depending on the size of the data store and the number of data store changes since the most recent checkpoint.

Types of checkpoints

TimesTen supports two kinds of data store checkpoints: Transaction-consistent checkpoints and Fuzzy or non-blocking checkpoints.

Transaction-consistent checkpoints

Transaction-consistent checkpoints, also known as blocking checkpoints, obtain an exclusive lock on the data store for a portion of the checkpoint, blocking all access to the data store during that time. The resulting checkpoint image contains the effects of all transactions that committed before the checkpointer obtained its lock. Because no transactions can be active while the data store lock is held, no modifications made by in-progress transactions are included in the checkpoint image.

Transaction-consistent checkpoints uses the log files during recovery to reapply the effects of transactions that committed durably after the checkpoint completed. To request a transaction-consistent checkpoint, an application uses the ttCkptBlocking built-in procedure. The actual checkpoint is delayed until the requesting transaction commits or rolls back. If a transaction-consistent checkpoint is requested for a data store for which both checkpoint files are already up to date then the checkpoint request is ignored.

Fuzzy or non-blocking checkpoints

Fuzzy checkpoints, or non-blocking checkpoints, allow transactions to execute against the data store while the checkpoint is in progress. Fuzzy checkpoints do not obtain locks of any kind, and therefore have a minimal impact on other data store activity. Because these other transactions may modify the data store while it is being written to the checkpoint file, the resulting checkpoint image may contain some effects of transactions that were active while the checkpoint was in progress. Furthermore, different portions of the checkpoint image may reflect different points in time. For example, one portion may have been written before a given transaction committed, while another portion was written afterward. The term "fuzzy checkpoint" derives its name from this fuzzy state of the data store image. TimesTen background checkpoints are always non-blocking.

To recover from a fuzzy checkpoint, TimesTen uses the log both to bring the various portions of the checkpoint into a consistent state with one another and to reapply the effects of transactions that committed durably after the checkpoint completed. To request a fuzzy checkpoint, an application uses the ttCkpt built-in procedure. This procedure issues a fuzzy checkpoint. As with all blocking checkpoints, the actual checkpoint is delayed until the requesting transaction commits or rolls back.

Setting and managing checkpoints

By default, TimesTen performs automatic non-blocking checkpoints in the background. In this case, background checkpoints are non-blocking. See "Fuzzy or non-blocking checkpoints" for more information.

Several data store attributes and built-in procedures are available to set, manage and monitor checkpoints. These include:

  • CkptFrequency attribute

  • CkptLogVolume attribute

  • CkptRate attribute

  • ttCkpt built-in procedure

  • ttCkptBlocking built-in procedure

  • ttCkptConfig built-in procedure

  • ttCkptHistory built-in procedure

TimesTen also automatically performs a transaction-consistent checkpoint when the last application disconnects from the data store, unless the RAM policy is always. For temporary data stores, checkpoints are still taken to purge the log files. See "Transaction-consistent checkpoints".

In addition, applications can programatically perform a checkpoint using the ttCkpt or ttCkptBlocking built in procedure. For details on how to call the ttCkpt and other TimesTen built-in procedures from a C or Java program, see "Calling TimesTen built-in procedures within C applications" in the Oracle TimesTen In-Memory Database C Developer's Guide or "Calling TimesTen built-in procedures" in the Oracle TimesTen In-Memory Database Java Developer's Guide.

By default, TimesTen performs background checkpoints at regular intervals. If an application attempts to perform a checkpoint while a background checkpoint is in progress, TimesTen returns an error to the application. To turn off background checkpointing, set CkptFrequency=0 and CkptLogVolume=0. You can also use the built-in procedure ttCkptConfig to configure background checkpointing or turn it off. The values set by ttCkptConfig take precedence over those set with the data store attributes.

Using these attributes and the built-in procedure, you can configure TimesTen to checkpoint either when the log files contain a certain amount of data or at a specific frequency. For information on default values and usage, see the Oracle TimesTen In-Memory Database Reference.

If the application attempts to back up a data store while a background checkpoint is in process, TimesTen waits until the checkpoint finishes and before beginning the backup. If a background checkpoint starts while a backup is in progress, the background checkpoint will not take place until the backup has completed. If a background checkpoint starts while an application-initiated checkpoint is in progress, then an error results.

You can use the ttCkptHistory built-in procedure to display the history of last eight checkpoints, the settings for checkpoint frequency and log volume and the status of in-progress checkpoint disk writes.

Setting the checkpoint rate for background checkpoints

By default, there is no limit to the rate at which checkpoints are written to disk. You can use the CkptRate attribute or the ttCkptConfig built-in procedure to set the maximum rate at which background checkpoints are written to disk, if you would like to have control over the rate. The rate is expressed in MB per second. Checkpoints taken during recovery and final checkpoints do not honor this rate; their rate is unlimited.

See the Oracle TimesTen In-Memory Database Reference for details on using these features.

Setting a rate too low can cause checkpoints to take an excessive amount of time and cause the following problems;

  • Delay the purging of unneeded log files

  • Delay the start of backup operations

  • Increase recovery time.

When choosing a rate, you should take into consideration the amount of data written by a typical checkpoint and the amount of time checkpoints usually take. Both of these pieces of information are available through the ttCkptHistory built-in procedure.

In addition, you can monitor the progress of a running checkpoint by looking at the Percent_Complete column of the ttCkptHistory result set. If a running checkpoint appears to be progressing too slowly, the rate can be increased by calling the ttCkptConfig built-in procedure. If a call to ttCkptConfig changes the rate, the new rate takes effect immediately, affecting even the running checkpoint.

A simple method of calculating the checkpoint rate is:

  1. Call the ttCkptHistory built-in procedure.

  2. For any given checkpoint, subtract the starttime from the endtime.

  3. Divide the number of bytes written by this elapsed time in seconds to get the number of bytes per second.

  4. Divide this number by 1024*1024 to get the number of megabytes per second.

When setting the checkpoint rate, some other things to consider are:

  • The specified checkpoint rate is only approximate. The actual rate of the checkpoint may be below the specified rate, depending on the hardware, system load and other factors.

  • Calculating the actual checkpoint rate using the above method may produce a result that is below the requested rate. This is because the starttime and endtime interval includes other checkpoint activities in addition to the writing of dirty blocks to the checkpoint file.

  • The Percent_Complete field of the ttCkptHistory call may show 100 percent before the checkpoint is actually complete. The Percent_Complete field shows only the progress of the writing of dirty blocks and does not include additional bookkeeping at the end of the checkpoint.

  • When adjusting the checkpoint rate, you may also need to adjust the checkpoint frequency, as a slower rate makes checkpoints take longer, which effectively increases the minimum time between checkpoint beginnings.