Record level locking and concurrency control: Difference between revisions

From m204wiki
Jump to navigation Jump to search
m (→‎Commit statement: link repair)
 
(12 intermediate revisions by 2 users not shown)
Line 89: Line 89:
====FIND statement====
====FIND statement====
<p>
<p>
The FIND statement immediately locks the set of records it has retrieved in share mode. If the locking is successful, none of the records in that set can be updated by another user until the entire request, including request continuation(s), has been completed or the records have been released by some form of the RELEASE statement, such as RELEASE RECORDS IN..., RELEASE ALL RECORDS, RELEASE COMMIT.</p>
The <var>Find</var> statement immediately locks the set of records it has retrieved in share mode. If the locking is successful, none of the records in that set can be updated by another user until the entire request, including request continuation(s), has been completed or the records have been released by some form of the <var>Release</var> statement, such as <var>Release Records In</var>..., <var>Release All Records</var>, <var>Release Commit</var>.</p>
<p>
<p>
A FIND statement executed in a loop releases the old found set as soon as the statement is re-executed. The final set selected by the FIND remains locked until the end of the request. An unlabeled FIND statement, such as a FIND AND PRINT COUNT statement, does not lock records at all.</p>
A <var>Find</var> statement executed in a loop releases the old found set as soon as the statement is re-executed. The final set selected by the <var>Find</var> remains locked until the end of the request. An unlabeled <var>Find</var> statement, such as a <var>Find And Print Count</var> statement, does not lock records at all.</p>
   
   
====FIND WITHOUT LOCKS statement====
====FIND WITHOUT LOCKS statement====
Line 256: Line 256:
After a CLEAR ON RECORD LOCKING CONFLICT or CLEAR ON FIND CONFLICT statement, a record locking conflict does not invoke the corresponding ON unit.</p>
After a CLEAR ON RECORD LOCKING CONFLICT or CLEAR ON FIND CONFLICT statement, a record locking conflict does not invoke the corresponding ON unit.</p>
   
   
===<b id="pause"></b>PAUSE statement===
===<b id="pause"></b>Pause statement===
   
   
====Purpose====
====Purpose====
<p>
<p>
You can use the PAUSE statement to cause the request to wait a specified number of seconds and then to retry the statement that caused the evaluation of the ON unit. </p>
You can use the <var>Pause</var> statement to cause the request to wait a specified number of seconds and then to retry the statement that caused the evaluation of the <var>ON</var> unit. </p>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of the PAUSE statement is: </p>
The format of the <var>Pause</var> statement is: </p>
<p class="syntax">PAUSE [<span class="term">n</span> | <span class="term">%variable</span>]
{{Template:Pause statement syntax}}
</p>
Where:
Where:
<ul>
<ul>
<li>The value of n must be in the range 0-600, allowing a maximum pause of 10 minutes. </li>
<li><var class="term">n</var> must be in the range 0-600, allowing a maximum pause of 10 minutes. </li>
   
   
<li>The %variable is interpreted as a numeric value representing the number of seconds to wait. The %variable must be in the range of 0-86400. </li>
<li><var class="term">%variable</var> is interpreted as a numeric value representing the number of seconds to wait. It must be in the range 0-86400. </li>
</ul>
</ul>
   
   
====Usage====
====Usage====
<p>
<p>
The PAUSE statement is a bumpable wait.</p>
The <var>Pause</var> statement is a bumpable wait.</p>
<p>
<p>
If n is not specified or is specified as zero, processing stops and does not continue until the user enters a carriage return. If n is specified, processing continues automatically after n seconds.</p>
If <var class="term">n</var> is not specified or is specified as zero, processing stops and does not continue until the user enters a carriage return. If <var class="term">n</var> is specified, processing continues automatically after <var class="term">n</var> seconds.</p>
<p>
<p>
If the %variable takes any non-null, non-numeric value or a numeric value in the range of 0-86400, the User Language request is canceled with the message:</p>
If <var class="term">%variable</var> takes any non-null, non-numeric value or a numeric value in the range 0-86400, the SOUL request is canceled with the message:</p>
<p class="code">M204.2650: PAUSE TIME-VARIABLE NOT IN RANGE
<p class="code">M204.2650: PAUSE TIME-VARIABLE NOT IN RANGE
</p>
</p>
<p>
<p>
A variable with a null or 0 value does a terminal read. For example, %a='xxx', is treated as if zero was specified and a read is issued.</p>
A variable with a null or 0 value does a terminal read. For example, <code>%a='xxx'</code> is treated as if zero was specified, and a read is issued.</p>


