I rebuild ^rINDEX using, as recommended, D ##class(%Library.RoutineIndex).RebuildIndex($NAMESPACE). That reduced the number of ^rINDEX entries with an empty Date Modified, the cause of the $RO error. However, this function is partially based on ^ROUTINE which in its turn had bogus entries, all of the type ^ROUTINE("ABC",0,"SIZE")=<some integer>. That’s all these routines contain. I killed these ^ROUTINE nodes and rebuilt ^rINDEX. No empty Date Modified. 

I wrote a simple function to find non-printable characters in a routine:

findNonAscii
stream = ##class(%FileCharacterStream).%New()
stream.Filename="C:\TestAGbackup_2024-04-15_AG.txt"
f  {
        q:stream.AtEnd
        s line = stream.ReadLine()
        ; Strip all control characters, including non-processable by XML export, except for tabs and newlines
        s l2=$ZSTRIP(line,"*C","",$C(9)_$C(10)_$C(13))
        w:l2'=line line,!,l2,!
}
q

Everybody, thanks for reading and Robert and Sarah for replying.

  • Yes, GetGlobalSizeBySubscript returns Allocated Size only
  • Changing the third GetGlobalSizeBySubscript argument to an empty one does not make a difference in returned Size.
  • GetGlobalSize and ^%GSIZE return Used Size which is still different but not dramatically.
  • I also found an bug in my code. The lengthy InterSystems instructions to the GetGlobalSizeBySubscript code mention: ""Size - Maximum number of MB to count...Be careful to RESET this for multiple calls to the method". I'd say such a Size definition is counterintuitive but at least I got totalSize=1321.57, very close to the result from GetGlobalSize from GetGlobalSizeBySubscript(path,global,global,.Size). Final code with results is:

partialGlobalsSize(dir,global)
sub="",path="C:\Cachesys\mgr\"_dir_"\",searchGlobal="^"_global,Alloc=0,Size=0
x=##Class(%GlobalEdit).GetGlobalSize(path, global,.Alloc,.Size)
global,",",Alloc,",",Size,!  Alloc=1312,725 here, Size=725
Size=0
x=##Class(%GlobalEdit).GetGlobalSizeBySubscript(path,global,"",.Size)
global,",",Size,! 1311.9 here
totalSize=0
F  {
    /// Size - Maximum number of MB to count. If the size of the global exceeds this value,
    /// calculation stops, and an error is returned. If undefined or set to 0, then the entire range is counted.
    /// Be careful to RESET this for multiple calls to the method
    Size=0 ; Resetting!
    sub=$O(@searchGlobal@(sub)) Q:sub="" ;$D(@("^MSCG("_t_")"))
    x=##Class(%GlobalEdit).GetGlobalSizeBySubscript(path,global_"("""_sub_""")","",.Size)
    totalSize=totalSize+Size
}
global,",",totalSize,! 1321.57 here
Q

Thanks, Robert. A couple of additional questions.

  • Would you say the Used Size from GetGlobalSize (Size argument from code above; 725 MB) is more correct or the %GSIZE result is more correct (760 MB)?
  • What's your take on GetGlobalSizeBySubscript when called for all first level subscripts yielding a magnitude lesser number in total, 8.56 MB? Could it be it returns only contents of purely ^GLOBAL(sub1) and not returning contents of ^GLOBAL(sub1,sub2)? BTW, I saw in the debugger that  GetGlobalSizeBySubscript calls %GSIZE internally.

That's the code I ended up with. Thanks for your help, everybody!

 ; str is parsed into two arrays, words and separators (spaces and punctuation)
 ; Trim leading and trailing spaces here if needed
 L=$L(str),(currWord,currSep)="",cnt=0
 i=1:1:{
  S currChar=$E(str,i,i)
  I $MATCH(currChar,"\w") {
     currWord=currWord_currChar
     currSep'="" {
       sepAr(cnt)=currSep,currSep=""
   }
}
  ELSE {
   currSep=currSep_currChar 
   currWord'="" {
     cnt=cnt+1,wordAr(cnt)=currWord,currWord=""
   }
  }
 }