Danny Wijnschenk · Jan 17, 2018 go to post

If you substract the current day-of-the month from the current date in $horolog format, you will end up with the first day of the current month in $horolog format :

Write $horolog - $zdate($horolog, 4) + 1

If your date is in another format, convert it using $zdateh/$zdate, see also :

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

and

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Danny Wijnschenk · Nov 20, 2017 go to post

Turn on Auditing (Portal -> System Admin -> Security -> Auditing -> Enable Auditing, configure system events to audit login failures ).

It can give you a clue on why you are getting Access Denied.

It could be an issue of licensing : check the system dashboard for Licensing use (maybe you have too many connections open).

If all this does not help, you can also turn on ODBC logging in the ODBC DSN.

Danny Wijnschenk · Nov 14, 2017 go to post

Hi Laura,

Can you check in the cconsole.log for any error messages ? If your cache.dat is not RW accessible by Caché, you get an error like :

11/14/17-16:55:39:138 (16952) 0 DKMOUNT: Mounted SFN 6 DB 'c:\intersystems\cache\mgr\user\' as Read Only DB. File or filesystem allows read-only access. 

Danny Wijnschenk · Nov 14, 2017 go to post

Hi Laura,

Can you look at the directory where your cache.dat is located.

If a database is mounted, there should be a cache.lck file with the root directory  and name of the Caché that mounted it.

If the root/name is not the same as your Caché system, it will not mount it as RW.

Best is to stop Caché (or dismount the database), remove the cache.lck, and mount/start Caché again.

(If you are sure that this DB is not used by another Caché).

Danny Wijnschenk · Nov 11, 2017 go to post

Your use of Set $listbuild was unknown to me : i only used it on the right hand side (like Set var = $lb(...) ), but on the left-hand side, it is ideal to set a bunch of variables in the same instruction, cool !

Danny Wijnschenk · Nov 3, 2017 go to post

hi Dmitry,

i gladly take your hints, this is precisely the goal of this article series : to comment and discuss code and make it better or point out alternative code.

Using streams is to be preferred over the Open command (like showed in Bert's code), you can see the age difference in comparing our code !

I limit the use of standalone Else to checking a timeout.

For example:

Lock +^MyLock("MyBatch"):1 Else  Quit "job is already running"

which is identical to 

Lock +^MyLock("MyBatch"):1
If '$Test {
    Quit "job is already running"
}
Danny Wijnschenk · Oct 31, 2017 go to post

You will always need to add the property and an entry in the storage section of the mapped class.

If you include the class source and global entry, we can help you in more detail.

Danny Wijnschenk · Oct 22, 2017 go to post

put your code in a try {  } catch { } block to prevent that Cache will not start if there are errors in your code

Danny Wijnschenk · Sep 19, 2017 go to post

Hi Steve,

It also depends if you are indexing all the sources at once or a bunch per day  : typically, a batch load will grow your database, and will leave it 50% empty at the end, after deleting  temporary storage. This is not a problem if you load new sources regularly, since this empty space will be used the next time.

If these temporary iKnow globals are mapped to cachetemp, dont forget to take this needed disk space into account as well, even if it will be released after restart. (especially since cachetemp is by default installed on the same drive as Caché, and could have less free disk space as other drives where you put your databases)

Danny Wijnschenk · Sep 14, 2017 go to post

Quick & Dirty : You could copy the cache.dat, and delete in one all routines and in the other all globals.

(but you might end up with a routines DB which has too much free space...)

Danny Wijnschenk · Jul 18, 2017 go to post

Make sure you don't assign more memory than the available physical memory : your OS will swap to the hard disk which will cancel the benenefits of global buffers.

Danny Wijnschenk · Jul 12, 2017 go to post

Global memory works with blocks and not with nodes :

When a global  node is accessed, the block where this global node is stored will be put into memory.

Any routine that needs to access the nodes that are in this block will be served from memory.

So, in your example, if the nodes (1), (1,2) and (1,7) are all stored in the same block, these will all be served from memory after the initial access by routineA.

Blocks are nowadays 8Kb (used to be 2Kb).

Danny Wijnschenk · May 11, 2017 go to post

Hi Amir,

You should convert all incoming data that is not in your native encoding : you don't want data in your database that is coming from ODBC, Web, Files or other to have different encodings !

I use $ZCONVERT( ... , "I", "UTF8") for all incoming data thru rest, and use $ZCONVERT( ... , "O", "UTF8") for all data that is sent via rest. I also use the "u" format flag when i use %WriteJSONFromSQL.

Danny Wijnschenk · May 11, 2017 go to post

- If the two directories should have the same classes, you could use class mapping to point the two namespaces to the same code base ...

Beside getting a source code tool, there are several ways to compare  :