<p class="note"><b>Note:</b> You should generally specify small values for n and issue a PAUSE only when no records are held by the request. If n is large, the request can seem to be hung.  </p>
<p class="note"><b>Note:</b> You should generally specify small values for <var class="term">n</var> and issue a <var>Pause</var> only when no records are held by the request. If <var class="term">n</var> is large, the request can seem to be hung.  </p>
 
====See also====
 
The <var>[[$WakeUp]]</var> function is an alternative approach; it offers millisecond resolution pausing.


===Handling Parallel Query Option/204 record locking conflicts===
===Handling Parallel Query Option/204 record locking conflicts===
Line 340: Line 343:
In the preceding example, the first FIND AND RESERVE statement prevents access to TOTAL PREMIUM while its corresponding VEHICLE PREMIUMs are being changed.    </p>
In the preceding example, the first FIND AND RESERVE statement prevents access to TOTAL PREMIUM while its corresponding VEHICLE PREMIUMs are being changed.    </p>
   
   
===RELEASE RECORDS statement===
===Release Records statement===
<p>
<p>
Records found using the FIND AND RESERVE statement are held in exclusive status until the end of the request or until they are released explicitly by the user with the RELEASE RECORDS statement. The RELEASE RECORDS statement also can be used to release records from SORT statements or records obtained in share status by FIND statements issued in the regular form. Records released in this manner are no longer available to the request and might have to be found again. The original found set or list from which the sorted set was built is not affected.     </p>
Records found using the <var>Find And Reserve</var> statement are held in exclusive status until the end of the request or until they are released explicitly by the user with the <var>Release Records</var> statement. The <var>Release Records</var> statement also can be used to release records from <var>Sort</var> statements or records obtained in share status by <var>Find</var> statements issued in the regular form. Records released in this manner are no longer available to the request and might have to be found again. The original found set or list from which the sorted set was built is not affected. </p>


<p class="note"><b>Note:</b> To avoid producing confusing results, issue a RELEASE RECORDS statement at the end of a loop and not in the middle of one, since the statement relinquishes control of a found set. </p>
<p class="note"><b>Note:</b> To avoid producing confusing results, issue a <var>Release Records</var> statement at the end of a loop and not in the middle of one, since the statement relinquishes control of a found set. </p>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of the RELEASE RECORDS statement is:</p>
The format of the <var>Release Records</var> statement is:</p>
<p class="syntax">RELEASE RECORDS {IN <span class="term">label</span> | ON [LIST] <span class="term">listname</span>}
{{Template:Release Records statement syntax}}
</p>
<p>
<p>
where label is the statement label of the FIND statement that locked the records.</p>
where <var class="term">label</var> is the statement label of the FIND statement that locked the records.</p>
<p>
<p>
The RELEASE RECORDS statement is supported in remote file and scattered group contexts.</p>
The <var>Release Records</var> statement is supported in remote file and scattered group contexts.</p>
   
   
====Processing====
====Processing====
<p>
<p>
The RELEASE RECORDS statement removes all:</p>
The <var>Release Records</var> statement removes all:</p>
<ul>
<ul>
<li>Entries from the specified found set(s), thereby removing the record set lock</li>
<li>Entries from the specified found set(s), thereby removing the record set lock</li>
Line 367: Line 369:
</ul>
</ul>
<p>
<p>
When the RELEASE statement refers to a SORT statement, the space occupied by the temporary sorted record copies is released.</p>
When the <var>Release</var> statement refers to a <var>Sort</var> statement, the space occupied by the temporary sorted record copies is released.</p>
<p>
<p>
RELEASE RECORDS ON is equivalent to the CLEAR LIST statement.   </p>
<var>Release Records On</var> is equivalent to the <var>Clear List</var> statement. </p>
 
