Kevin,

If your licenses for both platforms (different in InterSystems license model) allow running Mirroring, the question would be 'yes'. AFAIK, you need at least Entree Multi-Server.

In most cases Cache programs don't depend on bitness of underlined platform, so you can run all of them in 64bit. The only cases when bitness comes to play occur when you are interacting with external applications, e.g. communicating through SQL GateWay with external DSN with 32bit ODBC driver when 64bit version of the driver is not available.

I'd ask another question: Kevin, did you ever try to configure and run Mirroring on Windows 10? Was it working?

I tried it a couple of months ago (Cache 2015.1.4 on Windows 10) and completely failed: mirror members could not communicate. Having enough experience in Mirroring deployment on Red Hat EL and MS Windows Server,  I was sure that it was a platform issue rather than my own. As it was not of great importance for me, I decided not to disturb WRC and dropped it.

Dmitry,

Ricardo is right: DISABLE^%NOJRN (despite of its non intuitive name) disables the journaling for the current process. Documentation states this, besides it's easy to check:

USER>d DISABLE^%NOJRN w $$CURRENT^%NOJRN
0
USER>d ENABLE^%NOJRN w $$CURRENT^%NOJRN
1
USER>w $$DisableJournal^%SYS.NOJRN," ",$$CURRENT^%NOJRN
1 0
USER>d EnableJournal^%SYS.NOJRN w $$CURRENT^%NOJRN
1

Timur, thank you for the series of articles!
It's clear enough that the purpose of your 1st sample was just to introduce map-reduce ideas, but besides you've illustrated concurrent processing technique available in Cache' which can be used apart of map-reducing. From this point of view, the parallel implementation of word count algorithm could be better balanced if the method MR.Sample.WordCount.AppWorkers::Map() would just count words emitting the result to infraPipe. In this case Reduce() method becomes trivial as all it needs to do - just summarize 4 (= number of book volumes) numbers from the infraPipe.


 "How robust is your great OS",!
 "(Each of which has cons and pros),",!
 "But specific under stress?",!
 "Want to check it? Just key press:",! *key set OS=$system.Version.GetOS()
 w:OS="Windows" "Are you really its follower? press <RESET> to do failover!",!
 w:OS="UNIX" "Under *NIX you are OK: your job killed, others remain.",!
 w:OS="VMS" "Not aware of VMS, contribute somebody else!"
 ;for i=1:1 set a(i)=$j("",3*1024*1024) $j(i,4)

Fabian, yes, it would be interesting to hear more on your approach.

