Alexey Maslov · Feb 5, 2020 go to post

Dmitrii,
Your ideas sound interesting, while I have some doubts. One usually needs speed for scientific calculations. Skipping the discussion how good ObjectScript as interpretated language fits this need, if we place upon our (even small) additional interpreter, nobody would envy our calculation speed.

Your most infamous errors list can be appended with many others, such as "DO I=1.3" error which destroyed some satellite. Besides, missing The International Date Line example is merely logical error that derives from "common" inaccurate development practice.  Alas, such development errors list is sadly long, and I doubt if physical measures mismatch has the highest rate among others.

Alexey Maslov · Feb 5, 2020 go to post

The easier the better:

 if $data(^$Job(PID)) // then the process with PID is running...

But each method mentioned above has a potential problem: if the process with PID had finished far ago, the O/S PID counter could run a full cycle, and another Caché (IRIS) process could start with the same PID. The full solution may worth a separate article, while the simple one is: just to collect garbage often enough. To my experience, once a day is usually quite enough even on high loaded systems.

Alexey Maslov · Dec 11, 2019 go to post

Marat, 

Maybe it's possible to build a dictionary of wrong decoding of typical words and use it for encoding guessing. E.g., a word 

לרפא
will probably be a typical one in a medicine text. Wrong decodings can be collected using a tool like this. Using pronouns, articles or prepositions as "universal" typical words can even be a better idea.

Alexey Maslov · Dec 11, 2019 go to post

...otherwise all the gibberish lines look the same
 

While you are basically right, some euristics can help to find an answer. A line that matches a pattern: line?1(1U.L,.L,.U) is more likely encoded correctly than "camel case" one. After modifying Eduard's sample a bit: 

AutoCode
 new $namespace set $namespace="%SYS"
 Set Text = "ÍàØâàÞæØâë"
 Set Ref = ##class(Config.NLS.Locales).OpenCurrent(.Sc)
 Write "Locale name: ",Ref.Name, !!
 Do Ref.GetTables(.Tables)
 Set Key = ""
 For Set Key = $O(Tables("XLT", Key)) Quit:Key=""  line=$zcvt(Text, "I", Key) if line?1(1U.L,.L,.U) Write Key," ",line,!}
 q

we are getting (likely) correct answer without knowing a target language:

USER>d AutoCode^ztest
Locale name: yruw

LatinC Эритроциты 1

There are some other problems, e.g. system built-in tables such as UTF8 are not included, but they can be solved. Writing universal cyrillic decoder is not so easy task, but as there are some already exist in web, it's possible to write another one.

Alexey Maslov · Dec 11, 2019 go to post

Does anyone use this in production?

We tried; our intention was rather modest: just to run Caché system utilities. Alas, even JOBEXAM failed. The issue was discussed with the author, and it turned to be difficult to amend by design.

Alexey Maslov · Dec 9, 2019 go to post

It seems that try / catch paradigm encourages one to propagate exceptions. Otherwise it's easy to get a "style mix" that looks unpleasant, something like: 

   ...
   set sc=##Class(Config.Databases).Get(pDBname,.pProp)
   if 'sc goto gDBPropQ; more characters to type and less expressive
  
  catch ex {
   set sc=ex.AsStatus()
  }
gDBPropQ
  quit sc}

or 

  ...
  set sc=##Class(Config.Databases).Get(pDBname,.pProp)
  if 'sc return sc; many exit points from one method contradicts
                   ; with reasonable principles of modular coding
 catch ex {
   set sc=ex.AsStatus()
 }
 return sc}

All this stuff is just IMHO, just an attempt to be consistent. 

Alexey Maslov · Dec 9, 2019 go to post

Just a quick note: when errors are processed consistently, e.g. each %Status have been returned is processed with $$$TOE or $$$ThrowOnError  or $$$ThrowStatus macro, this approach seems to be excessive, and `set sc=ex.AsStatus()` is just enough. E.g. 