===RELEASE ALL RECORDS statement===
===Release All Records statement===
   
   
====Description====
====Description====
<p>
<p>
A RELEASE ALL RECORDS statement terminates the lock in share mode placed on records by the FIND statement. RELEASE ALL RECORDS statement also clears all lists and the results of all SORT statements, and sets the current record number to -1.   </p>
A <var>Release All Records</var> statement terminates the lock in share mode placed on records by the <var>Find</var> statement. <var>Release All Records</var> also clears all lists and the results of all <var>Sort</var> statements, and sets the current record number to -1. </p>
<p>
<p>
After a RELEASE ALL RECORDS statement is processed in a FOR EACH RECORD loop, subsequent references to the current record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available, and the first statement after the end of the loop is executed.   </p>
After a <var>Release All Records</var> statement is processed in a <var>For Each Record</var> loop, subsequent references to the current record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available, and the first statement after the end of the loop is executed. </p>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of this release statement is:</p>
The format of this release statement is:</p>
<p class="syntax">RELEASE ALL RECORDS
{{Template:Release All Records statement syntax}}
</p>
<p>
<p>
The RELEASE ALL RECORDS statement is supported in remote file and scattered group contexts.</p>
The <var>Release All Records</var> statement is supported in remote file and scattered group contexts.</p>
 
