Document locking - huh?

HI all

I have just rolled out a fairly major database for training with my own pre -v6 locking code - however, this proved a bit flaky with high volume transactions.

I have hurriedly converted it to use R6 native locking. The database will only be used by the client on one central server.

Question - is locking reliable? I have been getting some weird results (it took we a while to figure out the default error message when you try to edit a locked document is an an actual error event - so causes the rest of the script to abort unless error trapped - thanks for the documentation, guys!).

Second question. In training we got some replication / save conflicts where two trainees had edited the same document (it’s a workflow system). I thought this couldn’t happen with the default locking. However…

If User A opens the document for preview, and so does User B, then User B edits the document. User A tries to also edit the document, but quite rightly gets a ‘locked’ message. However, it doesn’t close them out of the document, so if they keep it in the uiworkspace, and then User B saves the document, if User A tries to edit again, it gives them a warning, and fails to open. If they try a second time, however, they can now edit the document. When they save it, conflict document is created.

Yes, I know, they shouldn’t ignore the warnings, they should close the document and re-open it - but these are users, you know!

Is there any way of forcing a failed edit attempt to close the document?

Otherwise, this can be a serious problem.

Thanx

Subject: Document locking - huh?

I haven’t worked with R6’s locking mechanism yet, so this is strictly theoretical, but wouldn’t the easy thing be to trap for the Document Locked error, and then throw up an alert to the second user telling them the document is locked and will be closed to avoid conflicts - and then actually close the uidoc via script?

Subject: RE: Document locking - huh?

It would be - if I could trap the error - however the error is handled by Notes itself and doesn’t seem to get as far as any of the programmable events (e.g. querymodechange) so nothing doing!

Thanks!

Subject: Document locking possible solution

I found the following possible solution to the problem described in this thread.

If a person A has a document locked and person B opens it for read. If person A saves and then person B puts it in edit mode without closing and reopening the document. Person B doesn’t get Person A changes. This then causes the document to conflict when person B saves the document.

We got around this by doing the following to the form:

  1. Set “Automatically enable edit mode”

  2. Set “Automatically refresh fields”

  3. Set Conflict Handling to “Merge Conflicts”

This then causes the document to give the “Locked” message at the view level and will not allow the user to open the document for read only at all.

We also found we needed to add a continue = false on querymodechange when the document is previewed. This prevented someone from going from preview (read) to edit and causing the same problem.

Hope this helps!!

Subject: RE: Document locking - huh?

Hi Tim and others,

I am looking for a solution for the same topic.

Have you found a solution for it, since?

Thanks in advance

Luc

Subject: Not perfect solution- but working !

The only way I have found to do this is to lock the document in the QueryOpen event - thus preventing anyone even previewing the document (though I guess I could start doing some clever stuff with form formulae and non-editable forms).

However, this does seem to prevent the save/replication conflict problem.

The code is

QueryOpen:

' 

' new documents don't yet exist, so lock would fail

' however, when the document is saved, it seems to be automatically locked by the save

' process, so lock correctly configured once the document is first saved

'



If Not isnewdoc Then 

	On Error Goto islocked

	locktest = source.Document.Lock

End If ' 	if not isnewdoc then 

Exit Sub

islocked:

Msgbox "Document locked by " + get_lock_name(source.document)

continue = False

Resume Next

QueryClose:

' when creating a new document, even though source.document exists on the save

' it seems to cause an error on the document.unlock, so we just skip over it

'

On Error Goto errhand

source.Document.UnLock

Exit Sub

errhand:

Resume Next

Function get_lock_name(lockdoc As notesdocument) As String

'

' get the name of the person locking a document from the $Writers field

get_lock_name = ""

If Not lockdoc.HasItem("$Writers") Then

	Exit Function

End If

Dim inm As New NotesName(lockdoc.GetItemValue ("$Writers")(0))

get_lock_name = inm.common

If lockdoc.HasItem("$WritersDate") Then

	get_lock_name = get_lock_name + " (" + Format(lockdoc.GetItemValue("$WritersDate")(0),"General Date") + ")"		

	Exit Function

End If

End Function

By the way - if anyone can spot any flaws in this and can see any potential pitfalls, please let me know!!!

Subject: RE: Not perfect solution- but working !

Tim -

I debated as to whether or not I should post this code. I’m sometimes a little too quick to adopt a “throw-more-code-at-it” approach. In any case, I wrote these functions to help deal with some of the behavioural nuances of using the native document locking feature introduced in ND6 (although I haven’t come across the specific problem mentioned here).

