go to post Alexey Maslov · Oct 2, 2017 It all depends.Attempts to connect a port or even to connect a super-server using potentially wrong password spoil Cache Audit with nasty records, so if they are done frequently those records can easilly overfill the Audit.Several years ago I faced the similar problem in opposite direction: how to let load balancer recognize Cache instances which are no longer alive to remove them from its list. Load balancer was to distribute super-server connections as well as web based ones. The idea of polling 1972/tcp was dropped as soon as I recognized its impact on auditting. So I used a web app which allowed unauthenticated access for the simple reason that if 57772/tcp port had reasonably answered, 1972/tcp should be accessible as well. There were no firewall(s) between the load balancer and application servers, therefore I was sure that there were no external "forces" that could prevent them from answering. The solution was deployed on a couple of different load balancers and showed its robustness on a farm of 4-7 application servers and 1000-3000 concurrent users.
go to post Alexey Maslov · Oct 2, 2017 It's better to use CACHETEMP mapped global, e.g. ^CacheTempUserYourGlobal($job,...).BTW there is another option: having a wrapper job, pass it an array serialized to JSON, other steps are evidient. I used it in one of my projects, and it was quicker than using of ^CacheTemp* intermediate global, while performance gain was not too sufficient (AFAIR)The approach with a global is apparently easier, so I'd use it if performance would not of great importantance.
go to post Alexey Maslov · Sep 6, 2017 I remember well times when routines used to start with KILL ^CacheTemp*($JOB)Our developers do the same, but modern versions of OSs usually have 6 digit PIDs, so it may take several days till PIDs would re-cycle their numbers.PPGs are used, however sometimes they are not applicable, e.g. when information is passed between processes via temp globals.Clean-up is a good idea, but can be fully implemented when (and only when) all app classes use the same before-exit-processing code, i.e. the app is always finish through one exit point. Sometimes it's difficult to achieve, while it's worth to.A while ago I thought about some enhancements of my purging task:automatic detection of too quick growing globalsautomatic detection of globals which belong to its scope, i.e. have @name@(PID) format. Maybe I do it when have some spare time... the priority of this work is rather medium.
go to post Alexey Maslov · Sep 6, 2017 Robert, You are quite right, but... life is life, and application can finish abnormally. In this case its temp globals are left till Caché restart, sometimes it may cause noticeable growth of CACHETEMP database. So, scheduling a nightly housekeeping task like ours makes some sense.
go to post Alexey Maslov · Sep 6, 2017 We have a TASKMGR's task that purges such kind of globals daily. (Sub)globals are cleaned using the following criteria:Global has a structure of @name@(PID)Global is listed in predefined "known globals" listCaché process identified with PID is not running.
go to post Alexey Maslov · Sep 5, 2017 Daniel,you wrote that:we need to communicate to the Authorization server with SSLIs it really necessary for the first steps with Open ID / OAUTH in testing environment?
go to post Alexey Maslov · Aug 29, 2017 Thank you, Eduard,This is a good example of regexp usage. At the meantime a colleague of mine is working on JS based solution outside of Caché (regexp replacement in .xml file). It's not clear enough if porting it to COS (class sources regexp replacement) would add any benefit.
go to post Alexey Maslov · Aug 22, 2017 Thank you, Timothy.Definitely this is a solution, while our case is a bit more complex. It can be several running copies of "dangerous" utility started by different users, so we can't select the actual one neither by executable name nor by its window title as it is started with "-nogui" option and has got no window. An approach how to bypass this limitation that we are going to implement looks like this: lock +^offPID set rc=$zf(-2,"drive:\path\utility --par1 --parN") if rc=0 { get PIDs of all running copies of utility.exe if '$data(^offPID(PID1)) { set ^offPID(PID1)=$h // search a new PID (let it be PID1) job checkJob(PID1) } } else { process an error } lock -^offPID ... ... сheckJob(pPID) // check if pPID is running for { get PIDs of all running copies of utility.exe if pPID is not listed { kill ^offPID(pPID) quit } elseif timeout expired { set rc=$zf(-1,"taskkill /pid "_pPID) if rc=0 { ... } else { process an error } kill ^offPID(pPID) quit } else { hang 30 // wait... } } quit
go to post Alexey Maslov · Aug 22, 2017 Thank you, Robert.In this case the PID saved in a file will be the PID of command processor (cmd) itself rather than the PID of an utility which it has invoked. If Cache process kill the cmd instance using this PID, the utility will continue its execution. Besides, there is no parent-child relationship between the cmd and the utility, so /t switch (kill process tree) would not help.
go to post Alexey Maslov · Aug 18, 2017 Thank you, Stephen.I should confess that you are quite write: our code resides in .cls, .inc, .int and also in globals. As to my straightforward code, it is not written yet. At the moment I have a simple "search-in-global engine", which matching ability should be improved (regexp?) and replacement functionality should be added. If speed will turn to be a problem, I will use it with ^ROUTINE, ^rINC and ^oddDEF globals as well, while I dislike this idea and prefer to start with official API (%Dictionary classes).
go to post Alexey Maslov · Aug 18, 2017 Thank you, John.Maybe we should look at RE/parser closer, while I'm not sure if it's able to cope with our great mixture of code (see my comment above). Honestly, string literals matching/replacing is only a small part of a bigger task of adding multi-language support to our HIS.
go to post Alexey Maslov · Aug 10, 2017 Robert,thank you for sharing your experience. I'm just curious:- What was the final database size in GB?- What tool will be used for data analyzis? If a homemade one, will it be based on Caché?
go to post Alexey Maslov · Aug 8, 2017 Jiri,URL in your post points to "Missing or Invalid Document". Right URL seems to be http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...
go to post Alexey Maslov · Aug 1, 2017 If +value=value This classic code is good for checking if the value is canonical number, while the term number can be interpreted in some other ways, e.g. a number in scientific format, double precision number, etc. Caché has a set of out-of-the-box functions to perform some of these checks, e.g. $isvalidnum, $isvaliddouble, $number, $normalize. So, the answer depends on topic starter's conditions. E.g., if I need to check if a number is a numlit (scientific numbers and numbers with starting zeroes are allowed), I'd use `$isvalidnum(x)`. Addition check on being integer (an intlit) can look like: `$isvalidnum(x)&&(+x\1=+x)`. Here are some testing results: USER> w !,?6,"Is number?",?20,"Is integer?",?35,"Is canonic?" USER> for x="001a","002",0,1,"-1.2","+1.3","1E3" w !,x,?10," ",$isvalidnum(x),?20," ",$isvalidnum(x)&&(+x\1=+x),?35,x=+x Is number? Is integer? Is canonic? 001a 0 0 0 002 1 1 0 0 1 1 1 1 1 1 1 -1.2 1 0 1 +1.3 1 0 0 1E3 1 1 0 In other conditions I'd write another code. There is no universal answer to topic starter's question. P.S. As to "Annotated MUMPS Standard" (http://71.174.62.16/Demo/AnnoStd):An intlit is not necessarily a canonic representation of a number. A numlit is not necessarily a canonic representation of a number. The reduction to a canonical numeric representation involves (colloquially) the removal of any redundant leading and trailing zeroes, the conversion of exponentionential notation to "mantissa only" notation, and the reduction of any leading plus (+) and minus (-) signs to at most one leading minus sign (see also Numeric interpretation of data).
go to post Alexey Maslov · Jul 19, 2017 Method with a variable arity can also pass through their arguments to the next methodGood point!Wouldn't it be great if $classmethod and $method functions support variable arity as well? (Today they don't, Cache 2017.1). How to use them with such a methods without this feature?PS. Sorry for off-topic.
go to post Alexey Maslov · Jun 16, 2017 Via SSH (putty, etc), am I right that you need to call csession <instance> to enter the Caché terminal? If so, there is no talk about SSH all. Caché has got embedded libssh2.dll/.so ages ago. Why not implement internal SSH server which can be a reasonable replacement for outdated (and Windows only) telnet one? It seems that some other projects (besides Web terminal) would take advantage from it.
go to post Alexey Maslov · Jun 8, 2017 As large as 20 chars in expression mode. /// ("鑔" = chǎ - small cymbals) * ("斚" = jiǎ - a small ancient stone cup for libations) ClassMethod main() As %String [ CodeMode = expression ] { $a("鑔")_$q*$a("斚") }
go to post Alexey Maslov · Jun 2, 2017 Our customers are to check DB integrity on regular basis, usually weekly, while I don't remember a case when it showed errors which were not evidient without it (<DATABASE> errors in error and console logs, etc).Last time when I had an opportunity to use ^REPAIR was about 1.5 year ago, when our support specialist defragmented free space in a database under Caché 2015.1.2. The bulletin from InterSystems about the possibility of defragmentation errors arrived a bit later... Thanks to backup performed before the defragmentation, the opportunity to use ^REPAIR was closed that time :) After upgrade to 2015.1.4 no errors of such kind were detected in the field.The faults of Integrity check are:- when there is some concurrent users' activity it may provide false positives in per database summary report (Errors found in database...) while there are no real errors neither in database nor in per global report;- (mostly about TASKMGR): there is no way to include into the task completion reports (which can be e-mailed) any information from the task, e.g., about errors found by Integrity.
go to post Alexey Maslov · Jun 1, 2017 Sergey, you are doing a great job popularizing our (unfairly) niche technology!Despite the article was published on private resource, such a phrase: They were first introduced in 1966 in the M(UMPS) programming language (which later evolved into Caché ObjectScript, COS), which was initially used in medical databases.sounds (at least for me) as a disrespect to many talented people who contributed to the technology in terms of many other M implementations. Some of them already gone...Truth should sound like this: COS was developed by InterSystems as a superset of M (see http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...). The original language is still accepted by developers' community and alive in a few implementations. There are several signs of activity around the web: MUMPS Google group, user group (http://mumps.org/), effective ISO Standard (http://71.174.62.16/Demo/AnnoStd), etc.
go to post Alexey Maslov · Jun 1, 2017 Another option is to use a classmethod %SYS.ProcessQuery::ExamStackByPid().