Muhammad Waseem · Jul 29, 2021

How to separate namespace Globals and Routines databases ?


Upon creating namespace I selected same database for both Globals and Routines. How can I separate both the databases. Please note that I already have data and code saved in database.


Product version: IRIS 2021.1
2 0 14 255
Log in or sign up to continue

I'll be interested to see others' thoughts on this as well, but one approach is:

  • Create a new empty database for the globals
  • Use GBLOCKCOPY or MERGE to copy each of the globals from the current DB to the new globals DB. I believe GBLOCKCOPY is faster than MERGE.
  • After they are copied/merged to the new DB kill the globals in the currrent DB. This then becomes your routines DB.

Or you can do the opposite and export all of your routines from the current DB, import them into a new routines DB, then delete them from the current DB which becomes your globals DB. This would be faster than the first approach unless your globals are really small.

I'd suggest GBLOCKCOPY as it operates @ DB level and doesn't care about namespace 

What is the full list of ROUTINES globals? 

I think the preferred way is to use $SYSTEM.OBJ.Export (or even better - VCS) instead of direct global manipulation to export code.

create a new DB and list all 32 system elements in DB view
ROUTINE => .int
odd* => obj stuff, and all r* for various others

Wow. That's a lot!

I think we need a function that will export all such globals. If there is not in the %SYS we should add a such as a ZPM module.

That's in fact happening by separating Globals-DB from Routine-DB in the namespace definition.
Those globals are visible in any DB but they are used only for RoutineDB with a kind of implicit routine mapping.  (ages old and implemented shortly after "Big Bang") 
Once the Routine-DB is clean and isolated just copy the full DB 
or use $system.OBJ.Export(....)

As example of this implicit mapping a view of my ^ROUTINE in namespace DEMO

I personally would dismount and then take a duplicate copy of the relevant IRIS.dat or Cache.dat at an OS level, then mount them both as separate databases.

I would then delete the globals from 1 and then the the routines/classes from the other.

Then remove any inapropriate namespace mappings if necessary.

I agree with Steve

You can use ^%GOF, GBLOCKCOPY,  or even Merge ^Global=^[{Old_Namespace_Name}]Global as long as you know which globals you need, that the globals are not already mapped from some other namespace.

When it comes to your code you have to take into account your Classes (.cls), include files (.inc), routines (.int) (rarely used in new Ensemble/IRIS applications but there are applications that are written entirely in routines and use old style "nested dot" syntax in the form:

TestList xx (xx,TestList)=""
sort="" f  sort=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort),-1) q:sort=""  d
. epis="" f  epis=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id)) q:epis=""  d
. . depseq="" f  depseq=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id,depseq)) q:depseq=""  d
. . . dep="" f  dep=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id,depseq,dep)) q:dep=""  d
. . . . sectseq="" f  sectseq=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id,depseq,dep,sectseq)) q:sectseq=""  d
. . . . . sect="" f  sect=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id,depseq,dep,sectseq,sect)) q:sect=""  d
. . . . . . tsseq="" f  tsseq=$o(^Global($zn,$j,"Literal",dh1,SORT,dh2,Master,report,sort,id,depseq,dep,sectseq,sect,xyzseq)) q:tsseq=""  d

I kid you not... 

There are .mac (same as .int but with embedded SQL, which compile down to .int), BPL's, DTL's, Business Rules,  modified HL7 schema's, CSP pages in /csp/{namesapce}, corresponding .js and .css in the /csp/broker/ directory but not necessarily, it depends on how they are referenced in the HTML Header.

So, in my opinion, Steve is correct. Either dismount the current database (you can tell that it is not mounted if there is no .lck file in the database directory. If there is a .lck file and you proceed with copying the .dat database file, there is a good chance that when you try and assign the new .dat to a namespace, it may fail to mount. Better to shut down the instance.

It is probably easier to delete the globals from the original database than to delete the logic as there are so many extensions that you need to check for (as listed above, and if you didn't write the original application, it is easy to forget about the .inc, .dtl,  .bpl, .hl7, .mac, .int entities (if there are any of course).

Export the globals you plan to delete from the original database, and I would use the Management Portal frankly as it is easier to check the checkboxes next to the global names you want to delete (and export first before you delete) than type in the global names in any of the terminal utility such as ^%GOF. One typo, and you think you exported ^Customer but actually exported ^Kustomer, but you killed ^Customer, and then you realise that ^Customer was actually mapped into the namespace. Now you've deleted it in the source database, and you need to restore it, but you don't have an export because of that typo. The Management Portal allows you to exclude System Globals and Mapped Globals and avoid an accidental kill.

It is also a good idea to adopt a meaningful naming convention to indicate the difference between your DEV, QC, UAT and PRD databases and whether the database is for data (DT) or code (RT or RTN). It is also worth considering separating your stream data into a third database using global mapping. The reason for this is that if you have, for example, a Patient Class and one of the properties is Picture as %BinaryStream, the Binary Stream content will be stored in the 'S' global in the Storage Definition. Pictures of your Patient may be useful to display in your Patient Registration UI. Still, unless you are exporting that Patient as a FHIR Patient Resource, it is unlikely that you will reference the picture very often. Even with Objects, IRIS won't load the Picture into memory (Global Buffer Pool or your User Process) unless specifically referenced, i.e. "Patient.Picture". IRIS creates a "stream" directory though I am not sure what its purpose is. 

MyDatabase-DT-PRD (Data, Production)

MyDatabase-RT-PRD (Code, Production)

form Namespace



Special thanks for your example of nested "dotted syntax"  yes

I felt the need to remind us that we were very lucky that InterSystems came along and did away with all those peculiarities. I should add it to the thread on the future of ObjectScript. Imagine if we had to sell that to a customer. Maybe it's because I first learned to write code like that and it is no wonder why I love ObjectScript so much.

Is is still recommended to separate the Globals and Routines ? What's the major benefit of it ? Rapid deployment by switching the Routine database ?

definitely yes.
global store is a fast-changing DB with related mirror, journal, ECP, Sharding.

routine DB should change rarely and under special control.
may eventually have journal, but should not participate in ECP, Sharding, Mirror