Question
· Sep 17, 2019

Mirror Backup vs. R/O Database Behavior - Scheduled Task for HL7 Message Dumps

I've created a scheduled task that dumps HL7 messages to flat files. It uses the OutputToLibraryStream() method of EnsLib.HL7.Message. I'd like to be able to run it on a mirror member host whether it's primary or backup.

When run against a database that's mounted read-only, it works fine. However, when I attempt to run it against a mirror backup database, I get the following error:

#5002: Cache error: <PROTECT>%LoadData+7^EnsLib.HL7.Message.1

Tracing that back to the source, I find:

Lock +(^EnsLib.H.MessageD(id)#"SE"):$zu(115,4)

Can someone help me understand how locking might behave differently on a "conventional" R/O database vs. a mirror backup R/O database? I can rationalize the behavior due to the fact that dejournaling is still doing sets/kills and that a lock would potentially mean bad things for mirror consistency, but I don't know why I wouldn't see this behavior on a database that is purposely mounted R/O.

Oh, and I'd also like to make this work :D

Discussion (9)2
Log in or sign up to continue

Hello Jeffrey,

You're absolutely right that normal read only databases and mirrored databases operate differently. It is not possible to take out locks for a mirrored database on a backup failover member as locks would prevent the member from taking over as primary.

If you have a DR async and take out a lock on a mirrored database, then when you try to promote to failover member you'll see a message like this:

Unfortunately, that means I don't have a workaround for you unless you have a DR where you can dump the messages instead.

Thanks to @Pete Greskoff who I talked to about this behavior.

Thanks Vic for the confirmation and explanation.

What I still can't figure out, though, is why a lock is needed to read a message body from the database and write it to flat file. Practically speaking I don't need the lock ... the message has almost reached its sell-by date and will be purged from the database within the week. It's never going to be modified again.

A DR Async/Reporting member is a possibility, but not for the near term ...

I didn't do a deep dive but presumably the HL7 message is being opened as an object and therefore automatically taking out a shared lock in order to read it.

If you really don't care about locking or concurrency protection, I imagine it wouldn't be that difficult to custom code something to do what you want, though you'd probably want to test:

https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_persobj#GOBJ_concurrency

Looking at the docs, %OpenId() accepts a  concurrency argument. 0 is "no lock," but when using it on a mirror backup I get:

ERROR #939: Insufficient privilege for object access 'EnsLib.HL7.Message::%Open'

Not sure what privilege I can be granted to allow it as I'm running it with the %All role ... but I get the feeling I'm barking up the wrong tree.

Jeffrey,

I'd try to define namespace global mapping, something like this:

[Map.YOURNSP]
...
Global_Ens*=YOURNSPDB,,YOURNSP-LOCKS
...

where

YOURNSP - your namespace
YOURNSPDB - database where ^Ens* globals are stored (mirrored one)
YOURNSP-LOCKS - database ^Ens* globals locks will be associated with (local one, RO or RW, it doesn't matter).

The similar definitions should exist for each global groups that can be locked.

Disclaimer: I didn't try this trick myself with mirrored DBs. It might help to bypass the locking problem, while not guarantee against other suprises one can face with running something on Mirror Backup member. Consulting with WRC might be of use... 

Jeffrey,

That's exactly what we did to offload message archiving to our DR server.

We created another namespace (R/W, non-mirrored) and mapped the following globals from the original namespace with the mirrored R/O database: 
EnsLib.*, EnsLib, EnsHL7.Segment, EnsHL7.Schema, EnsHL7.Description, EnsEDI.*, EnsEDI.X12.Schema, EnsEDI.X12.Description, EnsEDI.Schema, EnsEDI.Description, EnsEDI.ASTM.Schema, EnsEDI.ASTM.Description, Ens.MessageHeaderI, Ens.MessageHeaderD, Ens.MessageBodyI, Ens.MessageBodyD, CacheMsgNames, CacheMsg.

Then, we run the message archiving task in the other namespace without issues.