Using U_VERSION in a locking strategy

Tony Marston - 12th December 2002
amended 24th December 2002

U_VERSION is a special field recognised by the UNIFACE run-time kernel. It may be defined as a field in any entity in the application model. Its benefits are only recognised when using a Cautious or Optimistic locking strategy. This causes the UNIFACE kernel to re-read a row that is being modified, then verify that it has not been changed by another process before applying a lock.

The kernel begins its verification with the first field in the row, comparing each field in order. If the kernel encounters a field named U_VERSION (Data Type = String, Interface Definition = C1) in the row it will check the value of this field for changes. If the value of U_VERSION has not changed UNIFACE assumes that nothing else in the row has changed. Without U_VERSION the UNIFACE kernel will check the value of every field in the row for changes.

If the data source is a relational DBMS the kernel will include the known value of U_VERSION in the "WHERE" clause of the "SELECT" statement. If the value of U_VERSION has changed the row will not be retrieved, and the kernel will not have to perform any comparisons of field values.

If the kernel detects that the row has changed it will stop the process of updating the row. If it has not changed then the kernel will increment the value of U_VERSION and update the row.

If the data source is a relational DBMS and OPTIMISTIC locking is employed one can save a complete access to the database. Instead of SELECT plus UPDATE you can have a single UPDATE WHERE ...... AND U_VERSION = x This will reduce the workload of the database.

It is important to note that the value of U_VERSION must not be changed while the record is held in the form. This may happen if you use putlistitems/occ and getlistitems/occ to transfer information from one entity to update another one. Before the getlistitems/occ you should remove U_VERSION from the list using delitem/id <list>,"U_VERSION".

It is important to understand that U_VERSION will always contain a printable ASCII character. Thus of the 256 possible values for a single byte only the values between ASCII 32 (space) and ASCII 126 will be used. When the kernel increments the value of U_VERSION and it already contains ASCII 126, it will instead be reset to ASCII 32.

The primary benefit of using U_VERSION is increased performance, but any savings will be minimal unless:

However, in certain environments the use of U_VERSION can present a risk to application integrity. U_VERSION should NOT be used when:

Where a single row is updated frequently it is possible that between the time that a process retrieves a row, then checks it for modifications that so many other processes have modified the row that the value of U_VERSION has cycled round to its original value. The process will assume that no changes have been made and update the row, overwriting all the intermediate changes performed by other processes.

Where a row is inserted by a non-UNIFACE process which leaves the value of U_VERSION as NULL, an attempt by UNIFACE to access the row will fail because the select statement will read as "AND WHERE U_VERSION = NULL". The U_VERSION field must therefore be initialized to one of the printable characters, usually "!".

Where a row is modified by a non-UNIFACE process which does not increment the value of U_VERSION, and that row has previously been read by a UNIFACE process, any subsequent checking by that UNIFACE process will detect no changes. The row will be updated, and any changes made by the non-UNIFACE process will be overwritten.

As it is doubtful that the performance benefits of using U_VERSION will be noticeable except under extreme circumstances it is therefore recommended that U_VERSION not be used in new UNIFACE applications.

Tony Marston
12th December 2002

Amendment history:

24th Dec 2002 Included additional points provided by Ulrich Merkel. These are indicated with a red border.