Selects and File Resizing
Published 23 AUG 2011 at 12:51:00PM by APK
In a previous blog on Latent and Resolved Selects, we talked about how processing through the Basic+ reduce function and select statements were quicker than using the RLIST command. As hinted at in the prior article, the speed increase comes with additional maintenance required by the developer. In this part of our series on Selection, we'll talk about this maintenance, and the steps you need to take.
There are three areas that the developer needs to be aware of. The first is file resizing. The second is readnext termination. The third is cursor status, which will be covered in the next in this series of postings.
File Resizing
As most of you know, Revelation's Linear Hash Filing System (LH) is more accurately known as "Linear hashing with two partial expansions, separate chaining, distributed control and variable length records". It's the "distributed control" portion we're interested in here, since that's the part that manages the file resizing.
Without going into a detailed technical discussion about how and why the system chooses to resize the file, we know it happens without requiring any specific action by the user. The system checks for a resize on certain file access. When a file resizes, it generally interacts with only one or two groups. The records in these groups can be split and moved anywhere across the entire file. This means, when you read a record from a table, you can potentially trigger a resize.
Since there is no way of knowing where the records in the group will move to, it's possible that the records will move to a group with a lower group number. This means it will be positioned earlier in the file than the current position.
This is important, because when the system is processing a non-indexed select without an active key list, it starts at group 0 and moves through each group, examining each record. If the file resizes while this is happening, a record can be moved to a group that has already been processed, meaning the record will be skipped. Of course, the opposite can happen as well, in that a record that has already been processed can be moved forward to a group that hasn't been processed yet. This record can then potentially show up twice.
To avoid this problem, the RLIST function increases the sizelock by two when issuing a select.
- A sizelock of 0 means the file will resize normally, growing or shrinking as required.
- A sizelock of 1 means the file will only grow when required. It will never shrink.
- A sizelock of 2 or more means the file will never resize.
Increasing the sizelock by two ensures that the file will not resize out from under you while the select is being processed.
Since you are managing the select and readnext yourself, and not RLIST, you need to manually set the sizelock. This can easily be accomplished using the FIX_LH routine.
$insert DB_MGMT_EQUATES equ INCREMENT_SIZELOCK$ to 1 call fix_lh( tableName, UPDATE_SIZELOCK$, INCREMENT_SIZELOCK$ )
When you have finished processing the list, you must decrement the sizelock back.
$insert DB_MGMT_EQUATES equ DECREMENT_SIZELOCK$ to 0 call fix_lh( tableName, UPDATE_SIZELOCK$, DECREMENT_SIZELOCK$ )
It's important to remember that you should not decrement the sizelock until after you have completely finish processing the file. That means when you have finished processing the readNext loop, not just after you have issued the select statement.
ReadNext Termination
The second item to be aware of is readnext termination. When working with a latent list, the system continues to process the select in a non-terminating loop. To avoid this, you must use the AT (ascending terminating) or DT (descending terminating) options when issuing the readnext statement.
The extended ReadNext syntax is
readNext atId using cursorVar by AT else…
where the "by" option can be the following literals or numbers.
Literal | Number | Direction |
AT | 0 | Ascending Terminating |
AN | 1 | Ascending Non-Terminating |
DT | 2 | Descending Terminating |
DT | 3 | Descending Non-Terminating |
Note: Do not put the "by" option in quotes. It's a statement, not a passed string.
If you know the sort mode at compile time, you can use either the literal or the number. If you will only know the sort mode at runtime, you must use the number, which you can assign to a variable.
if option = ASCEND$ then sortMode = 0 ; * // AT - ascending end else sortMode = 2 ; * // DT - descending end readNext atId using cursorVar by sortMode else…
Cursor Status
As mentioned above, cursor status and working with multiple cursors will be covered in the next post in the Select Series.