ClassMethod GetDBProp(pDBname, ByRef pProp, pDivide = 1) As %Status{
  try {
   new $namespace set $namespace="%SYS"
   set sc=1/pDivide ;potential <DIVIDE>
   $$$TOE(sc, ##Class(Config.Databases).Get(pDBname,.pProp))
  catch ex {
   set sc=ex.AsStatus()
  }
  quit sc}

For me, unexpected %objlasterror is no more than a sign of inaccurate coding, when some %Status values are not processed.

Alexey Maslov · Nov 28, 2019 go to post

Or

USER>w $replace($j("",30)," ","=?")
=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?

USER>w $l(x,"=?")
31 ; as in previous samples
Alexey Maslov · Nov 22, 2019 go to post

Eduard, thank you for a very good webinar.

You mentioned that IAM can be helpful even if there is "service-mix": some services are IRIS based, others - not. How can IAM help with non-IRIS services? Can any Target Object be non-IRIS base?

Alexey Maslov · Nov 22, 2019 go to post

2c more. 

.service suffix is redundant in systemctl command, so one can just enter:

# systemctl start iris
# systemctl stop iris
...
# systemctl status iris

The published script pattern is applicable to Caché after evident correction (iris -> ccontrol).

Alexey Maslov · Nov 22, 2019 go to post

Thank you, Udo!

Just 2c to add.

Quotes are not needed in the following lines, due to the syntax of iris start/stop commands. They should look like:

ExecStart=<iris-inst-dir>/bin/iris start <instance>
ExecStop=<iris-inst-dir>/bin/iris stop <instance> quietly

After changing the iris.service file one should perform:

# systemctl daemon-reload
Alexey Maslov · Nov 12, 2019 go to post

Sergey, it's great that you are writing articles for newbies, nevertheless you don't explicitly mark it. Just a quick note on your samples: ZWRITE command never returns <UNDEFINED> in IRIS, so to check the global existence one should use something like

 if '$data(^A) { write "Global ^A is UNDEFINED",! }

I'm sure that you are aware of it; just thinking of novices that should not be confused.

Alexey Maslov · Nov 12, 2019 go to post

Stephen, agree with you, those %% can be nasty, while it's possible to avoid them in this very case:

..\bin\cache -s. -U"%SYS" <Routine/ClassMethod call>

making the command syntax very similar to Linux one. In most other cases %% are inevitable; take a look at a small brief from real CMD script: 

 call :CheckNameSpace %%%%SYS
 if %sc% equ 0 goto :help
 ...
:CheckNameSpace
 set sc=1
 If "%1" == "" goto :NameSpaceNotSet
 ...
Alexey Maslov · Nov 7, 2019 go to post

After re-reading excellent articles referenced above, it seemed that:
1) Too low QoS value can be incompatible with VM Stun time.
2) Too high value can be inappropriate as well for some other reasons. E.g., it can postpone a failover when it's of real need when Primary crashed or isolated.
So, why not stop bothering about QoS value, and just Set No Failover during snapshot phase? Documentation describes how to do it manually, while it should be possible programmatically as well.

Alexey Maslov · Nov 6, 2019 go to post

You may want to use some kind of print spooling to avoid the situations of monopolization such a device as printer. Take a look at CUPS; there is a brief notes how to use lp or lpr commands in Caché/IRIS: Using Pipes to Communicate with Processes.

On Windows we just used OS printer name for opening the device in Caché, and it was enough to spool the jobs to printer queue; no other tricks were needed.

Alexey Maslov · Oct 31, 2019 go to post

