go to post Timur Safin · Aug 2, 2016 Like this one? USER>write $match("abcdeabcde", "(a|b).*(de|fg)") 1 USER>write $match("abcdeabcfg", "(a|b).*(de|fg)") 1
go to post Timur Safin · Jul 21, 2016 You only partially correct: yes, as lazy developers we prefer to write only 1 method call, instead of 2 chained together;but, no, this is not %Connect (which may be expensive operation) which should move to the %OnNew, but rather other way around. I.e. for the cases when we need both (not actually in 100% of a cases, rather 90%) we could create combined classmethod, which will create instance of a class via call to %New() and then will proceed the necessary side-effect. i.e. ClassMethod %ConnectNew(Config As %Object) As Sample.RemoteProxy { ... } In general, you should rather avoid creating huge DOM tree of an objects, or proceeding network operations inside of %New constructor. Constructor needs to allocate just bare minimum of memory, necessary for beginning of operations, and initialize fields to their default values [that will be done automatically]. That's it.
go to post Timur Safin · Jul 19, 2016 As a dirty workaround I'd suggest to use Google query modifier which allows to narrow down results to only particular site, you need to use site:URL clause for this, i.e. for searching for "dynamic dispatch" over community site you could use this query:https://www.google.ru/#q=dynamic+dispatch+site:community.intersystems.com
go to post Timur Safin · Jul 18, 2016 Also about comment to move %Connect code inside of %New.This is not, generally a good idea to insert potentially long and slow code inside of object constructor. I prefer to have slim and fast %New, which might be nested elsewher to some wrapping onjects. While keeping slow, and expensive functions like %Connect in this case, outside of constructor, independently callable.For example, try to use incorrect login details here and then see how long it will take to fail such connection (i.e. timeout period).
go to post Timur Safin · Jul 18, 2016 Because:I hate long list of arguments passed to function, especially when most of them are optional;In similar cases I prefer to use named-arguments approach, whcih I saw otiginally in Perl (here is the quick link I've found which shows this idiom). Named arguments allow to pass arguments in any order, which allows to avoid many related errors if (optional) argument passed in the worng order.Named-arguments were actually creating hash object in Perl, with which we worked later, accessing it's key-value pairs. But at the end of a day the new, JSON dynamic objects we have in Cache' are semantically equivalent to hash-objects we were operating in Perl in the past;Thus similar idiom could be used in the ObjectScript.P.S.Though I agree, that was some stretching to use this idiom in this particular case, with not that much large number of arguments. But at least it didn't make code less readable. :)
go to post Timur Safin · Jul 8, 2016 Actually I don't see any value for checking $data for intermediate subscript (and check their consistency only at the most beginning of a function). Here is my [hopefully] simpler version CompareArrays(refL, refR) if $data(@refL) '= $data(@refR) { // they are not consistent: one is non-array return 0 } do { // fetch next data node subscript and it's value set refL = $query(@refL, 1, valueL), refR = $query(@refR, 1, valueR) if refL="" || (refR="") { quit } set subL = $qlength(refL), subR = $qlength(refR) if subL'=subR || (valueL '= valueR) { return 0 } // check each subscipt individually for i=1:1:subL { if $qsubscript(refL, i) '= $qsubscript(refR, i) { return 0 } } } while refL'="" && (refR'="") // only after all checks passed return refL=refRDebugArrayCompare() new set m(1,1,1)=11,m(1,2)=12,m(2,1)=133 set n(1,1,1)=11,n(1,2)=12,n(2,1)=133 write $$CompareArrays($name(m),$name(n)),! set n(3,1)=0 write $$CompareArrays($name(m),$name(n)),! quit
go to post Timur Safin · Jun 30, 2016 So you are using ODBC access in WinSQL to connect to CacheODBC source, from particular namespace... Did you check you are using DSN pointing to the desired namespace? Did you check the bitness (32- or 64-bit) for DSN you use in WinSQL?
go to post Timur Safin · Jun 22, 2016 Small correction though: the referred github sources are fork, and have been created not by Dmitry Maslennikov (@daimor) but by Eduard Lebedyuk (@eduard93)
go to post Timur Safin · Jun 17, 2016 Thanks, Dima, [I did expect you will publish it] and this advice is very interesting and easier to apply by "lazy devops engineer". Though some explanations and comments won't harm. Hope you'll find some time eventually to write article. P.S.Could not resist and not say my few notes about your docker file:- from pure micro-services point of view for the generic case of multiple ECP clients it makes no much sense IMHO to install csp gateway to each of instantiated docker instances;- I'd invoke it at the master (ECP database server) instance, or probably as separate docker image;- [though I suspect, that for HAproxy scenario you might needed to have this CSP-gateway services spread over each instance just for high-availability scenario. I'll be curious that Luca would recommend here from micro-services prospective?]
go to post Timur Safin · Jun 16, 2016 Let put aside software architecture (I'll write later some number of articles abut what I mean here), let talk about dirty details. If you have any oncrete details about the way you use Swarm, Ansible, Chef, or similar, then I (and community) will highly appreciate. P.S. It will simplify things a lot if we could configure ECP mapping at the runtime via some set of API calls, and not statucally via editing cache.cpf. Something like it's done in MongoDB for adding new shard: sh.addShard("repl0/mongodb3.example.net:27327") https://docs.mongodb.com/manual/reference/method/sh.addShard/ But not for the scenario of adding shard to shard-manager in particular, but for something more generic for ECP or mapping. I suspect there is something related already implemented for EM, but I have no clue how to use it for my case. P.P.S. And I know there is already implemented AssignShards call in the forthcoming product, but it's too much specific, creating particular set of mappings. I'd need to have it more generic.
go to post Timur Safin · Jun 16, 2016 Could you please share those Terraform configs, or at leats key part of them (concerning Cache.cpf modifications and alike).
go to post Timur Safin · Jun 3, 2016 This sounds very interesting.I could not give any data proven onclusion without looking into sar or mgstat data, but from your words it sounds like the bottleneck here is ObjectScript VM or engine interprocessor locks implementation. This is hard to believe taking into accont that we are talking about "io bound" experiment, but if you will show us sar metrics...
go to post Timur Safin · Jun 3, 2016 Few easy questions first:- how much memory did you allocate for your global buffers?- Did you see ^mgstat statistics at the moment your code was busy walking over huge globals?- and did you play with global prefetching in this case?P.S.Let put aside write amplification problem, disable global modifications and attack read performance first.
go to post Timur Safin · Jun 1, 2016 Given the returned from Quote^%qcr expression you could use XECUTE to reevaluate the string, i.e.: DEVLATEST:22:51:39:USER>set q= $$Quote^%qcr(lb) DEVLATEST:22:51:54:USER>x "s u = "_q DEVLATEST:22:52:30:USER>zw u u=$lb(1,2,3,",",5)
go to post Timur Safin · Jun 1, 2016 ZWRITE command is implemented in the ObjectScript, and if you are happy with the way it's quoting $LB then you could reuse it's core functionality, i.e. DEVLATEST:22:47:39:USER>set lb = $listbuild(1,2,3,",",5) DEVLATEST:22:47:41:USER>write $$Quote^%qcr(lb) $lb(1,2,3,",",5)
go to post Timur Safin · May 30, 2016 Yes, we need a way to change your own vote after you've accidentally pushed the wrong star (and the chance to push wrong start is dramatically increased if you have fat fingers and touchscreen. Done it many times :( ).
go to post Timur Safin · May 30, 2016 Let see to the keypad again, it's getting obvious instantly that keys are (mostly) located by groups of 3 symbols, and if there would not be those "s" (corresponding to "7777") and "z" (which produces "9999") then implementation will be simple formula with division by 3 and corresponding modulo. Also space is exception and is not a part of sequential numerics. So given this assumprion let us create the 1st approximation (no compression, not name reduction, everything ie readable and commented): 0(s) public { set S="" for %=1:1:$length(s) { set P="" set c = $e(s,%) set i = $a(c) - $a("a") if c=" " { set P="0" } elseif c="z" { set P="9999" } elseif c="s" { set P="7777" } elseif i<($a("s") - $a("a")) { // ($a("s") - $a("a")) = 18 set n=i\3+1,m=i#3+1 set before2 = $a("1") ; 49 set $p(P,$c(n + before2),m+1)="" } else { set n=i-1\3+1,m=i-1#3+1 set before2 = $a("1") ; 49 set $p(P,$c(n + before2),m+1)="" } set:$extract(S,*)=$extract(P,1) S=S_" " set S=S_P } quit S } [Don't botther to count symbols - we will compress the code a bit] This strange `set $piece(string,symbol,offset+1) = ""` is actually filling of a string with the given symbol. Let us review those several ifs, we see, actually, 2 groups of them: 3 ifs for exceptions fom formulae;2 ifs for disjointed rows of groupd by 3 keys. The formulae is atually the same, but witth some offset. So let's get rid of ifs via $select and extra offset itroduced. #; get rid of ifs, replace with $selects 1(s) public { set S="" for %=1:1:$length(s) { set P="" set c = $e(s,%) set i = $a(c) - $a("a") ; $a("a")=97 set o = i '< 18 ; ($a("s") - $a("a")) = 18 set $p(P, $c(i - o\3+1 + $a("1")), i - o#3+1+1)="" set P=$select(c=" ": "0", c="z": "9999", c="s": "7777", 1:P) set:$extract(S,*)=$extract(P,1) S=S_" " set S=S_P } quit S } [I believe this step is still obvious] [[I dislike the way I had to put expressions without pairs but we need as short as possible, sothis is inevitable evil.]] Now this is time to get shorter, but stiill readable version: #; name reduction 2(s) public { s S="" f %=1:1:$l(s) { s P="" s c = $e(s,%) s i = $a(c) - $a("a") ; $a("a")=97 s o = i '< 18 s $p(P, $c(i - o\3+1 + $a("1")), i - o#3+1+1)="" s P=$s(c=" ": "0", c="z": "9999", c="s": "7777", 1:P) s:$e(S,*)=$e(P,1) S=S_" " s S=S_P } q S } That was simple- select code in Studio, then press Ctrl+Shift+E. And the latest step, is to convert this barely readable code to 1 line mess hard-code stuff: #; linearization 3(s) public { s S="" f %=1:1:$l(s) {s P="",c=$e(s,%),i=$a(c)-97,o=i'<18,$p(P,$c(i-o\3+50),i-o#3+2)="",P=$s(c=" ":"0",c="z":"9999",c="s":"7777",1:P) s:$e(S,*)=$e(P,1) S=S_" " s S=S_P} q S } That's (if you count the 1st indent symbol) 173 characters length. P.S. Eduard Lebedyuk has improved this result a little bit: he has replaced quoted literals with numerics (because they are both represend canonical numericsfrom ObjectScript point of view);and replaced (where possiblle) comparisons of characters with comparisons of their derived ordinals (minus 97, or "a") #; +Eduard modifications 4(s) public { s S="" f %=1:1:$l(s){s P="",c=$e(s,%),i=$a(c)-97,o=i>17,$p(P,$c(i-o\3+50),i-o#3+2)=P,P=$s(i<0:0,i=25:9999,i=18:7777,1:P),S=S_$s($e(S,*)=$e(P):" "_P,1:P)} q S } We are 158 now!
go to post Timur Safin · May 30, 2016 157 is impressive: my first result was 174, which Eduard has improved to 161. I didn't thought it might be improven even further :)