Recently I faced the similar problem: we were asked for a tool to estimate a size of each global from the top N biggest ones. Our solution is to calculate the global sizes on regular basis (using a Cache Manager's Task) and to transfer the results to external SNMP server (using our own customized MIB). Visualization is provided by SNMP server (we and our customer use Zabbix).

As to global size calculation speed, in our case it takes about 30 minutes for 1TB database. Only allocated space is estimated.

Not tested for speed, while I expect this version should be rather fast as it compares common parts of both references rather than individual suscripts. Enjoy!

tttcmp(fgname,tgname,bKill,nErrTotal,nErrTop) ; Compare [sub]array @fgname with [sub]array @tgname
;In:
; fgname - "original" [sub]array
; tgname - its copy to check with;
; bKill - kill @tgname if it matches to @fgname (default = 0)
; nErrTop - # of mismatches to find to stop comparison
;
;Out:
; returns 1 on full subscripts and data match, else - 0.
; ByRef nErrTotal - # of mismatches.
;
new x,y,xtop,ytop,i,flOK,flQ,xquit,yquit,nErr,xstart,ystart
set bKill=$get(bKill,0)
set nErrTop=$get(nErrTop,1)
set x=fgname,y=tgname write !,"Comparing original "_fgname_" with imported "_tgname_":"
set xstart=$length($name(@x,$qlength(x)))+$select($qlength(x):1,1:2)
set xtop=$select($qlength(x):$extract(x,1,$length(x)-1)_",",1:x)
set ystart=$length($name(@y,$qlength(y)))+$select($qlength(y):1,1:2)
set ytop=$select($qlength(y):$extract(y,1,$length(y)-1)_",",1:y)
set flOK=1,flQ=0,nErr=0,nErrTotal=0
for i=1:1 do  quit:flQ
. set x=$query(@x),xquit=x=""!(x'[xtop)
. set y=$query(@y),yquit=y=""!(y'[ytop)
. if xquit,yquit write " OK. i=",set flQ=1 quit
. if xquit!yquit write " NO!!!: i=",i,$select(xquit:" "_fgname_" is shorter than "_tgname,1:" "_tgname_" is shorter than "_fgname) set nErrTotal=nErrTotal+1,flOK=0,flQ=1 quit
. if $extract(x,xstart,$length(x))'=$extract(y,ystart,$length(y)) write !,"!!! Ref NEQ: i=",write !," x=",x,!," y=",y  set nErrTotal=nErrTotal+1,nErr=nErr+1,flOK=0 set:nErr'<nErrTop flQ=1 quit:flQ  ;!,$e(x,xstart,$l(x)),!,$e(y,ystart,$l(y)),
. if $get(@x)'=$get(@y) write !,"!!! Data NEQ: i=",write !," *** x = ",x,!," x => ",@x,!," *** y = ",y,!," @y => ",@set nErrTotal=nErrTotal+1,nErr=nErr+1,flOK=0 set:nErr'<nErrTop flQ=1 quit:flQ
. else  set nErr=0
if flOK,bKill write !,"Killing "_tgname_"..." kill @tgname
else  write !,"Not Killing "_tgname
quit flOK

It seems that the source of the problem is a method of [re]starting Cache.

When it is started from shell using `ccontrol start ` command, SuperServer (as well as its childs) recognizes TZ that's actual system-wide.
But when it is started using a service script `service ca_cache start`, TZ is not recognized. There is nothing special in my script, its start() function is implemented as a wrapper for just the same `ccontrol start ` command as in the first case. It seems that service scripts are started from some special environment where some environment variables are deliberately unset.

I fixed the issue by setting the correct TZ in /etc/environment file and including one line of code into the service script:

start() {
        echo "Starting ca_$prog:"

        [ -f /etc/environment ] && . /etc/environment && export TZ

        ccontrol start $prog quietly
 

After 
# su cacheusr -
$ csession cache
QMS> w $$tz^ztest()
tap01.sparm.com /dev/pts/2 uid=502(cacheusr) gid=503(cacheusr) groups=503(cacheusr) tz= $ztz 0.0000008660

So the user type (=cacheusr) rather than process type seems to be a special case. After setting TZ manually I'm getting an expected responce:
tap01.sparm.com /dev/pts/2 uid=502(cacheusr) gid=503(cacheusr) groups=503(cacheusr) tz=Europe/Moscow $ztz 0.0000001271

but why cacheusr is not getting an environment from any standard place?

It's easy to set TZ for a Linux/UNIX tty user, but what about an app that is running some flavor of client/server mode? In this case Cache process inherits its environment from a special kind of parent, usually from SuperServer^%SYS.SERVER. 
At the moment I have no idea how to set the environment for SuperServer. I've tried:
1) setting system-wide using /etc/profile.d/*.sh
2) setting system-wide using /etc/environment
3) setting for cacheusr user using his .bash_profile.
Running a sample below, I'm getting a nice picture on /dev/pts and opposite one on |TCP|1972. The results are added in comments. I used CacheActiveX.dll (%Service_Bindings) for client/server connection.

tz(fun)
 if $zversion["UNIX" {
   set f="echo $TZ" open f:("QR"):1 if '$test write 0 quit "" use read tz close f
   set f="id" open f:("QR"):1 if '$test write 0 quit "" use read id close f
else {
   set tz="", id=""
 }
 set fun=$get(fun,"$ztz") ;"$h"
 set top=1000000 set ts=$zhorolog for i=1:1:top set @("d="_fun) set res=$zutil(110)_" "_$principal_" "_id_" tz="_tz_" "_fun_" "_$fnumber($zhorolog-ts/top,"",10) ;d $zf(-1,"echo $TZ") 
 quit res
 ;
 ; tap01.sparm.com |TCP|1972|1311 uid=502(cacheusr) gid=503(cacheusr) groups=503(cacheusr) tz= $ztz 0.0000011239
 ; tap01.sparm.com /dev/pts/0 uid=504(alex) gid=503(cacheusr) groups=503(cacheusr),10(wheel),505(alex) tz=Europe/Moscow $ztz 0.0000001212
 ;

Hello Mark,

As I had no idea which date and time functions can be affected with TZ setting, I'd tested some of them using a codelet:

top=1000000 fun="$h","$ztz","$zts","$zh" {ts=$zh i=1:1:top @("d="_fun) fun,?8,$fn($zh-ts/top,"",10),! $zf(-1,"echo $TZ")

My testing environment was:

%SYS>w $zv
Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2015.1.2 (Build 607_0_15223) Thu Jul 16 2015 17:33:31 EDT
%SYS>!cat /etc/centos-release
CentOS release 6.6 (Final)

The results w/o TZ:

$h      0.0000023653
$ztz    0.0000009993
$zts    0.0000004639
$zh     0.0000003155

and with TZ:

$h      0.0000011856
$ztz    0.0000001379
$zts    0.0000004690
$zh     0.0000003189
Europe/Moscow

I.e., the "]"-operator returns 1 if the first string operand collates after the second string operand.​

That's true for String type collations only (e.g. Cache String, Cyrillic2 String, etc). For most other collations defined in Cache (traditionally called Numeric collations) which comply the rule "numbers go first" (e.g. Cache Standard, Cyrillic2) one should use "]]" as "collate after" operator. In common, "]]" seems to be the better choice as it uses current collation rather than String one. This small sample code can demonstrate the difference between "]" and "]]": 

num
 new b,a,i,i0 
 set b("12345678901234567870")="Num20" set b("12345678901234567874")="NotNum20"
 set a=1E30,b(+a)=1,b(+a_"11")=11,b(+a_"111")=111,b(+a_"1a")="3a",a=3E30,b(+a)=3,b(+a_"33")=33,b(+a_"333")=333,b(+a_"1a")="4a"
 set i="",i0="" for  set i=$order(b(i)) quit:i=""  write "(i]]i0)=",i]]i0," (i]i0)=",i]i0," (i>i0)=",i>i0," (i=+i)=",i=+i,?30," " zwrite b(i) set i0=i
 quit

The result for Cache Standard collation is:  

LEARN>d num^ztest
(i]]i0)=1 (i]i0)=1 (i>i0)=1 (i=+i)=1 b(12345678901234567870)="Num20"
(i]]i0)=1 (i]i0)=1 (i>i0)=0 (i=+i)=0 b("12345678901234567874")="NotNum20"
(i]]i0)=1 (i]i0)=0 (i>i0)=1 (i=+i)=1 b(1000000000000000000000000000000)=1
(i]]i0)=1 (i]i0)=1 (i>i0)=1 (i=+i)=1 b(3000000000000000000000000000000)=3
(i]]i0)=1 (i]i0)=0 (i>i0)=1 (i=+i)=0 b("100000000000000000000000000000011")=11
(i]]i0)=1 (i]i0)=1 (i>i0)=1 (i=+i)=0 b("300000000000000000000000000000033")=33
(i]]i0)=1 (i]i0)=0 (i>i0)=1 (i=+i)=0 b("1000000000000000000000000000000111")=111
(i]]i0)=1 (i]i0)=1 (i>i0)=1 (i=+i)=0 b("3000000000000000000000000000000333")=333
(i]]i0)=1 (i]i0)=0 (i>i0)=0 (i=+i)=0 b("10000000000000000000000000000001a")="3a"
(i]]i0)=1 (i]i0)=1 (i>i0)=1 (i=+i)=0 b("30000000000000000000000000000001a")="4a"

While most system administrators may never need or use this function, some employ it for certain kinds of maintenance or other special cases.

Hello Ray, 

I just tried to imagine what kinds of maintenance are better to run with the stopped mirroring:

  • Cache version upgrade: just stop Cache - not need to stop mirroring;
  • integrity check: maybe, as one may want to have database in stale state to avoid "false positives";
  • performing database backup: not sure, as mirrored database(s) would apparently become too late behind the primary one(s) when backup is finished;
  • Have I missed something important? Being a consultant and a trainer, I eager to take in account as many special cases as possible...

    Thank you,

    Alex