To get more reliable figures on performance, we usually take the following approach (# 1):

 set nTop=1000000 // number of test repetitions
 for each test_j {
   init_counters
   for i=1:1:nTop {
      run_test_j
   }
   save_counters_for_test_j(nTop)
 }

because it introduces less extra payload and provides more precise measuring than alternative approach (#2):

 set nTop=1000000
 for i=1:1:nTop {
  for each test_j {
    init_counters
    run_test_j
    save_counters_for_test_j
  }
 }
 for each test_j {
   aggregate_counters_for_test_j(nTop)
 }
Alexey Maslov · Oct 29, 2019 go to post

you wouldn't need it for classes
 

... while it's available using Ctrl-E / Ctrl-Shift-E shortcuts, in classes as well.

Alexey Maslov · Oct 10, 2019 go to post

Mark,

The solution you suggested can be possible, but seems to be much more tricky than use of some USB/Ethernet converter. We done it many times connecting laboratory devices with interfaces of different types, such as RS232 / RS422 / etc.

Alexey Maslov · Oct 10, 2019 go to post

Sorry, I've just misunderstood the remark "The device would have to be called from a telnet session" thinking that telnet protocol would be used to communicate with the device.

Anyway, if one just Google "USB 100BaseT converter", many solutions will be found.
 

Alexey Maslov · Oct 10, 2019 go to post

how you going to connect these devices to the server for control?

Is it a problem to connect to server any device which supports some kind of TCP based protocol?

Alexey Maslov · Sep 29, 2019 go to post

 ...^MSU has been replaced by ^DATABASE for a long time.

At least in 2017.2 it is still available, despite its deprecation ages ago. I still prefer to call it as there are less characters to type.

Alexey Maslov · Sep 18, 2019 go to post

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... 

Alexey Maslov · Sep 17, 2019 go to post

When the file is opened as "W" (not "WL") in Caché for Linux, other process can immediately open it as "WL". For some reason journal files are opened as "W", so we have a "false positive" effect if attempt to check journal switching this way.

Alexey Maslov · Sep 16, 2019 go to post

Hi Julius,

Your solution is beautiful; alas, this code

open jouFile:"WL":1 // try to get ownership

instantly returns $Test=1 in Caché for Linux as its behavior differs from Windows version in this case according to documentation:
Caché Development References  >  Caché I/O Device Guide  >  Sequential File I/O: OPEN Mode Locking

I've checked it in Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2017.2.2 before writing here.

Alexey Maslov · Sep 16, 2019 go to post

Here is my solution. A couple of words as a preface. There are two tasks:
#1

  • Switches journal and fixes the name of new journal file (e.g., in @..#GtrlJ@("JrnFirst")).
  • Processes the globals of a namespace. The algorithm of processing doesn't matter here, it's usually some kind of data re-coding. 

#2. This task occurred just because users' activity during the task #1 execution can introduce the changes in globals already processed by the task #1.

  • Wait for the next journal file available for processing (WaitForJrnSwitch());
  • Process the globals found in this journal using the algorithm similar to the task_#1's one.

The latter is a pseudo-code of WaitForJrnSwitch() method and GetJrnID(), its helper. 

/// If new jrn is available, set %JrnID=Jrn ID and return 1;
/// waiting by ..#TimeWait steps till ..#TimeLimitClassMethod WaitForJrnSwitch() As %Boolean{
 set rc=0
 set nTimes = ..#TimeLimit \ ..#TimeWait
 for i=1:1:nTimes {
  $$$TOE(sc, ..GetJrnID(.JrnID)) // current journal
  if %JrnID="" {
    set JrnNext=@..#GtrlJ@("JrnFirst")
  else {
    set JrnNext=%JrnID+1
  }
  if JrnNext<JrnID { // avoid extra journal switching ("by restore")    set %JrnID=JrnNext
    set rc=1
    quit
  }  
  hang ..#TimeWait
 }
 quit rc
}


/// Get Jrn ID of the current journal file/// Out:/// returns %Status;
/// pJrnID - journal file name w/o prefix and "."ClassMethod GetJrnID(Output pJrnID) As %Status{
 set sc=1
 try {   set file=##class(%File).GetFilename(##class(%SYS.Journal.System).GetCurrentFileName())   set prefix=##class(%SYS.Journal.System).GetJournalFilePrefix()    set pJrnID=$tr($e(file,$l(prefix)+1,*),".")
 catch ex {
   set sc=$$$ERROR($s(ex.%IsA("%Exception.SystemException"):5002,'ex.Code:5002,1:ex.Code),$lg(ex.Data)_" "_ex.Location_" "_ex.Name)
 }
 quit sc}
Alexey Maslov · Sep 11, 2019 go to post

Hi Julius,

My solution is similar to yours while it is based on journal API only. If anybody is interested, I'll post it in a few days (being on vacations at the moment).

Thank you for reminding to check if the shutdown is in progress, while I am not sure how often my code should wake up to detect it for sure. Yours waking up each one second as I see.