Scimore Company Blog
Ramblings on databases

Locking, concurrency and transaction isolation levels in v3.0

September 7, 2009 18:04 by scimore

As the new version approaches the final cut, we would like to highlight some of the features that were not documented yet:

Locking and multi version concurrency control (MVCC)
ScimoreDB uses locking to prevent readers to read uncommitted rows. By default, readers use MVCC and data modifications row level exclusive locks. Readers will only read last committed rows' version, if concurrent transaction modified row and not committed it yet.
Here can be potential issue with concurrent updates when index field(s) being updated (the row will be re-inserted). For example, let’s say reader transaction selects fields from the table based on indexed field field1, where field1 > 100. The query will look up the lowest row where field1 > 100 and continue reading all rows to the end of the index. At the same time, assume the update updates a single row where field1 = 500 to 50000. The database will mark the current row as deleted and insert new row much further in the index. So, when reader reach deleted row, it will read it, since modified transaction has not yet committed and when reach row with field1 = 50000, skip it, because transaction still not committed. Now, consider the transaction that modified row has committed right after reader has read field1=500. When reader will reach field1=50000, the row will be read too, since update transaction has been committed. In such case, the reader has read the same row twice: the old version field1=500 and the new field1=50000. Hence, this is not happens when update in place occurs (updating field that is not part of the index). To avoid such case, reader may add additional locking hints:
select * from mytable xlock row - turn off MVCC and use exclusive row level locks, like with update/delete/insert.
select * from mytable read consistent - when reader reach modified/new row that was not committed yet, it will wait for the transaction to commit.
Another solution is to use READ REPEATABLE transaction isolation level.


Transaction isolation levels.
The syntax either use:
begin tran <isolevel> ... commit/rollback

or

set transaction isolation level <isoLevel>; SQL command;

ScimoreDB supports 3 isolation levels (<isoLevel>):

  1. READ COMMITTED - this is default isolation level. Readers will read only committed rows. Using locking hints you can optimize how to deal with modified/new not committed row as described above. The update/insert/delete will always use row-level locking and if row is modified by concurrent transaction will wait for commit.
  2. READ REPEATABLE - the isolation level is similar to SNAPSHOT isolation level in SQL Server. When read repeatable transaction starts it will see all rows at the point it started and any further modifications will not be visible for the particular transaction. For example:
    1st transaction updated row from value 0 to 100, but not committed yet. When starts second READ REPEATABLE transaction, at this point the rows' value will be 0 if it will read, since the 1st transaction has not committed when 2nd started. 3rd transaction starts, modify another row, set value 1 to 101 and commit. Still, the 2nd transaction will not "see" the change. However, other new started transactions will see the change made by the 3rd transaction. If DB crash at this point, recovery will apply 3rd update and abort 1st transaction update, since it was not committed during crash.
    READ REPEATABLE uses row versioning to store old versions of modified rows located in "sysundo.dat" file. Therefore, “sysundo.dat” file may grow in size until commit.
    Using SET TRANSACTION ISOLATION LEVEL REPEATABLE READ will commit current transaction when the reader read all rows. For example, SQL batch:
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
    select * from mytable  - until the client read all rows, the read repeatable transaction will not commit and maintain row versioning in "sysundo.dat".
  3. SERIALIZABLE - only 1 transaction at the time.

 

How to shring sysundo.dat & sysredo.log.
Sysredo.dat file is the transaction log. It always grows until checkpoint. By default, the checkpoint occurs every 5 minutes (it can be changed in the configuration). So, for example, single transaction inserting/updating/deleting many rows may noticeably increase sysredo.dat file size. Even, if after checkpoint the file space will be re-used, it might be ok for servers, but unacceptable for the embedded database. In such case you may execute: TRUNCATE TRANSACTION LOG sql command to truncate “sysundo.dat” and “sysredo.log” files. Note, the truncate transaction is serializable, i.e. no other transaction will run until it done and, also, the truncate will wait for all pending transaction to commit without allowing new once to start.

Disk space savings in the new engine.
The new engine uses much less disk space, usually 4-8 times less to compare with v2.5. This has been achieved by compressing of internal rows' attributes and using new b+tree splitting algorithm that does not pre-allocate 50% (8kb) disk space on page splitting.

Why *.dat files size never change in file explorer?
ScimoreDB opens files in exlusive mode, without Windows file manager cache. Therefore, the file size change is invisible in explorer. To see the current size of the table you can use manager, right click on the table, choose alter table... and then click on statistics tab, or, re-start the database.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Related posts

Comments are closed