LDAS logo
TclDOC logo

The metadata.tcl Script

Modification Date: 11/26/2008

Table of Procedures

red ball ${API}::atExit
red ball metadata
red ball metadata::cmdTime
red ball metadata::destructObjs
red ball metadata::destructThreads
red ball metadata::evalCmd
red ball metadata::init
red ball metadata::killJob
red ball metadata::log
red ball metadata::registerObj
red ball metadata::runningInsertStatsFile
red ball metadata::setSchema
red ball metadata::submit
red ball metadata::wakeupDataRecvThreads

metadata.tcl Version 1.0 Wraps the metadataAPI.so and the genericAPI.so and the genericAPI.tcl for use by the metadata API.
Provides data retrieval functions for the LDAS.
Release Date: Not Available The caller wishing to use these functions without qualifiying the names with metadata:: should include the line:
namespace import metadata::*.
after requiring or sourcing this code. Possibly qualfying this with:
namespace forget metadata::someProc.
Which will make the forgotten commands inaccesible outside of the metadata namespace. (rendering them "private" in the c++ class sense.)
Run environment: requires DB2 client side:
ODBC driver DM: IBM Driver Manager Dataset name: ldas_tst All data for job is saved in global ::${jobid} array

package provide metadata 1.0
package require metadataAPI
package require metadataSpectrum
package require metaCallback
package require metaschema
package require getMetaData
package require putMetaData
namespace eval metadata {}

§   §   §

Name: ${API}::atExit

Description:
dump more thread info via ssh Usage:

Comments:

proc ${API}::atExit {} {
	;## remove the threads when cancel threads work
    set threads [ getThreadList ]
    set text "cleaning up threads $threads"
    foreach { tid func status } [ getThreadList ] {
        regexp {\(([^\)]+)\)} $func -> threadfunc
        append text "thread function ${threadfunc}_r"
        ${threadfunc}_r $tid
    }
	set objects [ getElementList ]
    append text "Threads $threads "
	append text "destroying objects $objects, "
	foreach datap $objects {
		destructElement $datap
	}
	append text "channels [ countChannels ]"	
    addLogEntry $text
}

§   §   §

Name: metadata::log

Description:
tags the interp's name to log
Parameters: Usage:
 metadata::log $msg
Comments:
proc metadata::log { { msg "" } { errlvl 0 } { caller "" } } {
     catch { set jobid [ uplevel set jobid ] }
     set log $::LOCAL_LOG_FILE
     if { [ catch {
        if { ! [ string compare "" $caller ] } {
           set caller [ uplevel myName ]
        }
        if  { $errlvl || $::DEBUG > 1 } {
    	    addLogEntry "'$msg'" $errlvl $caller [ gpsTime ] $log
        }
     } err ] } {
       if { $::DEBUG } {
          puts stderr "[ myName ]: $err"
       }
     }
}

§   §   §

Name: metadata::init

Description:
Initialization on startup by manager in genericAPI.

Parameters: Usage:
metadata::Init
Returns:

None.
Comments:
Called by genericAPI on startup save the log file entry to share with slave
proc metadata::init {} {
    if  { [ catch {
        ;## patterns for retry
        set patfile [ file join $::TOPDIR metadataAPI SQLretries.putMetaData ]
	    if	{ ! [ file exist $patfile ] } {
		    set patfile [ file join $::LDAS lib metadataAPI SQLretries.putMetaData ]
	    }
	    set patterns [ dumpFile $patfile ]
        set patterns [ split $patterns \n ]
        set temp [ list ]
   	    foreach pattern $patterns {
		    if	{ [ regexp {^#} $pattern ] } {
			    continue
		    }
            regexp {([^#\s\t]+)} $pattern -> pattern
            lappend temp "($pattern)"
        }
        set ::pattern_putMetaData [ join $temp \| ]
        set patfile [ file join $::TOPDIR metadataAPI SQLretries.getMetaData ]
	    if	{ ! [ file exist $patfile ] } {
		    set patfile [ file join $::LDAS lib metadataAPI SQLretries.getMetaData ]
	    }
	    set patterns [ dumpFile $patfile ]
        set patterns [ split $patterns \n ]
        set temp [ list ]
   	    foreach pattern $patterns {
		    if	{ [ regexp {^#} $pattern ] } {
			    continue
		    }
            regexp {([^#\s\t]+)} $pattern -> pattern
            lappend temp "($pattern)"
        }
        set ::pattern_getMetaData [ join $temp \| ]
        ;## set to 2 to get one retry
        if  { ! [ info exist ::MAX_TRIES ] } {
            set ::MAX_TRIES 2
        }
        if  { ! [ info exist ::METADATA_MAX_JOB_TIME ] } {
            set ::METADATA_MAX_JOB_TIME 50000
        }
        if  { ! [ info exist ::THREAD_TIMEOUT_SECS ] } {
            set  ::THREAD_TIMEOUT_SECS  50
        }
        if	{ [ regexp {8.4} $::tcl_version ] } {
    		set ::metadata::tcl8.4 1
        }
        ;## bgLoop metadata_wakeupDataRecvThreads metadata::wakeupDataRecvThreads 60
    } err ] } {
        addLogEntry $err 2
    }
}

§   §   §

Name: metadata::cmdTime

Description:
compute the time taken to process cmd
Parameters: Usage:
execSlaveCmd $slave
Returns:

results of cmd
Comments:
proc metadata::cmdTime { jobid } {
     if	{ [ catch {
        if  { [ info exist ::${jobid}(cmdstem) ] } {
            set cmdstem [ set ::${jobid}(cmdstem) ]
            set dbname  [ set ::${jobid}(-database) ]
		    ;## usage log for queries
            if  { [ regexp {getMetaData|descMetaData} $cmdstem ] } {
                set wallsecs [ __t::mark $jobid ]
                __t::cancel $jobid
			    set begintic [ set ::${jobid}(begintic) ]
			    # set endtic [ exectime ]
                set endtic 1.0
			    set rows [ set ::${jobid}(Rows) ]
			    if	{ ! [ info exist ::${dbname}(queries) ] } {
				    set ::${dbname}(queries) 0
			    }
                incr ::${dbname}(queries) $rows
			    addLogEntry "$cmdstem for database $dbname CPUtime=[ expr $endtic - $begintic ] secs, \
			    walltime=$wallsecs secs; received [set ::${dbname}(queries)] queries since start up." blue
            } else {
			    set dims [ set ::${jobid}(dims) ]
			    if	{ ! [ info exist ::${dbname}(inserted) ] } {
				    set ::${dbname}(inserted) 0
			    }
                incr ::${dbname}(inserted) $dims
			    ;## timing already done in slave
			    addLogEntry "$cmdstem inserted [set ::${dbname}(inserted)] rows into database $dbname since start up." blue
            }
        }
    } err ] } {
        return -code error $err
   	}
}

§   §   §

Name: metadata

Description:
cleanup and returns response to manager
Parameters: Usage:
cleanupJob
Returns:

None.
Comments:
maybe called from error or killJob by manager
proc metadata::cleanupJob { jobid caller { abort 0 } } {
    set jobexist 0
	if	{ [ catch {
        if  { [ info exist ::${jobid} ] } {
            set jobexist 1
            if  { ! [ info exist ::${jobid}(errors) ] && ! $abort } {
                metadata::cmdTime $jobid
            }
		}
    } err ] } {
        log  $err 2
	}
    # catch { destructObjs $jobid }
    ;## may overwrite a reused thread
    # catch { destructThreads $jobid }
	if	{ [ catch {
        if  { $jobexist } {
            set callback [ set ::${jobid}(cmd) ]
		    eval $callback $jobid 	
        }
	} err ] } {
		addLogEntry "$jobid called by $caller: $err" blue
	}	
}

§   §   §

Name: metadata::evalCmd

Description:
Evaluate a cmd from operator input; this is the main entry point into metadata namespace. It is called within metadata macros.

Parameters: Usage:
metadata::evalCmd $cmd
Returns:

None.
Comments:
More vigorous checking of cmd is needed this function returns back to operator proc in LDASgwrap
proc metadata::evalCmd { jobid cmd } {
	set seqpt ""
	set dbname $::DATABASE_NAME
	if	{ [ catch {
		set cid [ set ::${jobid}(cid) ]		
		if	{ ! [ regexp -- {-database\s+[\{]*(\S+)[\}]*\s+} $cmd -> dbname ] } {
			set dbname $::DATABASE_NAME
		}
		set seqpt "check $dbname"
    	regsub -all {\{} $dbname {} dbname
    	regsub -all {\}} $dbname {} dbname
    	if  { ! [ string length $dbname ] } {
        	set dbname $::DATABASE_NAME
    	}
		set ::${jobid}(errlvl) 0
        set ::${jobid}(-database) $dbname
    	if  {  [ regexp "^\[ \t]*$"  $cmd ] } {
        	set ::${jobid}(errlvl) 3
        	log "malformed command: cmd=$cmd,$errmsg"
        	set result "malformed command: cmd=$cmd,$errmsg"
        	error $result
    	}
    	set cmdstem [ lindex $cmd 0 ]
		set callback [ set ::${jobid}(cmd) ]
        set ::${jobid}(cmdstem) $cmdstem
        ;## validate the database
        ;## IF THE DSO IN A DATAPIPELINE OR DATASTANDALONE/PUTSTANDALONE JOB IS NOT
        ;## IN THE /LAL/LIBRARY DIRECTORY (THE OFFICIAL LAL RELEASE DIRECTORY) THEN
        ;## LDAS MUST OVERWRITE AND FORCE THE RESULTS TO GO IN THE TEST DATABASE.
        if  { [ info exist ::${jobid}(-dynlib) ] } {
            set dso [ set ::${jobid}(-dynlib) ]
            if  { ! [ regexp {^lib} $dso ] &&
              ! [ regexp $::DYNLIB_DIRECTORY $dso ] &&
              ! [ regexp {(tst|test)} $dbname ] } {
                error "non standard DSO $dso should be inserted \
                into test database only, "
            }
        }
        if  { ! [ info exist ::${dbname}(login) ] } {
                error "$dbname is not a valid database name, \
                must be [ set ::site_dbnames($::LDAS_SYSTEM) ]"
        }
        eval $cmdstem $jobid			
	} err ] } {
        metadata::putMetaDataOjDel $jobid
		set msg "cmd=$cmd, database $dbname, $err"
        set ::${jobid}(errors) $err
        if  { [ regexp -nocase {mysterious} $err ] } {
            log "$seqpt: $msg" 3
        } else {
		    log "$seqpt: $msg" 2
        }
        cleanupJob $jobid [ myName ]
	}
}

§   §   §

Name: metadata::killJob

Description:
Terminate a job by force by deleting the slave interp
Parameters: Usage:
metadata::killJob $jobid
Returns:

None.
Comments:
force job to abort but dont record statistics.
proc ${API}::killJob { jobid } {
    if  { [ catch {
        cleanupJob $jobid [ myName ] 1
    } err ] } {
        log $err 2
    }
}

§   §   §

Name: metadata::runningInsertStatsFile

Description:

Parameters: Usage:

Comments:

proc metadata::runningStatsFile {  jobid cmd rows { table "" } } {
     if { [ catch {
	 		
       	set endtime [ gpsTime ]
        if	{ [ info exist ::${jobid}(-userid) ] } {
			set userid [ set ::${jobid}(-userid) ]
		} else {
			set userid ldas
		}
        set dbname [ set ::${jobid}(-database) ]
        set usercmd [ set ::${jobid}(-commandname) ]
        if  { [ regexp {dataPipeline} $usercmd ] } {
            set dso [ set ::${jobid}(-dynlib) ]
            set usercmd "${usercmd}($dso)"
        }
        set active  $::LDASLOG/$cmd.log
        set archive $::LDASARC/jobstats_archive/$cmd.log.$endtime
        set dir $::LDASARC/jobstats_archive
		
        if { ! [ file isdirectory $dir ] } {
           file mkdir $dir
           file attributes $dir -permissions 04755
           gifBalls $dir
        }
        set mb [ expr { 1024 * 1024 } ]
        if { [ file exists $active ] } {
           if { [ file size $active ] >= $mb } {
              file rename $active $archive
           }
        }
		set fid   [ open $active a+ ]
        puts $fid "$endtime $userid $usercmd $dbname $rows $table"
        ::close $fid
		
        file attributes $active -permissions 0644
     } err ] } {
        catch { ::close $fid }
        return -code error "[ myName ]: $err"
     }
}

§   §   §
global procs
Name: metadata::registerObj

Description:
Save ilwd object in list for destruction later transactions
Parameters: Usage:
 registerStmt $stmtp
Comments:
Should call metadata::destructObjs when done
proc metadata::registerObj { jobid elemp } {
	if	{ [ array exist ::${jobid} ] } {
    	lappend ::${jobid}(objects) $elemp
        debugPuts "registered $elemp"
	}
}

§   §   §

Name: metadata::destructObjs

Description:
Destroys ilwd objects allocated for the database transactions
Parameters: Usage:
 destructObjs
Comments:
All ilwds allocated for transaction should be saved already in ::metadata::obj_list
proc metadata::destructObjs { jobid } {
	if	{ [ catch {
	if	{ [ info exist ::${jobid}(objects) ] } {
    	foreach elemp [ set ::${jobid}(objects) ] {
        	if { [ catch {
                destructElement $elemp
                if  { [ string length [ info commands $elemp ] ] } {
                    debugPuts "rename $elemp"
                    rename $elemp {}
                }
			} err ] } {
				log "destructElement $elemp error: $err" 2
			}
		}
		unset ::${jobid}(objects)
    }
	} err ] } {
		log $err 2
		return -code error "[myName], $err"
	}
}

§   §   §

Name: metadata::submit

Description:
submits a query
Parameters: Usage:
       metadata::submit dbquery
Comments:
Assumes that db henv and hdbc have been created DROP statement errors are ignored stmtp is not destroyed here if error will need to do so ?
proc metadata::submit { { dbquery "" } { readonly 0 } } {
    if    { $dbquery == "" } {
        return -code error "metadata::submit query cannot be empty."
    }
    set dbquery [string trim $dbquery "\"\}\{"]
#   create a statement
    set stmtp [ createStmt $readonly ]
	set ::${::jobid}(stmtp) $stmtp
#   submit the statement, ignore DROP statement errors if table does
#   not already exist
#
    if    { [ catch {
          dbEasyStmt_Submit $stmtp $dbquery
    } errmsg ] } {
          log "Statement Submit error: $errmsg" 2
          if    {  ! [regexp -nocase -- {^-|drop|^[ \t]+$} $dbquery] } {
                return -code error $errmsg
          }
    }
    return -code ok $stmtp
}

§   §   §

Name: metadata::setSchema

Description:
set schema to db2 user instance
Parameters: Usage:
 metadata::setSchema $stmtp
Comments:
proc metadata::setSchema { stmtp dbuser } {
	if	{ ! [ string compare $::DBSCHEMA "IBMdb2" ] } {
		if	{ [ catch {
			set sqlcmd "set schema $dbuser"
			dbEasyStmt_Prepare $stmtp $sqlcmd
			dbEasyStmt_Submit $stmtp
			log "submitted set schema for $dbuser"
		} err ] } {
			return -code error $err
		}	
	}
}

§   §   §

Name: metadata::destructThreads

Description:
wait for threads to finish
Parameters: Usage:
 destructThreads $jobid
Comments:
proc metadata::destructThreads { jobid } {
    if  { [ catch {
     	foreach var [ info vars ::metadata::threads_* ] {
        	# addLogEntry "var $var, [ set $var ] jobid $jobid" purple
            set thread_jobid [ set $var ]
        	if	{ [ regexp {metadata::threads_(\S+)} $var -> tid ] } {
            	if	{ [ string equal $jobid $thread_jobid ] } {
            		set threadfunc none
            		catch { set threadfunc [ getThreadFunction $tid ] }
            		addLogEntry "cleaning up $thread_jobid $tid '$threadfunc'" purple
                    if	{ ! [ string equal none $threadfunc ] } {
            			catch { ${threadfunc}_r $tid }
                    }
                }
        	}
        }
    } err ] } {
    	addLogEntry $err red
    }
}

§   §   §

Name: metadata::wakeupDataRecvThreads

Description:

Parameters: Usage:

Comments:

wake up dataRecv threads for a job that did not reach finish state
proc metadata::wakeupDataRecvThreads  {} {
    if  { [ array exist ::dataRecvStates ] } {
        foreach tid [ array names ::dataRecvStates ] {
            foreach { sid currtime } [ set ::dataRecvStates($tid) ] { break }
            dataRecvReaper $tid $sid
        }
    }
}

§   §   §

up arrow Back to Top up arrow