How to replace the CACHE.DAT of a mirrored database (i.e: when you need to upgrade a software version)
Context:
mirrored configuration with one primary member and one async member (without failover/backup member)
Purpose:
replace the CACHE.DAT of a mirrored database on the primary member.
Steps to follow:
- on the PRIMARY
- remove the database to replace from the mirror
- dismount the database
- copy the new database
- mount the database
- add the database to the mirror
- backup the database (external backup)
- on the ASYNC
- remove the database to replace from the mirror
- dismount the database
- restore the new database backup from the PRIMARY
- mount the database
- activate database
- catch up database
The following script use the same update() method on both PRIMARY and ASYNC members with 2 parameters:
- when executed on the PRIMARY member:
- the first parameter = the directory containing the database to be updated on the PRIMARY
- the second parameter = the directory containing the new database
USER>set db="d:/databases/application"
USER>set newDB="t:/newVersion"
USER>w ##class(install.tools).update(db,newDB)
(1) removing d:\databases\application from MYMIRROR .../...
[USER] d:\databases\application successfully removed from MYMIRROR
(2) dismounting d:\databases\application .../...
[USER] d:\databases\application successfully dismounted
(3) copying t:\newVersion\user to d:\databases\application .../...
[USER] t:\newVersion\user successfully copied in d:\databases\application
(4) mounting d:\databases\application .../...
[USER] d:\databases\application successfully mounted
(5) adding d:\databases\application to MYMIRROR .../...
[USER] database d:\databases\application successfully added to mirror MYMIRROR
NOW YOU HAVE TO BACKUP THE FOLLOWING DATABASE:
d:\databases\application
1
- when executed on the ASYNC member:
- the first parameter = the directory containing the database to be updated on the ASYNC
- the second parameter = the directory containing the backup of the database (newly updated on the PRIMARY)
USER>set db="d:/databases/application"
USER>set backupDB="d:\backup\databases\application"
USER>w ##class(install.tools).update(db,backupDB)
(1) removing d:\databases\application from MYMIRROR .../...
[USER] d:\databases\application successfully removed from MYMIRROR
(2) dismounting d:\databases\application .../...
[USER] d:\databases\application successfully dismounted
(3) copying d:\backup\databases\application to d:\databases\application .../...
[USER] d:\databases\application successfully copied in d:\databases\application
(4) mounting d:\databases\application .../...
[USER] d:\databases\application successfully mounted
(5) activating d:\databases\application to MYMIRROR .../...
[USER] database d:\databases\application successfully activated in mirror MYMIRROR
(6) catching up d:\databases\application .../...
[USER] d:\databases\application database has been caught up successfully
1
Script:
ClassMethod update(database As %String, newdatabase As %String, verbose As %Boolean = 1) As %Status
{
set ns=$namespace,sc=$$$OK
set mirrorName=$system.Mirror.MirrorName()
set:mirrorName="" mirrorName="MYMIRROR"
set preMsg="["_$namespace_"] "
try {
zn "%sys"
set:$system.Version.GetOS()="Windows" database=$replace(database,"/","\"),newdatabase=$replace(newdatabase,"/","\")
set:$system.Version.GetOS()="UNIX" database=$replace(database,"\","/"),newdatabase=$replace(newdatabase,"\","/")
// check CACHE.DAT files
if '##class(%File).Exists(database_"/CACHE.DAT") || '##class(%File).Exists(newdatabase_"/CACHE.DAT") {
set msg="the 2 CACHE.DAT of "_database_" and "_newdatabase_" not found - update not possible "
set sc=$system.Status.Error(5001,msg)
write:verbose msg,!
return sc
}
// remove database from mirror
write:verbose "("_$i(step)_") "_"removing "_database_" from "_mirrorName_" .../...",!
set sc=##class(SYS.Mirror).RemoveMirroredDatabase(database)
set:sc msg=preMsg_database_" successfully removed from "_mirrorName,severity=0
set:'sc msg=preMsg_"Error while trying to remove "_database_" from "_mirrorName_" : "_$system.Status.GetErrorText(sc),severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// dismount database
write:verbose "("_$i(step)_") "_"dismounting "_database_" .../...",!
set sc=##class(SYS.Database).DismountDatabase(database)
set:sc msg=preMsg_database_" successfully dismounted",severity=0
set:'sc msg=preMsg_"Error while trying to dismount "_database_" : "_$system.Status.GetErrorText(sc),severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// replace database
write:verbose "("_$i(step)_") "_"copying "_newdatabase_" to "_database_" .../...",!
set:$system.Version.GetOS()="Windows" command="copy /Y "_newdatabase_"\CACHE.DAT "_database_"\CACHE.DAT"
set:$system.Version.GetOS()="UNIX" command="cp -f "_newdatabase_"/CACHE.DAT "_database_"/CACHE.DAT"
set sc=$zf(-1,command)
set:sc=0 msg=preMsg_newdatabase_" successfully copied in "_database,severity=0
set:'sc=0 msg=preMsg_"Error while trying to execute "_command_" : "_sc,severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// mount database
write:verbose "("_$i(step)_") "_"mounting "_database_" .../...",!
set sc=##class(SYS.Database).MountDatabase(database)
set:sc msg=preMsg_database_" successfully mounted",severity=0
set:'sc msg=preMsg_"Error while trying to mount "_database_" : "_$system.Status.GetErrorText(sc),severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// add database to mirror on PRIMARY
if $system.Mirror.IsPrimary() {
write:verbose "("_$i(step)_") "_"adding "_database_" to "_mirrorName_" .../...",!
set sc=##class(SYS.Mirror).AddDatabase(database)
set:sc msg=preMsg_"database "_database_" successfully added to mirror "_mirrorName,severity=0
set:'sc msg=preMsg_"error while adding database "_database_" to mirror "_mirrorName_" : "_$system.Status.GetErrorText(sc),severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// message recalling to launch the external backup of database newly added to the mirror
write:verbose "NOW YOU HAVE TO BACKUP THE FOLLOWING DATABASE:",!
write:verbose database,!
}
// activate and catch up database on ASYNC
if $system.Mirror.IsAsyncMember() {
// activate database
write:verbose "("_$i(step)_") "_"activating "_database_" to "_mirrorName_" .../...",!
set sc=##class(SYS.Mirror).ActivateMirroredDatabase(database)
set:sc msg=preMsg_"database "_database_" successfully activated in mirror "_mirrorName,severity=0
set:'sc msg=preMsg_"error while activating database "_database_" in mirror "_mirrorName_" : "_$system.Status.GetErrorText(sc),severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
// catch up database
set db="",SFNlist="",dbName=""
set db=##class(SYS.Database).%OpenId(database)
if $IsObject(db) {
set SFNlist=SFNlist_$lb(db.SFN)
set dbName=dbName_$lb(db.Directory)
}
set err=""
write:verbose "("_$i(step)_") "_"catching up "_database_" .../...",!
set sc=##class(SYS.Mirror).CatchupDB(SFNlist,"",.err)
if (sc)&&(err="") {
set msg=preMsg_database_" database has been caught up successfully",severity=0
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
} else {
set catchupErr=""
for i=1:1:$ll(err) {
set msg=preMsg_"error while catching up database "_$lg(dbName,i)_"(SFN:"_$lg(err,i)_")",severity=1
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
write:verbose msg,!
set catchupErr=catchupErr_"("_i_"):"_msg
}
set:sc=0 sc=$system.Status.Error(5001,catchupErr)
}
}
}
catch ex {
set msg=preMsg_"error while executing "_..%ClassName(1)_": upgrade : "_ex.DisplayString(),severity=1
write:verbose msg,!
do ##class(%SYS.System).WriteToConsoleLog(msg,1,severity)
set sc=ex.AsStatus()
}
do ..checkRW(1,0)
zn ns
return sc
}