dgg

Public Function isDocumentLocked(pdoc As NotesDocument) As Boolean

'// +++ GLOBAL VARIABLES +++

'// Constants:

'// LIB_NAME = name of this library

'//

'// Class instances:

'// none

'//

'// Primitives:

'// none

'//

'// 11/10/2003 - Dallas Gimpel

'//

'// DESCRIPTION:

'// Given a handle to a backend document, examines the document’s Lockholders property to

'// determine whether or not the document is locked.

'//

'// INPUT:

'// pdoc - NotesDocument, handle to the document to be examined

'//

'// OUTPUT:

'// function returns a boolean - true if the document passed in is locked (as indicated

'// by the lockholders), otherwise false.

On Error Goto errorHandler



Const CODE_ELEMENT$ = "isDocumentLocked function"	

Dim varLockHolders As Variant



isDocumentLocked = False

If Not(pdoc Is Nothing) Then

	varLockHolders = pdoc.LockHolders

	If Len(varLockHolders(0)) > 0 Then

		isDocumentLocked = True

	End If

End If

functionExit:

Exit Function

errorHandler:

Call processUIError(CODE_ELEMENT & " / " & LIB_NAME)

Resume functionExit

End Function

Public Function applyLock(pdoc As NotesDocument, pstrUName As String) As Boolean

'// +++ GLOBAL VARIABLES +++

'// Constants:

'// LIB_NAME = name of this library

'//

'// Class instances:

'// none

'//

'// Primitives:

'// none

'//

'// 05/03/2004 - Dallas Gimpel

'//

'// DESCRIPTION:

'// This function is just a helper for the Lock method of the NotesDocument class. It is

'// just a more consistent way of locking a document without causing unnecessary errors

‘// to be raised. Unlike Lotus’ implementation, this function just returns true if the

'// document was successfully locked and suppresses (known) possible errors.

'//

'// INPUT:

'// pstrUName - String, the user name to be used when locking a given document

'//

'// OUTPUT:

'// Function returns a boolean (true if successfull, otherwise false).

On Error Goto errorHandler



Const CODE_ELEMENT = "applyLock function"

Const ERR_DOC_MODIFIED = 4579 '// error text: Unable to lock - Note has been modified since opening

Const ERR_DOC_IS_LOCKED = 4595 '// error text: Note is already locked by someone else



applyLock = False

If Len(pstrUName$) > 0 Then

	If pdoc.Lock(pstrUName$, False) Then

		applyLock = True

	End If

Elseif pdoc.Lock() Then '// if empty string is passed, use defaults

	applyLock = True

End If

functionExit:

Exit Function

errorHandler:

Select Case Err

Case ERR_DOC_MODIFIED

	Print Error$

Case ERR_DOC_IS_LOCKED

	Print Error$

Case Else

	Call processUIError(CODE_ELEMENT & " / " & LIB_NAME)

End Select

Resume functionExit

End Function

Public Function removeLock(pdoc As NotesDocument, pstrUName As String) As Boolean

'// +++ GLOBAL VARIABLES +++

'// Constants:

'// LIB_NAME = name of this library

'//

'// Class instances:

'// none

'//

'// Primitives:

'// none

'//

'// 05/03/2004 - Dallas Gimpel

'//

'// DESCRIPTION:

'// This function is just a helper for the Unlock method of the NotesDocument class. It

'// is just a more consistent way of unlocking a document without causing unnecessary

'// errors to be raised when a given user is not among the lock holders of the document.

'// This helps in suppressing unnecessary errors.

'//

'// INPUT:

'// pstrUName - String, the user name to be evaluated before unlocking a given document

'//

'// OUTPUT:

'// pdoc - NotesDocument, the document to be unlocked

'// Function returns a boolean (true unless an error is encountered).

On Error Goto errorHandler



Const CODE_ELEMENT = "removeLock function"



removeLock = False

If Isnumeric(Arraygetindex(pdoc.LockHolders, pstrUName$, 5)) Then

	Call pdoc.UnLock()

End If

removeLock = True

functionExit:

Exit Function

errorHandler:

Call processUIError(CODE_ELEMENT & " / " & LIB_NAME)

Resume functionExit

End Function

Public Function lockDocumentCollection(pdclxnTarget As NotesDocumentCollection) As Boolean

'// +++ GLOBAL VARIABLES +++

