Two questions about MCM’s article
Fundamentals of Multi-User Programming in PowerBASIC
1. MCM describes two forms of record locking: physical and logical. In physical locking the network O/S locks the record (per program command). The lock is detected by other users when they try to access the record and get an Error. In logical locking each record has an extra one byte field. The program sets this to “L” to lock the record. Other users check this byte to determine when the record is locked.
Question: In logical locking if the “locker” user terminates abnormally his lock stays in place. In case a lock gets stuck like that, as pointed out in MCM’s article, there needs to be an administrative way of removing locks. How about physical locks: what happens to a physical lock if the computer of the user who set it crashes? If the lock stays (for any great length of time) how would another program remove it?
Question: Why provide two different methods of locking records? What are the advantages and disadvantages of each?
2. Per MCM’s article, the data file, say Customer.txt, is opened with
OPEN "Customer.txt" FOR RANDOM ACCESS READ WRITE LOCK SHARED AS CustFileNo LEN = LEN(DataRecord)
When is the file open and closed? Can the program open it when the user starts the program and close it only when the user closes the program, keeping the file open all day long? (After all, it’s SHARED.) Or should the program, each time a user wants to access a record, open the file then close it right after the user is done with the record?
MCM’s example code just does one edit of a given record, but you could put a do-loop around it. So the above question is: put OPEN before DO and CLOSE after LOOP, or OPEN after DO and CLOSE before LOOP ?
End of questions.
MCM’s example code doesn’t check if the record got changed by someone else while the user was typing. This check has been added in a new version of MCM’s code below. If another user had changed the field by the time he tries to save his work, he gets a message that it cannot be saved. (Of course that situation could be handled another way.) Other changes include:
1. PBCC instead of PBDOS.
2. A loop so you can edit several records without restarting the program.
3. A more persistent GET, trying several times each fifth of a second instead of just twice after half a second.
4. Closing the file. (MCM’s original code is missing a CLOSE statement.)
I put OPEN outside the do-loop.
Fundamentals of Multi-User Programming in PowerBASIC
1. MCM describes two forms of record locking: physical and logical. In physical locking the network O/S locks the record (per program command). The lock is detected by other users when they try to access the record and get an Error. In logical locking each record has an extra one byte field. The program sets this to “L” to lock the record. Other users check this byte to determine when the record is locked.
Question: In logical locking if the “locker” user terminates abnormally his lock stays in place. In case a lock gets stuck like that, as pointed out in MCM’s article, there needs to be an administrative way of removing locks. How about physical locks: what happens to a physical lock if the computer of the user who set it crashes? If the lock stays (for any great length of time) how would another program remove it?
Question: Why provide two different methods of locking records? What are the advantages and disadvantages of each?
2. Per MCM’s article, the data file, say Customer.txt, is opened with
OPEN "Customer.txt" FOR RANDOM ACCESS READ WRITE LOCK SHARED AS CustFileNo LEN = LEN(DataRecord)
When is the file open and closed? Can the program open it when the user starts the program and close it only when the user closes the program, keeping the file open all day long? (After all, it’s SHARED.) Or should the program, each time a user wants to access a record, open the file then close it right after the user is done with the record?
MCM’s example code just does one edit of a given record, but you could put a do-loop around it. So the above question is: put OPEN before DO and CLOSE after LOOP, or OPEN after DO and CLOSE before LOOP ?
End of questions.
MCM’s example code doesn’t check if the record got changed by someone else while the user was typing. This check has been added in a new version of MCM’s code below. If another user had changed the field by the time he tries to save his work, he gets a message that it cannot be saved. (Of course that situation could be handled another way.) Other changes include:
1. PBCC instead of PBDOS.
2. A loop so you can edit several records without restarting the program.
3. A more persistent GET, trying several times each fifth of a second instead of just twice after half a second.
4. Closing the file. (MCM’s original code is missing a CLOSE statement.)
I put OPEN outside the do-loop.
Code:
' MULTIA.bas ' Bare-bones multiuser customer file maintenance. ' Original PDOS by Michael Mattias, October 1995. ' Here converted to PBCC with minor improvements. #Compile Exe #Dim All '------------------------------------------------------------------ ' Constants %PhysicalLocking = -1 'true (compiler option) %LogicalLocking = Not %PhysicalLocking %PermissionDenied = 70 'error code '------------------------------------------------------------------ Type CustomerRecord ' three fields, not counting AcctNo & Record Status AcctNo As Long AcctName As String * 30 StreetAddress As String * 30 CityStateZip As String * 30 RecordStatus As String * 1 ' used if %LogicalLocking: "L" or " " End Type '------------------------------------------------------------------ Global ReadDelay As Single Global CustFileNo As Long '================================================================== ' The general purpose subroutines from here to the next double line ' separator could be placed in an include file. ' Read a record, test if locked. Sub ReadCustomerRecord (RecordNo As Long, DataRecord As CustomerRecord, Stat As Long) Local count As Long On Error Resume Next count = 0 Do Stat = 0 ErrClear Incr count Get CustFileNo, RecordNo, DataRecord Stat = Err ' record the error If Stat = 0 _ ' good read And %LogicalLocking _ ' logical locking And DataRecord.RecordStatus = "L" Then ' locked by another user Stat = %PermissionDenied End If If Stat = %PermissionDenied Then ' wait and retry Sleep ReadDelay End If Loop Until stat = 0 Or count > 3 ' now Stat contains success (0) or failure. End Sub '------------------------------------------------------------------ ' Lock a record. Sub LockCustomerRecord (RecordNo As Long, Stat As Long) Local ReadStatus As Long Local DataRecord As CustomerRecord On Error Resume Next If %PhysicalLocking Then ' use PB and O/S services Lock CustFileNo, RecordNo Stat = Err Else ReadCustomerRecord RecordNo, DataRecord, ReadStatus ' get current copy of the record If ReadStatus Then ' some error in the read - maybe locked! Stat = ReadStatus ' return it to the main program Else DataRecord.RecordStatus = "L" ' mark the disk record "locked" Put CustFileNo, RecordNo, DataRecord ' and store it Stat = Err ' could get error on PUT! End If End If End Sub '------------------------------------------------------------------ ' Unlock a Record. Sub UnlockCustomerRecord (RecordNo As Long, Stat As Long) Dim DataRecord As CustomerRecord On Error Resume Next If %PhysicalLocking Then ' use PB and O/S services UnLock CustFileNo, RecordNo Stat = Err Else ReadCustomerRecord RecordNo, DataRecord, Stat If Stat = 0 Then DataRecord.RecordStatus = " " ' clear out the "L" Put CustFileNo, RecordNo, DataRecord Stat = Err End If End If End Sub '================================================================== Function PBMain Local DataRecord As CustomerRecord Local SaveRecord As CustomerRecord ' not used here Local CustNum As Long Local Stat As Long ' error code Local NewAcctName As String Print " Records are identified by Customer number," Print " starting at 1. Each record has three fields," Print " but here you can only update one of them:" Print " AcctName." Print ReadDelay = .2 ' global constant, in seconds CustFileNo = FreeFile ' global constant Open "Customer.txt" For Random Access Read Write Lock Shared _ As CustFileNo Len = Len(DataRecord) Do ' loop through given customer numbers Input " Enter Customer Number to view/update ", CustNum If CustNum = 0 Then Exit Do ' read it ReadCustomerRecord Custnum, DataRecord, Stat If Stat = %PermissionDenied Then ' this will never happen using instances of this program, ' but it might happen in a version that had to lock the ' whole file for a time Print " Can't update this customer - record in use" ElseIf Stat <> 0 Then Print " Error on GET, # "; Stat Else Print " AcctName: "; DataRecord.AcctName Print " StreetAddress: "; DataRecord.StreetAddress Print " CityStateZip: "; DataRecord.CityStateZip Print ' save the image used by operator SaveRecord = DataRecord ' get the new data from the user Line Input " Enter new AcctName: ", NewAcctName If NewAcctName = "" Then Iterate Do ' lock the record LockCustomerRecord CustNum, Stat ' get a current copy of it If Not Stat Then ReadCustomerRecord Custnum, DataRecord, Stat End If ' check if this is the same as it was when we started If Not Stat Then ' OK on the LOCK and READ If DataRecord.AcctName = SaveRecord.AcctName Then ' store the record back to disk with new data DataRecord.AcctName = NewAcctName Put CustFileNo, CustNum, DataRecord ' unlock the record UnlockCustomerRecord CustNum, Stat ' tell user successful Print " Customer file updated." Else ' unlock the record UnlockCustomerRecord CustNum, Stat ' tell user he didn't type fast enough Print " Someone else edited this record while you were typing." End If End If If Stat Then Print " Error on file access." End If Print End If Loop Close CustFileNo End Function
Comment