- If you want to write your own compare logic, you can use the %Dictionary.* classes (a lot of work,  since there are a lot of classes /properties to compare). Use this to get a list of classes in the two directories and to see which is missing.

- If you want to compare  two classes quick-and-dirty : you can have a look at the global ^oddDEF. It contains the class definition of all classes : methods, properties, indexes, storage etc. are all in this global. You could $ZOrder your way through the global and compare the two namespaces. But since this is internal stuff, it could change in new versions of Caché!

Here is an example, but test before you use it !!!

Class Utils.Classes{

/// Compare two classes :
/// If ##class(Utils.Classes).Diff("USER","TEST","Data.MyClass", .reason) {
///   Write $List(reason, 1)," = ",$List(reason, 2) ;global from USER///   Write $List(reason, 3)," = ",$List(reason, 4) ;global from TEST
/// }ClassMethod Diff(ns1 As %String, ns2 As %String, class As %String, ByRef reason As %String){   Set diff = ..Diff1way(ns1, ns2, class, .reason)   If 'diff Set diff = ..Diff1way(ns2, ns1, class, .reason)   Quit diff}ClassMethod Diff1way(ns1 As %String, ns2 As %String, class As %String, ByRef reason As %String){   Set diff = 0   Set startref1="^["""_ns1_"""]oddDEF("""_class   Set startref2="^["""_ns2_"""]oddDEF("""_class   Set global1="^["""_ns1_"""]oddDEF("""_class_""")"   For {       Set global1=$ZOrder(@global1) Quit:global1=""  Quit:global1'[startref1       Set data1=$Get(@global1)       Set subs=$Piece(global1,class,2,*)       Set global2=startref2_subs       Set data2=$Get(@global2)       If (subs=""",63)")!(subs=""",64)") Continue  ;properties time changed (63) & time created (64) can be different       If data1'=data2 Set diff=1,reason=$lb(global1,data1,global2,data2) Quit   }   Quit diff}

}
Danny Wijnschenk · Apr 29, 2017 go to post

And you can even use the Output window in Studio to execute commands (but don't do Halt !)

Danny Wijnschenk · Apr 28, 2017 go to post

If the restore succeeded on a Caché 2015 installation, it might be easier to copy the cache.dat's from that version to your 2016 installation! (what was the version of the original backup).

Without detailed info it is hard to find the exact cause (cache.cpf, cconsole.log), connect me directly or  mail support@intersystems.com if you cannot find a work around.

Danny Wijnschenk · Apr 27, 2017 go to post

Can you look in the directory r:\data\blabla :

there should be a CACHE.DAT, and it should not be locked by another Caché instance.

You can verify who locked the CACHE.DAT file by looking at the cache.lck file in the same directory, this file contains the mgr directory  of the Caché instance who mounted the CACHE.DAT database :

  • If Caché is not running, there should not be a cache.lck file.
  • If Caché is running, the cache.lck should contain the mgr directory and server name of the Cache instance.

You can stop Caché and delete the cache.lck file if any of the previous conditions are false. After startup and mount, the cache.lck file should automatically be created with the proper mgr directory name. (mount will occur by accessing the database or namespace using the database).

Danny Wijnschenk · Apr 26, 2017 go to post

If you did not install Caché with minimal security, make sure your Caché user has sufficient privileges in Caché to run $ZF(-1 : you need the %System_CallOut resource.

Danny Wijnschenk · Apr 9, 2017 go to post

And if you want to make your own prompt, you could even use your own Shell routine :

Shell ;
    For {
        Try {
            Write !,$$Prompt()
            Read cmd Write !
            Xecute cmd
        } Catch {
            Write $ZE,!
        }
        If ($ZCVT($G(cmd),"U")="QUIT") Quit
    }
    Quit
Prompt() ;Create your own prompt here !
    New prompt
    Set prompt = $ZDate($H,4)_" - "_$ZTime($P($H,",",2))_" > "
    Quit prompt
Danny Wijnschenk · Apr 1, 2017 go to post

You can put some code in the OnHandleCorsRequest to debug or monitor the CORS handling :

/// This is the CORS request handler. User should override this method in their subclass
/// if they don't want the default behavior
ClassMethod OnHandleCorsRequest(pUrl As %String) As %Status
{
    #; The default implementation is simply to dispatch to the
    #; default handler
    Set tOrigin=$Get(%request.CgiEnvs("HTTP_ORIGIN"))
    Set ip = $Get(%request.CgiEnvs("REMOTE_ADDR"))
    Set method = $Get(%request.CgiEnvs("REQUEST_METHOD"))
    set ^debug($i(^debug))=$lb($ZD($H,8),$ZT($P($H,",",2)),pUrl,tOrigin,ip,method)
    Quit ..HandleDefaultCorsRequest(pUrl)
}