'// Constants:

'// LIB_NAME = name of this library

'//

'// Class instances:

'// none

'//

'// Primitives:

'// none

'//

'// 05/04/2004 - Dallas Gimpel

'//

'// DESCRIPTION:

'// This function iterates through a given NotesDocumentCollection and attempts to lock

'// each member document. If at any point, the attempt to lock a document fails, the

'// function unlocks any documents that were locked.

'//

'// NOTE:

'// This function is particularly useful when preparing to use the RemoveAll or StampAll

'// methods of NotesDocumentCollection.

'//

'// INPUT:

'// none

'//

'// OUTPUT:

'// pdclxnTarget - NotesDocumentCollection, the document collection to be locked

'// Function returns a boolean (true ONLY if all documents are successfully locked, otherwise false).

On Error Goto errorHandler



Const CODE_ELEMENT$ = "lockDocumentCollection function"

Dim nsess As NotesSession

Dim doc As NotesDocument

Dim x As Long

Dim lngClxnCount As Long

Dim lngLockCount As Long

Dim strUName As String



lockDocumentCollection = False

Set nsess = New NotesSession

lngClxnCount& = pdclxnTarget.Count

lngLockCount& = 0

strUName$ = nsess.UserName

'// Attempt to lock all documents in the collection.

If lngClxnCount& > 0 Then

	Set doc = pdclxnTarget.GetFirstDocument()

	For x = 1 To lngClxnCount&

		If applyLock(doc, strUName$) Then

			lngLockCount& = lngLockCount& + 1

		Else

			Exit For

		End If

		Set doc = pdclxnTarget.GetNextDocument(doc)

	Next x

End If



lockDocumentCollection = (lngClxnCount& = lngLockCount&)

functionExit:

'// Enforce an “all-or-none” rule - if ALL documents were not locked successfully, we

'// unlock any that were.

If Not(lockDocumentCollection) Then

	If Not(pdclxnTarget Is Nothing) Then

		If lngLockCount& > 0 Then

			Set doc = pdclxnTarget.GetFirstDocument()

			For x = 1 To lngLockCount&

				Call removeLock(doc, strUName$)

				Set doc = pdclxnTarget.GetNextDocument(doc)

			Next x

		End If

	End If

End If

Exit Function

errorHandler:

Call processUIError(CODE_ELEMENT & " / " & LIB_NAME)

Resume functionExit	

End Function

Public Function unlockDocumentCollection(pdclxnTarget As NotesDocumentCollection) As Boolean

'// +++ GLOBAL VARIABLES +++

'// Constants:

'// LIB_NAME = name of this library

'//

'// Class instances:

'// none

'//

'// Primitives:

'// none

'//

'// 05/04/2004 - Dallas Gimpel

'//

'// DESCRIPTION:

'// This function iterates through a given NotesDocumentCollection and attempts to unlock

'// each member document by way of the “removeLock” function. Since all known erorrs are

'// trapped in the removeLock function, we call the function without checking its return

'// value. This way processing continues even if a single document can’t be unlocked.

'//

'// INPUT:

'// none

'//

'// OUTPUT:

'// pdclxnTarget - NotesDocumentCollection, the document collection to be unlocked

'// Function returns a boolean (true unless an error is encountered here).

On Error Goto errorHandler



Const CODE_ELEMENT$ = "unlockDocumentCollection function"	

Dim nsess As NotesSession

Dim doc As NotesDocument

Dim x As Long

Dim lngClxnCount As Long

Dim strUName As String



unlockDocumentCollection = False

Set nsess = New NotesSession

lngClxnCount& = pdclxnTarget.Count

strUName$ = nsess.UserName

'// Attempt to lock all documents in the collection.

Set doc = pdclxnTarget.GetFirstDocument()

If lngClxnCount& > 0 Then

	For x = 1 To lngClxnCount&

		Call removeLock(doc, strUName$)

		Set doc = pdclxnTarget.GetNextDocument(doc)

	Next x

End If



unlockDocumentCollection = True

functionExit:

Exit Function

errorHandler:

Call processUIError(CODE_ELEMENT & " / " & LIB_NAME)

Resume functionExit	

End Function

Subject: Document locking - huh?

Take a look at this thread:http://www-10.lotus.com/ldd/nd6forum.nsf/55c38d716d632d9b8525689b005ba1c0/d1984d2c6e25ac0d85256cda0049810a?OpenDocument