===RELEASE and COMMIT RELEASE statements with global foundsets and lists===
===RELEASE and COMMIT RELEASE statements with global foundsets and lists===
<p>
<p>
Line 404: Line 405:
</p>
</p>
   
   
==COMMIT statement==
==<b id="COMMIT statement"></b><b id="commit"></b>Commit statement==
<p>
<p>
A COMMIT statement ends the current transaction, dequeues checkpoints, and drops all LPU locks and exclusive record locks obtained by update statements (ADD, CHANGE, DELETE) for all files participating in the transaction. The COMMIT statement does not release record locks obtained by the FIND statement. The share record lock obtained by the FOR RECORD NUMBER statement is not released by a COMMIT statement executed inside a loop.</p>
A <var>Commit</var> statement ends the current transaction, dequeues checkpoints, and drops all LPU locks and exclusive record locks obtained by update statements (<var>[[Add statement|Add]]</var>, <var>[[Change statement|Change]]</var>, <var>[[Data maintenance#Delete statement|Delete]]</var>) for all files participating in the transaction.
The <var>Commit</var> statement does not release record locks obtained by the <var>[[Find statement (find records)|Find]]</var> statement. The share record lock obtained by the <var>[[For Record Number statement|For Record Number]]</var> statement is not released by a <var>Commit</var> statement executed inside a loop.</p>
<p>
<p>
The COMMIT statement is supported in remote context. If records on any remote nodes are updated, the COMMIT statement saves all remote updates on all remote nodes. Also, remote updates are committed automatically by the system when appropriate.</p>
The <var>Commit</var> statement is supported in remote context. If records on any remote nodes are updated, the <var>Commit</var> statement saves all remote updates on all remote nodes. Also, remote updates are committed automatically by the system when appropriate.</p>
   
   
====Syntax====
====Syntax====
<p>
{{Template:Commit statement syntax}}
The format of the COMMIT statement is:</p>
<p class="syntax">COMMIT [RELEASE]
</p>
   
   
====Example====
====Example====
<p class="code">BEGIN
<p class="code">begin
GET.REC: FIND ALL RECORDS FOR WHICH
get.rec: find all records for which
             LNAME = NELSON
             lname = 'NELSON'
         END FIND
         end find
         FOR EACH RECORD IN GET.REC
         for each record in get.rec
             ADD MONTH = NOV
             add month = 'nov'
             COMMIT
             commit
             PRINT FNAME AND LNAME AND EACH MONTH
             print fname and lname and each month
         END FOR
         end for
NAME.CT: COUNT RECORDS IN GET.REC
name.ct: count records in get.rec
         PRINT COUNT IN NAME.CT WITH ' RECORDS UPDATED'
         print count in name.ct and 'records updated'
END
end
</p>
</p>
   
   
===RELEASE option===
===Release option===
<p>
<p>
The RELEASE option of the COMMIT statement performs all the operations of the COMMIT and RELEASE ALL RECORDS statements. :</p>
The <var>Release</var> option of the <var>Commit</var> statement performs all the operations of the <var>Commit</var> and <var>[[Release All Records statement|Release All Records]]</var> statements:</p>
<table>
<table>
<tr class="head">
<tr class="head">
<th nowrap>After processing a <br>
<th nowrap>After processing a <br>
COMMIT&nbsp;RELEASE
Commit&nbsp;Release
statement ... </th>
statement ... </th>
<th valign="bottom">Any subsequent reference to the current...</th>
<th valign="bottom">Any subsequent reference to the current...</th>
</tr>
</tr>
 
<tr>
<tr>
<td nowrap>FOR EACH RECORD loop </td>
<td nowrap><var>[[For Each Record statement|For Each Record]]</var> loop </td>
<td>Record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available; the first statement after the end of each loop is executed.</td>
<td>Record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available; the first statement after the end of each loop is executed.</td>
</tr>
</tr>
 
<tr>
<tr>
<td>FOR EACH VALUE loop </td>
<td><var>[[For Each Value statement|For Each Value]]</var> loop </td>
<td>Value still obtains the last value processed. </td>
<td>Value still obtains the last value processed. </td>
</tr>
</tr>
Line 455: Line 454:
====Usage====
====Usage====
<p>
<p>
To avoid confusing results, it is recommended that COMMIT RELEASE be issued at the end of a loop and not in the middle of one.</p>
To avoid confusing results, it is recommended that <var>Commit Release</var> be issued at the end of a loop and not in the middle of one.</p>
   
   
===RELEASE and COMMIT RELEASE statements with global foundsets and lists===
===Release and Commit Release statements with global foundsets and lists===
<p>
<p>
The RELEASE statements and the COMMIT RELEASE statements empty the contents of a global found set, global sort set, or global list. The label and positions associated with a found set, sort set, or the list is still considered global, but it is empty. Global positions are not cleared by RELEASE or COMMIT RELEASE statements, however, without records there is nothing to process.    </p>
The <var>Release</var> statement and the <var>Commit Release</var> statement both empty the contents of a global found set, global sort set, or global list. The label and positions associated with a found set, sort set, or the list is still considered global, but it is empty. Global positions are not cleared by <var>Release</var> or <var>Commit Release</var> statements, however, without records there is nothing to process.    </p>
   
   
</div> <!-- end of toc limit div -->
</div> <!-- end of toc limit div -->
 
[[Category:SOUL]]
[[Category:SOUL]]

Latest revision as of 18:54, 23 July 2018

Overview

This article discusses aspects of request design related to concurrency control in a multi-user environment and presents statements and Model 204 options that can be used to ensure logical consistency.

Illustrating a concurrent update

A user executing a User Language request expects that the records retrieved will not be modified by another user's concurrent request until the user's own request has completed. For example, consider these two requests being run concurrently:

User 1

BEGIN BLUE.CARS: FIND ALL RECORDS FOR WHICH COLOR = BLUE END FIND FOR EACH RECORD IN BLUE.CARS PRINT MAKE AND COLOR END FOR END

User 2

BEGIN BLUE.BUICKS: FIND ALL RECORDS FOR WHICH MAKE = BUICK AND COLOR = BLUE END FIND FOR EACH RECORD IN BLUE.BUICKS CHANGE COLOR TO RED END FOR END

User 1 expects only the make and the color BLUE to be printed. User 2's request must be prevented from changing User 1's records before they are printed.

Record locking in Model 204

Conflicts arise when one or more users are reading a file and another user attempts to update the file or when two or more users attempt to perform file maintenance on the same records retrieved from that file. The technique used by Model 204 to prevent overlapping updates is called record level locking.

Record locking modes

Model 204 can lock records as a set of records or as a single record number. Model 204 performs record level locking in two modes:

Lock mode Allows...
Share One or more users to read a file. Any number of users can have shared control of a record or record set concurrently.
Exclusive Single user to update the file. An exclusive lock is not compatible with other exclusive locks nor with any shared locks.

All records in a record set have the same locking strength: they are all locked share, or exclusive, or they are all unlocked.

FIND statement records

Records located by a FIND statement, called a record set or found set, are locked based on the FIND statement specification:

  • FIND

    Locks the record set in share mode

  • FIND AND RESERVE

    Locks the record set in exclusive mode

  • FIND WITHOUT LOCK

    Does not lock record set

Once obtained record set locks are kept till a RELEASE or COMMIT RELEASE statement is executed or the request ends.

Record level locking evaluation rules

Request compilation and evaluation

Record-level locking is performed in the following manner. User Language requests are processed in two phases: compilation and evaluation. All requests can be compiled regardless of the operations to be performed or of other requests being compiled or evaluated at the same time. All requests are allowed to begin the evaluation stage.

When the evaluation involves records or sets of records, Model 204 automatically ensures that operations achieves the expected results by adhering to the following set of rules. The following User Language statements generate found sets that are processed as described.

FIND statement

The Find statement immediately locks the set of records it has retrieved in share mode. If the locking is successful, none of the records in that set can be updated by another user until the entire request, including request continuation(s), has been completed or the records have been released by some form of the Release statement, such as Release Records In..., Release All Records, Release Commit.

A Find statement executed in a loop releases the old found set as soon as the statement is re-executed. The final set selected by the Find remains locked until the end of the request. An unlabeled Find statement, such as a Find And Print Count statement, does not lock records at all.

FIND WITHOUT LOCKS statement

The FIND WITHOUT LOCKS statement executes a FIND statement without locking any records. The found set of records is indistinguishable from a list, except that it is referenced with an IN label clause. You must use the FIND WITHOUT LOCKS statement with caution, otherwise logical inconsistencies might occur. See FIND WITHOUT LOCKS statement for more information.

FOR RECORD NUMBER statement

The FOR RECORD NUMBER statement locks the specified record in share mode, if it was not locked by the FIND statement. The lock is kept until the end of the loop or a COMMIT statement is processed.

DELETE ALL RECORDS IN statement

The DELETE ALL RECORDS IN statement temporarily locks the set of records to be deleted in exclusive mode before deletion occurs. The locking does not succeed if another user has access to any of the records through a FIND or file maintenance statement. Once a record has been deleted, the exclusive lock on the record is released, because the record no longer exists in the file.

ADD, CHANGE, or DELETE, DELETE RECORD, and INSERT statements

The ADD, CHANGE, DELETE fieldname, DELETE RECORD, and INSERT statements all lock the current record in exclusive mode before updating it. The exclusive single record lock remains on the current record until it passes through the loop, unless the record has been deleted.

Upon completion of a DELETE RECORD statement the deleted record cannot cause a record locking conflict. However, it the deleting user attempts to reference the deleted record via a previously established found set or list, the following message is issued:

M204.1266: NONEXISTENT RECORD REFERENCED

STORE RECORD statement

The STORE RECORD statement gets a LPU record lock for the TBO files and does not get a record lock for non-TBO files.

  • For TBO files, an LPU record lock, which is always exclusive, is obtained, meaning unconditionally gotten, at the beginning of the STORE RECORD processing. However, other users cannot get a record locking conflict, because the record's existence bit is not turned on until STORE RECORD processing finishes. If you store a record, you automatically obtain an LPU lock and hold it until the next COMMIT statement is processed.
  • For non-TBO files, no record lock of any kind is obtained. However, the record existence bit is not turned on until STORE RECORD processing is finished, so there are no problems with protecting the record from other users during STORE RECORD processing.

END MORE statement

If a request ends with END MORE, records found by that request remain locked and cannot be modified by other users. If the request ends with END, all records are released as soon as execution is completed.

Locking conflicts

If Model 204 cannot lock a record, a locking conflict occurs, which are discussed in detail in Handling locking conflicts.

FIND WITHOUT LOCKS statement

The FIND WITHOUT LOCKS statement executes a FIND statement without locking any records. The resulting found set is indistinguishable from a list, except that it is referenced with an IN label clause.

Note: The FIND WITHOUT LOCKS feature should be used only to solve specific performance problems. Before using the FIND WITHOUT LOCKS statement, please take into account the FIND WITHOUT LOCKS statement following Responding to a record locking conflict.

Syntax

The format of the FIND WITHOUT LOCKS statement is:

{FIND WITHOUT LOCKS | FDWOL} [ALL] RECORDS [IN label | ON [LIST] listname] [FOR WHICH | WITH] retrieval-conditions

Usage notes

Issues involved with using FIND WITHOUT LOCKS include:

  • Logical integrity of data is at risk when another user:
    • Is in the midst of changing values which are related
    • Changes or deletes the field which caused the record to be found
  • Physical integrity error messages or snaps are generated, including:
    • SICK RECORD messages are sent when extension records are deleted. The record is not really sick; temporarily it appears that way to Model 204.
    • SICK RECORD messages are sent from FOR EACH OCCURRENCE (FEO) statements when the record is modified by another user. Again, the record is not really sick.
    • NONEXISTENT RECORD messages are sent when entire records are deleted.
  • Examples of appropriate use of the FIND WITHOUT LOCKS statement include:
    • When there is one user at a time per record (for example, scratch records or bank teller applications where an account is usually modified by one teller at a time)
    • Report programs in a heavy update environment
  • Examples of inappropriate uses of the FIND WITHOUT LOCKS, which can result in snaps, include:
    • Report program in a heavy delete environment (results in many NONEXISTENT RECORD messages)
    • Retrievals in which the selection criteria can be changed by other users
    • Reuse Record Number files, except possibly scratch files keyed on the user ID

Handling locking conflicts

A typical locking situation is as follows. The first user issues a FIND statement for a large set of records and begins printing a long report. The second user issues a FIND statement for some of the same records and tries to update them with a CHANGE statement.

ENQRETRY parameter

The number of times a request automatically attempts to lock a record or set of records before notifying the user of a conflict is determined by the ENQRETRY parameter. Between attempts, Model 204 waits until the record or records that were held by another user are released or until three seconds pass.

Under these circumstances, the second user must decide whether to cancel the request or try again. The second user receives a message noting that the locking failed and is queried: DO YOU REALLY WANT TO TRY AGAIN? The second user can respond in one of three ways:

  • Reply N, thereby cancelling the request.
  • Reply Y and try to lock again immediately.
  • Wait a minute or two and reply Y.

Responding to a record locking conflict

In Model 204 you can specify the action to take if, an effort to lock a set of records is unsuccessful. The following statements specify the action to take in detail.

ON clause Can be used for...
RECORD LOCKING CONFLICT Any type of conflict, including a retrieval statement conflict, that arises during a record locking attempt.
FIND CONFLICT Only a conflict that arises during the evaluation of a FIND statement or a FOR EACH RECORD statement used for retrieval.

Syntax

The format for these ON units is:

[label] ON {RECORD LOCKING CONFLICT | FIND CONFLICTS}

If both types of ON units are active

ON RECORD LOCKING CONFLICT and ON FIND CONFLICT follow the same rules as other ON units (see ON units). If both ON RECORD LOCKING CONFLICT and ON FIND CONFLICT are active within a request when a conflict occurs, the conflict is handled in the following manner:

If the conflict results from... Clause invoked...
FIND statement or FOR EACH RECORD statement used for retrieval ON FIND CONFLICT
A condition other than the FIND or FOR EACH RECORD statement used for retrieval ON RECORD LOCKING CONFLICT

CLEAR ON statement

The definition of an ON RECORD LOCKING CONFLICT or ON FIND CONFLICT unit is cleared by the following statement:

CLEAR ON {RECORD LOCKING CONFLICT | FIND CONFLICTS}

After a CLEAR ON RECORD LOCKING CONFLICT or CLEAR ON FIND CONFLICT statement, a record locking conflict does not invoke the corresponding ON unit.

Pause statement

Purpose

You can use the Pause statement to cause the request to wait a specified number of seconds and then to retry the statement that caused the evaluation of the ON unit.

Syntax

The format of the Pause statement is:

Pause [n | %variable]

Where:

  • n must be in the range 0-600, allowing a maximum pause of 10 minutes.
  • %variable is interpreted as a numeric value representing the number of seconds to wait. It must be in the range 0-86400.

Usage

The Pause statement is a bumpable wait.

If n is not specified or is specified as zero, processing stops and does not continue until the user enters a carriage return. If n is specified, processing continues automatically after n seconds.

If %variable takes any non-null, non-numeric value or a numeric value in the range 0-86400, the SOUL request is canceled with the message:

M204.2650: PAUSE TIME-VARIABLE NOT IN RANGE

A variable with a null or 0 value does a terminal read. For example, %a='xxx' is treated as if zero was specified, and a read is issued.

Note: You should generally specify small values for n and issue a Pause only when no records are held by the request. If n is large, the request can seem to be hung.

See also

The $WakeUp function is an alternative approach; it offers millisecond resolution pausing.

Handling Parallel Query Option/204 record locking conflicts

If a client request cannot complete because of a record locking conflict on the server system, the server automatically tries again to lock the record or set of records. The server tries again until it succeeds or until it has tried as many times as the value of the client thread ENQRETRY parameter. The value of the ENQRETRY parameter that is specified on the server thread has no effect on the number of retries.

If ENQRETRY attempts to lock a record or set of records do not succeed, the server notifies the client about the conflict. If an ON RECORD LOCKING or ON FIND CONFLICT unit is active, the unit is invoked. Otherwise, the client receives a message that the locking failed, followed by a prompt asking if the client wants to try again.

If the client enters N, the request is canceled. If the client enters Y, the server repeats the locking attempt cycle, making as many as ENQRETRY attempts before prompting again.

Record locking and release statements

The following statements can place a lock on a set of records or remove the lock placed on records.

Note: To remove the lock placed on record sets, you can also use the COMMIT RELEASE for of the COMMIT statement.

FIND AND RESERVE statement

A User Language request can lock records in exclusive mode by using the FIND AND RESERVE statement. However, because records are exclusively locked, concurrency is reduced.

Syntax

The basic format of the FIND AND RESERVE statement is:

FIND AND RESERVE [ALL] RECORDS FOR WHICH

Example

BEGIN ON RECORD LOCKING CONFLICT PRINT 'RECORD LOCKING CONFLICT OCCURRED WITH ' - WITH $RLCUSR PRINT 'FILE ' WITH $RLCFILE PRINT 'RECORD ' WITH $RLCREC END ON POL.HLDR: IN CLIENTS FIND AND RESERVE ALL RECORDS - FOR WHICH POLICY NO = 100015 RECTYPE = POLICYHOLDER END FIND OWNER.POL: IN VEHICLES FIND AND RESERVE ALL RECORDS - FOR WHICH OWNER POLICY = 100015 END FIND FOR EACH RECORD IN OWNER.POL %NEW.PREMIUM = VEHICLE PREMIUM + 100 CHANGE VEHICLE PREMIUM TO %NEW.PREMIUM %TOTAL.PREMIUM = %TOTAL.PREMIUM + %NEW.PREMIUM END FOR FOR EACH RECORD IN POL.HLDR CHANGE TOTAL PREMIUM TO %TOTAL.PREMIUM END FOR END

In the preceding example, the first FIND AND RESERVE statement prevents access to TOTAL PREMIUM while its corresponding VEHICLE PREMIUMs are being changed.

Release Records statement

Records found using the Find And Reserve statement are held in exclusive status until the end of the request or until they are released explicitly by the user with the Release Records statement. The Release Records statement also can be used to release records from Sort statements or records obtained in share status by Find statements issued in the regular form. Records released in this manner are no longer available to the request and might have to be found again. The original found set or list from which the sorted set was built is not affected.

Note: To avoid producing confusing results, issue a Release Records statement at the end of a loop and not in the middle of one, since the statement relinquishes control of a found set.

Syntax

The format of the Release Records statement is:

Release Records {In label | On [List] listname}

where label is the statement label of the FIND statement that locked the records.

The Release Records statement is supported in remote file and scattered group contexts.

Processing

The Release Records statement removes all:

  • Entries from the specified found set(s), thereby removing the record set lock
  • List entries, when issued against list(s)
  • The user's single record locks.

When the Release statement refers to a Sort statement, the space occupied by the temporary sorted record copies is released.

Release Records On is equivalent to the Clear List statement.

Release All Records statement

Description

A Release All Records statement terminates the lock in share mode placed on records by the Find statement. Release All Records also clears all lists and the results of all Sort statements, and sets the current record number to -1.

After a Release All Records statement is processed in a For Each Record loop, subsequent references to the current record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available, and the first statement after the end of the loop is executed.

Syntax

The format of this release statement is:

Release All Records

The Release All Records statement is supported in remote file and scattered group contexts.

RELEASE and COMMIT RELEASE statements with global foundsets and lists

The RELEASE statements and the COMMIT RELEASE statements empty the contents of a global found set, global sort set, or global list. The label and positions associated with a found set, sort set, or the list is still considered global, but it is empty. Global positions are not cleared by RELEASE or COMMIT RELEASE statements, however, without records there is nothing to process.

Lock pending updates

Model 204 provides a special facility, lock pending updates, that prevents updated records in one transaction (a sequence of file updating operations) from being used by other applications until the transaction ends. Lock pending updates ensures logical consistency without requiring the use of the FIND AND RESERVE statement. LPU locks are distinct from single record locks.

Processing

If the lock pending updates option is specified, records are locked in share mode by a FIND statement. The first update to a record locks the record in exclusive mode and adds it to a set of updated locked records called the pending update pool. The record is not released from this exclusive lock at the end of the FOR EACH RECORD loop. Instead, the record is locked until the end of the transaction when the entire pending update pool is released.

Set with the FOPT parameter

Lock pending updates is an option of the FOPT parameter that is enabled or disabled on a file-by-file basis.

Commit statement

A Commit statement ends the current transaction, dequeues checkpoints, and drops all LPU locks and exclusive record locks obtained by update statements (Add, Change, Delete) for all files participating in the transaction. The Commit statement does not release record locks obtained by the Find statement. The share record lock obtained by the For Record Number statement is not released by a Commit statement executed inside a loop.

The Commit statement is supported in remote context. If records on any remote nodes are updated, the Commit statement saves all remote updates on all remote nodes. Also, remote updates are committed automatically by the system when appropriate.

Syntax

Commit [Release]

Example

begin get.rec: find all records for which lname = 'NELSON' end find for each record in get.rec add month = 'nov' commit print fname and lname and each month end for name.ct: count records in get.rec print count in name.ct and 'records updated' end

Release option

The Release option of the Commit statement performs all the operations of the Commit and Release All Records statements:

After processing a

Commit Release

statement ...
Any subsequent reference to the current...
For Each Record loop Record in the loop cannot find a current record. If processing returns to the top of the loop, no new record is available; the first statement after the end of each loop is executed.
For Each Value loop Value still obtains the last value processed.

Usage

To avoid confusing results, it is recommended that Commit Release be issued at the end of a loop and not in the middle of one.

Release and Commit Release statements with global foundsets and lists

The Release statement and the Commit Release statement both empty the contents of a global found set, global sort set, or global list. The label and positions associated with a found set, sort set, or the list is still considered global, but it is empty. Global positions are not cleared by Release or Commit Release statements, however, without records there is nothing to process.