Index: common.scm ================================================================== --- common.scm +++ common.scm @@ -54,11 +54,11 @@ (declare (uses dbmod)) (import dbmod) (include "common_records.scm") - +;;====================================================================== ;; (require-library margs) ;; (include "margs.scm") ;; (define old-exit exit) ;; @@ -79,10 +79,11 @@ ;;====================================================================== ;; L O C K I N G M E C H A N I S M S ;;====================================================================== +;;====================================================================== ;; faux-lock is deprecated. Please use simple-lock below ;; (define (common:faux-lock keyname #!key (wait-time 8)(allow-lock-steal #t)) (if (rmt:no-sync-get/default keyname #f) ;; do not be tempted to compare to pid. locking is a one-shot action, if already locked for this pid it doesn't actually count (if (> wait-time 0) @@ -103,10 +104,11 @@ (begin (if (rmt:no-sync-get/default keyname #f) (rmt:no-sync-del! keyname)) #t) #f)) +;;====================================================================== ;; simple lock. improve and converge on this one. ;; (define (common:simple-lock keyname) (rmt:no-sync-get-lock keyname)) @@ -123,11 +125,12 @@ (debug:print-info 02 *default-log-port* "Running command: " fullcmd) (cond (with-vars (common:without-vars fullcmd)) (with-orig-env (common:with-orig-env fullcmd)) (else (common:without-vars fullcmd "MT_.*"))))) - + +;;====================================================================== ;; ideally put all this info into the db, no need to preserve it across moving homehost ;; ;; return list of ;; ( reachable? cpuload update-time ) (define (common:get-host-info hostname) @@ -155,10 +158,11 @@ (alist-ref 'adj-core-load (common:get-normalized-cpu-load hostname)))) ;; this is cheaper than you might think. get-normalized-cpu-load is cached for up to 5 seconds (else (list #f 0 -1) ;; bad host, don't use! )))) +;;====================================================================== ;; see defstruct host at top of file. ;; host: reachable last-update last-used last-cpuload ;; (define (common:update-host-loads-table hosts-raw) (let* ((hosts (filter (lambda (x) @@ -179,10 +183,11 @@ (host-reachable-set! rec is-reachable) (host-last-update-set! rec last-reached-time) (host-last-cpuload-set! rec load))) hosts))) +;;====================================================================== ;; hash-table tree to html list tree ;; ;; tipfunc takes two parameters: y the tip value and path the path to that point ;; (define (common:htree->html ht path tipfunc) @@ -204,10 +209,11 @@ (list levelname (common:htree->html y newpath tipfunc)))))) datlist))))) +;;====================================================================== ;; logic for getting homehost. Returns (host . at-home) ;; IF *toppath* is not set, wait up to five seconds trying every two seconds ;; (this is to accomodate the watchdog) ;; (define (common:get-homehost #!key (trynum 5)) @@ -262,10 +268,11 @@ (equal? homehost bestadrs)))) (set! *home-host* (cons homehost at-home)) (mutex-unlock! *homehost-mutex*) *home-host*)))) +;;====================================================================== ;; am I on the homehost? ;; (define (common:on-homehost?) (let ((hh (common:get-homehost))) (if hh @@ -274,10 +281,11 @@ ;;====================================================================== ;; D A S H B O A R D U S E R V I E W S ;;====================================================================== +;;====================================================================== ;; first read ~/views.config if it exists, then read $MTRAH/views.config if it exists ;; (define (common:load-views-config) (let* ((view-cfgdat (make-hash-table)) (home-cfgfile (conc (get-environment-variable "HOME") "/.mtviews.config")) @@ -292,10 +300,11 @@ ;;====================================================================== ;; T A R G E T S , S T A T E , S T A T U S , ;; R U N N A M E A N D T E S T P A T T ;;====================================================================== +;;====================================================================== ;; (map print (map car (hash-table->alist (read-config "runconfigs.config" #f #t)))) ;; (define (common:get-runconfig-targets #!key (configf #f)) (let ((targs (sort (map car (hash-table->alist (or configf ;; NOTE: There is no value in using runconfig:read here. @@ -308,10 +317,11 @@ (filter (lambda (x) (patt-list-match x target-patt)) targs) targs))) +;;====================================================================== ;; Lookup a value in runconfigs based on -reqtarg or -target ;; (define (runconfigs-get config var) (let ((targ (common:args-get-target))) ;; (or (args:get-arg "-reqtarg")(args:get-arg "-target")(getenv "MT_TARGET")))) (if targ @@ -416,10 +426,11 @@ ) ) 0) +;;====================================================================== ;; TODO: for multiple areas, we will have multiple watchdogs; and multiple threads to manage (define (common:watchdog) (debug:print-info 13 *default-log-port* "common:watchdog entered.") (if (launch:setup) (if (common:on-homehost?) @@ -482,10 +493,11 @@ (debug:print-error 0 *default-log-port* "Invalid target, spaces or blanks not allowed \"" target "\", target should be: " (string-intersperse keys "/") ", have " tlist " for elements") (if exit-if-bad (exit 1)) #f) #f)))) +;;====================================================================== ;; do we honor the caches of the config files? ;; (define (common:use-cache?) (let ((res #t)) ;; priority by order of evaluation (if *configdat* ;; sillyness here. can't use setup/use-cache to know if we can use the cached files! @@ -498,11 +510,12 @@ (if (equal? (getenv "MT_USE_CACHE") "yes") (set! res #t) (if (equal? (getenv "MT_USE_CACHE") "no") (set! res #f)))) ;; overrides -no-cache switch res)) - + +;;====================================================================== ;; force use of server? ;; (define (common:force-server?) (let* ((force-setting (configf:lookup *configdat* "server" "force")) (force-type (if force-setting (string->symbol force-setting) #f)) @@ -537,10 +550,11 @@ (not (get-environment-variable "MT_DEBUG_MODE")))) (setenv "MT_DEBUG_MODE" (if (list? (verbosity)) (string-intersperse (map conc (verbosity)) ",") (conc (verbosity))))))) +;;====================================================================== ;; go through the hosts from least recently used to most recently used, pick the first that meets the load criteral from the ;; [host-rules] section. ;; (define (common:get-least-loaded-host hosts-raw host-type configdat) (let* ((rdat (configf:lookup configdat "host-rules" host-type)) @@ -602,17 +616,18 @@ (debug:print 0 *default-log-port* "INFO: Found host: " new-best " load: " load " last-used: " delta " seconds ago, with job-rate: " job-rate) (host-last-used-set! rec curr-time) new-best) (if (null? tal) #f (loop (car tal)(cdr tal) best-host))))))))) +;;====================================================================== ;; '(print (string-intersperse (map cadr (hash-table-ref/default (read-config "megatest.config" \#f \#t) "disks" '"'"'("none" ""))) "\n"))' (define (common:get-disks #!key (configf #f)) (hash-table-ref/default (or configf (read-config "megatest.config" #f #t)) "disks" '("none" ""))) - +;;====================================================================== ;; currently the primary job of the watchdog is to run the sync back to megatest.db from the db in /tmp ;; if we are on the homehost and we are a server (by definition we are on the homehost if we are a server) ;; (define (common:readonly-watchdog dbstruct) (thread-sleep! 0.05) ;; delay for startup @@ -640,11 +655,11 @@ (debug:print-info 13 *default-log-port* "rosync called, " res " records transferred.")))) (loop (current-seconds))) #t))) (debug:print-info 0 *default-log-port* "Exiting readonly-watchdog timer, *time-to-exit* = " *time-to-exit*" pid="(current-process-id)" mtpath="golden-mtpath))) - +;;====================================================================== ;; Force a megatest cleanup-db if version is changed and skip-version-check not specified ;; Do NOT check if not on homehost! ;; (define (common:exit-on-version-changed) (if (common:on-homehost?) @@ -683,15 +698,16 @@ (debug:print 0 *default-log-port* " You have read-only access to this area. Cannot proceed with megatest version migration.") (exit 1)) (else (debug:print 0 *default-log-port* " to switch versions you can run: \"megatest -cleanup-db\"") (exit 1))))))) +;;====================================================================== ;; (begin ;; (debug:print 0 *default-log-port* "ERROR: cannot migrate version unless on homehost. Exiting.") ;; (exit 1)))) - +;;====================================================================== ;; Rotate logs, logic: ;; if > 500k and older than 1 week: ;; remove previous compressed log and compress this log ;; WARNING: This proc operates assuming that it is in the directory above the ;; logs directory you wish to log-rotate. @@ -773,10 +789,11 @@ (debug:print-error 0 *default-log-port* "failed to remove " fullname ", exn=" exn) (delete-file* fullname))))) files) (debug:print-info 0 *default-log-port* "Deleted " (length files) " files from logs, keeping " max-allowed " files.")))))) +;;====================================================================== ;; calculate a delay number based on a droop curve ;; inputs are: ;; - load-in, load as from uptime, NOT normalized ;; - numcpus, number of cpus, ideally use the real cpus, not threads ;; @@ -808,10 +825,11 @@ (let loop ((x 0)) (print x "," (common:get-delay x 1)) (if (< x 2) (loop (+ x 0.1))))) +;;====================================================================== ;; DO NOT CALL THIS DIRECTLY. It is called from common:wait-for-normalized-load ;; count - count down to zero, at some point we'd give up if the load never drops ;; num-tries - count down to zero number tries to get numcpus ;; (define (common:wait-for-cpuload maxnormload numcpus-in @@ -883,10 +901,11 @@ (debug:print 0 *default-log-port* "Load on " effective-host " is acceptable at effective normalized load of " normalized-effective-load " continuing.")) (debug:print 0 *default-log-port* "Load on " effective-host ", " first" could not be retrieved. Giving up and continuing.")))))) +;;====================================================================== ;; wait for normalized cpu load to drop below maxload ;; (define (common:wait-for-normalized-load maxnormload msg remote-host #!optional (rem-tries 5)) (let ((num-cpus (common:get-num-cpus remote-host))) (if num-cpus @@ -895,10 +914,11 @@ (thread-sleep! (random 60)) ;; we failed to get num cpus. wait a bit and try again (if (> rem-tries 0) (common:wait-for-normalized-load maxnormload msg remote-host (- rem-tries 1)) #f))))) +;;====================================================================== ;; given path get free space, allows override in [setup] ;; with free-space-script /path/to/some/script.sh ;; (define (get-df path) (if (configf:lookup *configdat* "setup" "free-space-script") @@ -916,11 +936,10 @@ 0))) (list (> dbspace required) dbspace required dirpath))) - (define (get-free-inodes path) (if (configf:lookup *configdat* "setup" "free-inodes-script") (with-input-from-pipe (conc (configf:lookup *configdat* "setup" "free-inodes-script") " " path) @@ -1033,10 +1052,11 @@ (let* ((pdb (open-queue-db pdbpath "pkts.db" schema: '("CREATE TABLE groups (id INTEGER PRIMARY KEY,groupname TEXT, CONSTRAINT group_constraint UNIQUE (groupname));")))) (proc pktsdirs pktsdir pdb) (dbi:close pdb)))))) +;;====================================================================== ;; check space in dbdir and in megatest dir ;; returns: ok/not dbspace required-space ;; (define (common:check-db-dir-space) (let* ((required (string->number @@ -1046,11 +1066,12 @@ (dbdir (common:get-db-tmp-area)) ;; (db:get-dbdir)) (tdbspace (common:check-space-in-dir dbdir required)) (mdbspace (common:check-space-in-dir *toppath* required))) (sort (list tdbspace mdbspace) (lambda (a b) (< (cadr a)(cadr b)))))) - + +;;====================================================================== ;; check available space in dbdir, exit if insufficient ;; (define (common:check-db-dir-and-exit-if-insufficient) (let* ((spacedat (car (common:check-db-dir-space))) ;; look only at worst for now (is-ok (car spacedat)) @@ -1059,11 +1080,12 @@ (dbdir (cadddr spacedat))) (if (not is-ok) (begin (debug:print-error 0 *default-log-port* "Insufficient space in " dbdir ", require " required ", have " dbspace ", exiting now.") (exit 1))))) - + +;;====================================================================== ;; paths is list of lists ((name path) ... ) ;; (define (common:get-disk-with-most-free-space disks minsize) (let* ((best #f) (bestsize 0) @@ -1116,10 +1138,11 @@ (map car disks)) (if (and best (> bestsize minsize)) best #f))) ;; #f means no disk candidate found +;;====================================================================== ;; from metadat lookup MEGATEST_VERSION ;; (define (common:get-last-run-version) ;; RADT => How does this work in send-receive function??; assume it is the value saved in some DB (rmt:get-var "MEGATEST_VERSION")) @@ -1128,10 +1151,11 @@ (define (common:get-last-run-version-number) (string->number (substring (common:get-last-run-version) 0 6))) +;;====================================================================== ;; postive number if megatest version > db version ;; negative number if megatest version < db version (define (common:version-db-delta) (- megatest-version (common:get-last-run-version-number))) @@ -1141,11 +1165,11 @@ (define (common:api-changed?) (not (equal? (substring (->string megatest-version) 0 4) (substring (conc (common:get-last-run-version)) 0 4)))) - +;;====================================================================== ;; Move me elsewhere ... ;; RADT => Why do we meed the version check here, this is called only if version misma ;; (define (common:cleanup-db dbstruct #!key (full #f)) (apply db:multi-db-sync @@ -1161,10 +1185,12 @@ ;; '()) ) (if (common:api-changed?) (common:set-last-run-version))) +;;====================================================================== +;; use to transition to area-name (define common:get-area-name common:get-testsuite-name) (define (common:load-pkts-to-db mtconf #!key (use-lt #f)) (common:with-queue-db mtconf @@ -1197,10 +1223,11 @@ ))) pkts))))) pktsdirs)) use-lt: use-lt)) +;;====================================================================== ;; use-lt is use linktree "lt" link to find pkts dir (define (common:save-pkt pktalist-in mtconf use-lt #!key (add-only #f)) ;; add-only saves the pkt only if there is a parent already (if (or add-only (hash-table-exists? *pkts-info* 'last-parent)) (let* ((parent (hash-table-ref/default *pkts-info* 'last-parent #f)) Index: commonmod.scm ================================================================== --- commonmod.scm +++ commonmod.scm @@ -73,10 +73,11 @@ (define *number-of-writes* 0) (define *number-non-write-queries* 0) (define *glob-like-match-cache* (make-hash-table)) +(define *numcpus-cache* (make-hash-table)) (define (get-full-version) (conc megatest-version "-" megatest-fossil-hash)) (define (version-signature) @@ -142,16 +143,18 @@ ;;====================================================================== ;; misc conversion, data manipulation functions ;;====================================================================== +;;====================================================================== ;; if it looks like a number -> convert it to a number, else return it ;; (define (lazy-convert inval) (let* ((as-num (if (string? inval)(string->number inval) #f))) (or as-num inval))) +;;====================================================================== ;; to '((a . 1)(b . 2)(c . "a silly thing")(d . "")) ;; (define (val->alist val #!key (convert #f)) (let ((val-list (string-split-fields ";\\s*" val #:infix))) (if val-list @@ -177,10 +180,11 @@ (let ((res (message-digest-string (md5-primitive) toppath))) (if short (substring res 0 4) res))) +;;====================================================================== ;; need generic find-record-with-var-nmatching-val ;; (define (path->area-record cfgdat path) (let* ((areadat (get-cfg-areas cfgdat)) (all (filter (lambda (x) @@ -190,10 +194,11 @@ areadat))) (if (null? all) #f (car all)))) ;; return first match +;;====================================================================== ;; given a config return an alist of alists ;; area-name => data ;; (define (get-cfg-areas cfgdat) (let ((adat (get-section cfgdat "areas"))) @@ -206,17 +211,19 @@ ;; debug stuff ;;====================================================================== (define verbosity (make-parameter '())) +;;====================================================================== ;; (define (debug:print . params) #f) ;; (define (debug:print-info . params) #f) ;; ;; (define (set-functions dbgp dbgpinfo) ;; (set! debug:print dbgp) ;; (set! debug:print-info dbgpinfo)) +;;====================================================================== ;; this was cached based on results from profiling but it turned out the profiling ;; somehow went wrong - perhaps too many processes writing to it. Leaving the caching ;; in for now but can probably take it out later. ;; (define (debug:calc-verbosity vstr arg) ;; arg is 'v (verbose) or 'q (quiet) @@ -233,10 +240,11 @@ ((eq? arg 'q) 0) ;; quiet (else 1)))) (verbosity res) res)) +;;====================================================================== ;; check verbosity, #t is ok #;(define (debug-check-verbosity verbosity vstr) (if (not (or (number? verbosity) (list? verbosity))) (begin @@ -313,10 +321,11 @@ ;;;; TODO: catch permission denied exceptions and emit appropriate warnings (common:false-on-exception (lambda () (directory-exists? path-string)) message: (conc "Unable to access path: " path-string) )) +;;====================================================================== ;; does the directory exist and do we have write access? ;; ;; returns the directory or #f ;; (define (common:directory-writable? path-string) @@ -400,15 +409,17 @@ ((4 5 6) 2) ((7 8 9) 3) ((10 11 12) 4) (else #f))) +;;====================================================================== ;; basic ISO8601 format (e.g. "2017-02-28 06:02:54") date time => Unix epoch ;; (define (common:date-time->seconds datetime) (local-time->seconds (string->time datetime "%Y-%m-%d %H:%M:%S"))) +;;====================================================================== ;; given span of seconds tstart to tend ;; find start time to mark and mark delta ;; (define (common:find-start-mark-and-mark-delta tstart tend) (let* ((deltat (- (max tend (+ tend 10)) tstart)) ;; can't handle runs of less than 4 seconds. Pad it to 10 seconds ... @@ -439,19 +450,21 @@ '(5 10 15 20 30 40 50 500)) (if values (apply values result) (values 0 day 1 0 'd)))) +;;====================================================================== ;; given x y lim return the cron expansion ;; (define (common:expand-cron-slash x y lim) (let loop ((curr x) (res `())) (if (< curr lim) (loop (+ curr y) (cons curr res)) (reverse res)))) +;;====================================================================== ;; expand a complex cron string to a list of cron strings ;; ;; x/y => x, x+y, x+2y, x+3y while x+Ny a, b ,c ;; @@ -504,12 +517,12 @@ (flatten (map common:cron-expand new-list-crons)))) ;; (map common:cron-expand (map common:cron-expand new-list-crons)))) (else (if (null? tal) cron-str (loop (car tal)(cdr tal)(car type-tal)(cdr type-tal)(append res (list hed))))))))))) - - + +;;====================================================================== ;; given a cron string and the last time event was processed return #t to run or #f to not run ;; ;; min hour dayofmonth month dayofweek ;; 0-59 0-23 1-31 1-12 0-6 ### NOTE: dayofweek does not include 7 ;; @@ -617,10 +630,11 @@ ;;====================================================================== ;; key <=> target routines ;;====================================================================== +;;====================================================================== ;; This invalidates using "/" in item names. Every key will be ;; available via args:get-arg as :keyfield. Since this only needs to ;; be called once let's use it to set the environment vars ;; ;; The setting of :keyfield in args should be turned off ASAP @@ -636,10 +650,11 @@ vals) (debug:print-error 0 *default-log-port* "wrong number of values in " target ", should match " keys)) vals) (debug:print 4 *default-log-port* "ERROR: keys:target-set-args called with no target."))) +;;====================================================================== ;; given the keys (a list of vectors or a list of keys) and a target return a keyval list ;; keyval list ( (key1 val1) (key2 val2) ...) (define (keys:target->keyval keys target) (let* ((targlist (string-split target "/")) (numkeys (length keys)) @@ -655,10 +670,11 @@ (string-join (map (lambda (key)(conc key " TEXT")) keys) ",")) +;;====================================================================== ;; (define keys:config-get-fields common:get-fields) (define (common:get-area-path-signature) (message-digest-string (md5-primitive) *toppath*)) @@ -667,10 +683,11 @@ ;;====================================================================== ;; S Y S T E M S T U F F ;;====================================================================== +;;====================================================================== ;; lazy-safe get file mod time. on any error (file not existing etc.) return 0 ;; (define (common:lazy-modification-time fpath) (handle-exceptions exn @@ -679,10 +696,11 @@ 0) (if (file-exists? fpath) (file-modification-time fpath) 0))) +;;====================================================================== ;; find timestamp of newest file associated with a sqlite db file (define (common:lazy-sqlite-db-modification-time fpath) (let* ((glob-list (handle-exceptions exn (begin @@ -695,10 +713,11 @@ (apply max (map common:lazy-modification-time file-list)))) +;;====================================================================== ;; execute thunk, return value. If exception thrown, trap exception, return #f, and emit nonfatal condition note to *default-log-port* . ;; arguments - thunk, message (define (common:fail-safe thunk warning-message-on-exception) (handle-exceptions exn @@ -729,10 +748,11 @@ (define home (getenv "HOME")) (define user (getenv "USER")) +;;====================================================================== ;; returns list of fd count, socket count (define (get-file-descriptor-count #!key (pid (current-process-id ))) (list (length (glob (conc "/proc/" pid "/fd/*"))) (length (filter identity (map socket? (glob (conc "/proc/" pid "/fd/*"))))) @@ -739,10 +759,11 @@ ) ) +;;====================================================================== ;; GLOBALS ;; CONTEXTS (defstruct cxt (taskdb #f) @@ -762,10 +783,11 @@ ;; (mutex-lock! cxt-mutex) ;; (let ((res (proc cxt))) ;; (mutex-unlock! cxt-mutex) ;; res)))) +;;====================================================================== ;; A hash table that can be accessed by #{scheme ...} calls in ;; config files. Allows communicating between confgs ;; (define *user-hash-data* (make-hash-table)) @@ -846,10 +868,29 @@ (define *homehost-mutex* (make-mutex)) ;; Miscellaneous (define *triggers-mutex* (make-mutex)) ;; block overlapping processing of triggers +(define *host-loads* (make-hash-table)) + +;;====================================================================== +;; cache environment vars for each run here +(define *env-vars-by-run-id* (make-hash-table)) + +;;====================================================================== +;; Testconfig and runconfig caches. +(define *testconfigs* (make-hash-table)) ;; test-name => testconfig +(define *runconfigs* (make-hash-table)) ;; target => runconfig + +;; This is a cache of pre-reqs met, don't re-calc in cases where called with same params less than +;; five seconds ago +(define *pre-reqs-met-cache* (make-hash-table)) + +;; cache of verbosity given string +;; +(define *verbosity-cache* (make-hash-table)) + (use posix-extras pathname-expand files) ;; this plugs a hole in posix-extras in recent chicken versions > 4.9) (let-values (( (chicken-release-number chicken-major-version) (apply values @@ -873,14 +914,18 @@ (string-match "^-(s|ss|sx|script)$" (cadr argv))) (caddr argv)) (else (car argv)))) (fullpath (realpath this-script))) fullpath)) + +;;====================================================================== + (define *common:this-exe-fullpath* (common:get-this-exe-fullpath)) (define *common:this-exe-dir* (pathname-directory *common:this-exe-fullpath*)) (define *common:this-exe-name* (pathname-strip-directory *common:this-exe-fullpath*)) +;;====================================================================== ;; when called from a wrapper I need sometimes to find the calling ;; wrapper, this is for dashboard to find the correct megatest. ;; (define (common:find-local-megatest #!optional (progname "megatest")) (let ((res (filter file-exists? @@ -942,27 +987,10 @@ (else "FAIL"))) (define (common:logpro-exit-code->test-status exit-code) (status-sym->string (common:logpro-exit-code->status-sym exit-code))) -(define *host-loads* (make-hash-table)) - -;; cache environment vars for each run here -(define *env-vars-by-run-id* (make-hash-table)) - -;; Testconfig and runconfig caches. -(define *testconfigs* (make-hash-table)) ;; test-name => testconfig -(define *runconfigs* (make-hash-table)) ;; target => runconfig - -;; This is a cache of pre-reqs met, don't re-calc in cases where called with same params less than -;; five seconds ago -(define *pre-reqs-met-cache* (make-hash-table)) - -;; cache of verbosity given string -;; -(define *verbosity-cache* (make-hash-table)) - (define (common:clear-caches) (set! *target* (make-hash-table)) (set! *keys* (make-hash-table)) (set! *keyvals* (make-hash-table)) (set! *toptest-paths* (make-hash-table)) @@ -1090,10 +1118,11 @@ ;;====================================================================== ;; L O C K E R S A N D B L O C K E R S ;;====================================================================== +;;====================================================================== ;; block further accesses to databases. Call this before shutting db down (define (common:db-block-further-queries) (mutex-lock! *db-access-mutex*) (set! *db-access-allowed* #f) (mutex-unlock! *db-access-mutex*)) @@ -1107,10 +1136,11 @@ ;;====================================================================== ;; File locking ;;====================================================================== +;;====================================================================== ;; dot-locking egg seems not to work, using this for now ;; if lock is older than expire-time then remove it and try again ;; to get the lock ;; (define (common:simple-file-lock fname #!key (expire-time 300)) @@ -1156,10 +1186,11 @@ ;;====================================================================== ;; U S E F U L S T U F F ;;====================================================================== +;;====================================================================== ;; convert things to an alist or assoc list, #f gets converted to "" ;; (define (common:to-alist dat) (cond ((list? dat) (map common:to-alist dat)) @@ -1284,10 +1315,11 @@ (lambda (a b) (let ((a-num (cadr (or (assoc a items-order) '(0 0)))) (b-num (cadr (or (assoc b items-order) '(0 0))))) (acomp a-num b-num)))))) +;;====================================================================== ;; ;; given a toplevel with currstate, currstatus apply state and status ;; ;; => (newstate . newstatus) ;; (define (common:apply-state-status currstate currstatus state status) ;; (let* ((cstate (string->symbol (string-downcase currstate))) ;; (cstatus (string->symbol (string-downcase currstatus))) @@ -1348,10 +1380,11 @@ (define (assoc/default key lst . default) (let ((res (assoc key lst))) (if res (cadr res)(if (null? default) #f (car default))))) +;;====================================================================== ;; safe getting of toppath (define (common:get-toppath areapath) (or *toppath* (if areapath (begin @@ -1418,10 +1451,11 @@ ;;====================================================================== ;; M I S C U T I L S ;;====================================================================== +;;====================================================================== ;; convert stuff to a number if possible (define (any->number val) (cond ((number? val) val) ((string? val) (string->number val)) @@ -1444,10 +1478,11 @@ (set! res #t)))) (string-split patts ",")) res) #t)) +;;====================================================================== ;; return first command that exists, else #f ;; (define (common:which cmds) (if (null? cmds) #f @@ -1470,10 +1505,11 @@ (pathname-directory (pathname-directory (pathname-directory exe-path)))) #f))) +;;====================================================================== ;; return first path that can be created or already exists and is writable ;; (define (common:get-create-writeable-dir dirs) (if (null? dirs) #f @@ -1494,10 +1530,11 @@ res (if (null? tal) #f (loop (car tal)(cdr tal)))))))) +;;====================================================================== ;; return the youngest timestamp . filename ;; (define (common:get-youngest glob-list) (let ((all-files (apply append (map (lambda (patt) @@ -1516,10 +1553,11 @@ (list curmod fname) res))) '(0 "n/a") all-files))) +;;====================================================================== ;; use bash to expand a glob. Does NOT handle paths with spaces! ;; (define (common:bash-glob instr) (string-split (with-input-from-pipe @@ -1528,10 +1566,11 @@ ;;====================================================================== ;; Some safety net stuff ;;====================================================================== +;;====================================================================== ;; return input if it is a list or return null (define (common:list-or-null inlst #!key (ovrd #f)(message #f)) (if (list? inlst) inlst (begin @@ -1540,10 +1579,11 @@ (define (common:get-fields cfgdat) (let ((fields (hash-table-ref/default cfgdat "fields" '()))) (map car fields))) +;;====================================================================== ;; looking only (at least for now) at the MT_ variables craft the full testname ;; (define (common:get-full-test-name) (if (getenv "MT_TEST_NAME") (if (and (getenv "MT_ITEMPATH") @@ -1554,10 +1594,11 @@ ;;====================================================================== ;; M I S C L I S T S ;;====================================================================== +;;====================================================================== ;; items in lista are matched value and position in listb ;; return the remaining items in listb or #f ;; (define (common:list-is-sublist lista listb) (if (null? lista) @@ -1576,10 +1617,11 @@ (car talb) (cdr talb))) #f))))) +;;====================================================================== ;; Needed for long lists to be sorted where (apply max ... ) dies ;; (define (common:max inlst) (let loop ((max-val (car inlst)) (hed (car inlst)) @@ -1598,10 +1640,11 @@ (fold (lambda (a b) (if (comp a b) a b)) (car lst) lst))) +;;====================================================================== ;; get min or max, use > for max and < for min, this works around the limits on apply ;; (define (common:sum lst) (if (null? lst) 0 @@ -1608,10 +1651,11 @@ (fold (lambda (a b) (+ a b)) (car lst) lst))) +;;====================================================================== ;; path list to hash-table tree ;; ((a b c)(a b d)(e b c)) => ((a (b (d) (c))) (e (b (c)))) ;; (define (common:list->htree lst) (let ((resh (make-hash-table))) @@ -1629,10 +1673,11 @@ (hash-table-set! ht hed (make-hash-table)) (loop ht hed tal))))) lst) resh)) +;;====================================================================== ;; hash-table tree to alist tree ;; (define (common:htree->atree ht) (map (lambda (x) (cons (car x) @@ -1644,10 +1689,11 @@ ;;====================================================================== ;; M U N G E D A T A I N T O N I C E F O R M S ;;====================================================================== +;;====================================================================== ;; Generate an index for a sparse list of key values ;; ( (rowname1 colname1 val1)(rowname2 colname2 val2) ) ;; ;; => ;; @@ -1683,16 +1729,18 @@ new-colnames (if (> curr-rownum rownum) curr-rownum rownum) (if (> curr-colnum colnum) curr-colnum colnum) )))))) +;;====================================================================== ;; if it looks like a number -> convert it to a number, else return it ;; (define (common:lazy-convert inval) (let* ((as-num (if (string? inval)(string->number inval) #f))) (or as-num inval))) +;;====================================================================== ;; convert string a=1; b=2; c=a silly thing; d= ;; to '((a . 1)(b . 2)(c . "a silly thing")(d . "")) ;; (define (common:val->alist val #!key (convert #f)) (let ((val-list (string-split-fields ";\\s*" val #:infix))) @@ -1733,10 +1781,11 @@ (with-input-from-pipe (conc "/bin/readlink -f " path) (lambda () (read-line))))) +;;====================================================================== ;; returns *effective load* (not normalized) ;; (define (common:get-intercept onemin fivemin) (if (< onemin fivemin) ;; load is decreasing, just use the onemin load onemin @@ -1744,10 +1793,12 @@ (tchange (- 300 60))) (max (+ onemin (* 60 (/ load-change tchange))) 0)))) (define (get-cpu-load #!key (remote-host #f)) (car (common:get-cpu-load remote-host))) + +;;====================================================================== ;; (let* ((load-res (process:cmd-run->list "uptime")) ;; (load-rx (regexp "load average:\\s+(\\d+)")) ;; (cpu-load #f)) ;; (for-each (lambda (l) ;; (let ((match (string-search load-rx l))) @@ -1756,10 +1807,11 @@ ;; (if (number? newval) ;; (set! cpu-load newval)))))) ;; (car load-res)) ;; cpu-load)) +;;====================================================================== ;; get values from cached info from dropping file in logs dir ;; e.g. key is host and dtype is normalized-load ;; (define (common:get-cached-info key dtype #!key (age 10)) (if *toppath* @@ -1824,10 +1876,11 @@ #f) ;; more specific handling of errors needed (with-input-from-pipe (conc "ssh " remote-host " cat /proc/loadavg") (lambda ()(list (read)(read)(read)))))) +;;====================================================================== ;; get cpu load by reading from /proc/loadavg, return all three values ;; (define (common:get-cpu-load remote-host) (handle-exceptions exn @@ -1854,10 +1907,11 @@ (common:write-cached-info actual-hostname "cpu-load" result) result) '(-1 -1 -1))) ;; -1 is bad result (else '(-2 -2 -2)))))))) +;;====================================================================== ;; get normalized cpu load by reading from /proc/loadavg and /proc/cpuinfo return all three values and the number of real cpus and the number of threads ;; returns alist '((adj-cpu-load . normalized-proc-load) ... etc. ;; keys: adj-proc-load, adj-core-load, 1m-load, 5m-load, 15m-load ;; (define (common:get-normalized-cpu-load remote-host) @@ -1937,11 +1991,10 @@ (define (common:unix-ping hostname) (let ((res (system (conc "ping -c 1 " hostname " > /dev/null")))) (eq? res 0))) -(define *numcpus-cache* (make-hash-table)) (define (common:get-num-cpus remote-host) (let* ((actual-host (or remote-host (get-host-name)))) ;; hosts had better not be changing the number of cpus too often! (or (hash-table-ref/default *numcpus-cache* actual-host #f) (let* ((numcpus (or (common:get-cached-info actual-host "num-cpus" age: (+ 2592000 (random 3600))) @@ -1966,10 +2019,11 @@ (common:write-cached-info actual-host "num-cpus" result)) result)))) (hash-table-set! *numcpus-cache* actual-host numcpus) numcpus)))) +;;====================================================================== ;; DO NOT CALL THIS DIRECTLY. It is called from common:wait-for-normalized-load ;; ;; (define (common:wait-for-cpuload maxload-in numcpus-in waitdelay #!key (count 1000) (msg #f)(remote-host #f)(force-maxload #f)(num-tries 5)) ;; (let* ((loadavg (common:get-cpu-load remote-host)) ;; (numcpus (if (<= 1 numcpus-in) ;; not possible to have zero. If we get 1, it's possible that we got the previous default, and we should check again @@ -2058,10 +2112,11 @@ (uname #f)) (if (null? (car uname-res)) "unknown" (caar uname-res)))) +;;====================================================================== ;; for reasons I don't understand multiple calls to real-path in parallel threads ;; must be protected by mutexes ;; (define (common:real-path inpath) ;; (process:cmd-run-with-stderr->list "readlink" "-f" inpath)) ;; cmd . params) @@ -2113,10 +2168,11 @@ (if (number? newval) (set! freenodes newval)))))) (car df-results)) freenodes)) +;;====================================================================== ;; convert a spec string to a list of vectors #( rx action rx-string ) (define (common:spec-string->list-of-specs spec-string actions) (let ((spec-strings (string-split-fields "\\s*;\\s*" spec-string #:infix)) (actions-regex (regexp (conc "^(.*)\\s+(" (string-intersperse (map conc actions) "|") ")")))) (filter @@ -2128,10 +2184,11 @@ (begin (debug:print 0 *default-log-port* "WARNING: Unrecognised rule \"" s "\" in clean-up specification.") #f)))) spec-strings)))) +;;====================================================================== ;; given a list of specs rx . rule and a file return the first matching rule ;; (define (common:file-find-rule fname rules) ;; rule is vector #( rx action rx-string) (let loop ((rule (car rules)) (tail (cdr rules))) @@ -2141,10 +2198,11 @@ rule ;; return the whole rule so regex can be printed etc. (if (null? tail) #f (loop (car tail)(cdr tail))))))) +;;====================================================================== ;; given a spec apply some rules to a directory ;; ;; WARNING: This function will REMOVE files - be sure your spec and path is correct! ;; ;; spec format: @@ -2258,10 +2316,11 @@ (map (lambda (x) (cons (string->symbol (conc "-" (car x))) (cdr x))) default) default))) +;;====================================================================== ;; set some env vars from an alist, return an alist with original values ;; (("VAR" "value") ...) ;; a value of #f means "unset this var" ;; (define (alist->env-vars lst) @@ -2277,11 +2336,11 @@ (unsetenv var)))) lst) res) '())) - +;;====================================================================== ;; clear vars matching pattern, run proc, set vars back ;; if proc is a string run that string as a command with ;; system. ;; (define *common:orig-env* @@ -2338,10 +2397,11 @@ ((red) "223 33 49") ((grey) "192 192 192") ((orange) "255 172 13") ((purple) "This is unfinished ..."))) +;;====================================================================== ;; (define (common:get-color-for-state-status state status) ;; (case (string->symbol state) ;; ((COMPLETED) ;; (case (string->symbol status) ;; ((PASS) "70 249 73") @@ -2386,10 +2446,11 @@ (or (hash-table-ref/default *glob-like-match-cache* key #f) (let* ((newrx (regexp str-in flag))) (hash-table-set! *glob-like-match-cache* key newrx) newrx)))) +;;====================================================================== ;; tests:glob-like-match (define (tests:glob-like-match patt str) (let* ((like (substring-index "%" patt)) (notpatt (equal? (substring-index "~" patt) 0)) (newpatt (if notpatt (substring patt 1) patt)) @@ -2398,10 +2459,11 @@ (string-substitute (regexp "\\*") ".*" newpatt #f))) (rx (tests:cache-regexp finpatt (if like #t #f))) (res (string-match rx str))) (if notpatt (not res) res))) +;;====================================================================== ;; if itempath is #f then look only at the testname part ;; (define (tests:match patterns testname itempath #!key (required '())) (if (string? patterns) (let ((patts (append (string-split patterns ",") required))) @@ -2429,10 +2491,11 @@ #t (if (null? tal) #f (loop (car tal)(cdr tal))))))))))) +;;====================================================================== ;; make a query (fieldname like 'patt1' OR fieldname (define (db:patt->like fieldname pattstr #!key (comparator " OR ")) (let ((patts (if (string? pattstr) (string-split pattstr ",") '("%")))) @@ -2442,10 +2505,11 @@ (if (null? patts) '("") patts)) comparator))) +;;====================================================================== ;; if itempath is #f then look only at the testname part ;; (define (tests:match->sqlqry patterns) (if (string? patterns) (let ((patts (string-split patterns ","))) @@ -2465,10 +2529,11 @@ (if (null? tal) (string-intersperse (append (reverse res)(list qry)) " OR ") (loop (car tal)(cdr tal)(cons qry res))))))) #f)) +;;====================================================================== ;; A routine to map itempaths using a itemmap ;; patha and pathb must be strings or this will fail ;; ;; path-b is waiting on path-a ;; @@ -2479,10 +2544,11 @@ (let ((path-b-mapped (db:multi-pattern-apply path-b itemmap))) (debug:print-info 6 *default-log-port* "ITEMMAP is " itemmap ", path: " path-b ", mapped path: " path-b-mapped) (equal? path-a path-b-mapped)) (equal? path-b path-a)))) +;;====================================================================== ;; A routine to convert test/itempath using a itemmap ;; NOTE: to process only an itempath (i.e. no prepended testname) ;; just call db:multi-pattern-apply ;; (define (db:convert-test-itempath path-in itemmap) @@ -2491,10 +2557,11 @@ (test-name (if (null? path-parts) "" (car path-parts))) (item-path (string-intersperse (if (null? path-parts) '() (cdr path-parts)) "/"))) (conc test-name "/" (db:multi-pattern-apply item-path itemmap)))) +;;====================================================================== ;; patterns are: ;; "rx1" "replacement1"\n ;; "rx2" "replacement2" ;; etc. ;; @@ -2532,10 +2599,11 @@ (define (keys->valslots keys) ;; => ?,?,? .... (string-intersperse (map (lambda (x) "?") keys) ",")) +;;====================================================================== ;; (define-inline (keys->key/field keys . additional) ;; (string-join (map (lambda (k)(conc k " TEXT")) ;; (append keys additional)) ",")) (define (item-list->path itemdat) @@ -2551,13 +2619,13 @@ (if (eq? (length output) 0) #f #t)) #t)) -;; ;;====================================================================== -;; ;; N A N O M S G C L I E N T -;; ;;====================================================================== +;;====================================================================== +;; N A N O M S G C L I E N T +;;====================================================================== ;; ;; ;; ;; (define (common:send-dboard-main-changed) ;; (let* ((dashboard-ips (mddb:get-dashboards))) @@ -2665,10 +2733,11 @@ ;;====================================================================== ;; H I E R A R C H I C A L H A S H T A B L E S ;;====================================================================== +;;====================================================================== ;; Every element including top element is a vector: ;; (define (hh:make-hh #!key (ht #f)(value #f)) (vector (or ht (make-hash-table)) value)) @@ -2677,10 +2746,11 @@ (define-inline (hh:set-ht! hh ht) (vector-set! hh 0 ht)) (define-inline (hh:get-ht hh) (vector-ref hh 0)) (define-inline (hh:set-value! hh value) (vector-set! hh 1 value)) (define-inline (hh:get-value hh value) (vector-ref hh 1)) +;;====================================================================== ;; given a hierarchial hash and some keys look up the value ... ;; (define (hh:get hh . keys) (if (null? keys) (vector-ref hh 1) ;; we have reached the end of the line, return the value sought @@ -2690,10 +2760,11 @@ (if sub-hh (apply hh:get sub-hh (cdr keys)) #f)) #f)))) +;;====================================================================== ;; given a hierarchial hash, a value and some keys, add needed hierarcy and insert the value ;; (define (hh:set! hh value . keys) (if (null? keys) (hh:set-value! hh value) ;; we have reached the end of the line, store the value @@ -2707,10 +2778,11 @@ (apply hh:set! sub-hh value (cdr keys)))) ;; call the sub-hierhash with remaining keys (begin (hh:set-ht! hh (make-hash-table)) (apply hh:set! hh value keys)))))) +;;====================================================================== ;; Manage pkts, used in servers, tests and likely other contexts so put ;; in common ;;====================================================================== (define common:pkts-spec @@ -2738,10 +2810,11 @@ (define (common:get-pkt-alists pkts) (map (lambda (x) (alist-ref 'apkt x)) ;; 'pkta pulls out the alist from the read pkt pkts)) +;;====================================================================== ;; given list of pkts (alist mode) return list of D cards as Unix epoch, sorted descending ;; also delete duplicates by target i.e. (car pkt) ;; (define (common:get-pkt-times pkts) (delete-duplicates @@ -2750,12 +2823,11 @@ `(,(alist-ref 't x) . ,(string->number (alist-ref 'D x)))) pkts) (lambda (a b)(> (cdr a)(cdr b)))) ;; sort descending (lambda (a b)(equal? (car a)(car b))))) ;; remove duplicates by target - - +;;====================================================================== ;; accept an alist or hash table containing envvar/env value pairs (value of #f causes unset) ;; execute thunk in context of environment modified as per this list ;; restore env to prior state then return value of eval'd thunk. ;; ** this is not thread safe ** (define (common:with-env-vars delta-env-alist-or-hash-table thunk) @@ -2826,10 +2898,11 @@ #t) ;; just ignore it, it might have died in the meantime so joining it will throw an exception (thread-join! thread)) ))) (hash-table-keys *common:thread-punchlist*))) +;;====================================================================== ;; (define *common:telemetry-log-state* 'startup) ;; (define *common:telemetry-log-socket* #f) ;; ;; (define (common:telemetry-log-open) ;; (if (eq? *common:telemetry-log-state* 'startup) @@ -3003,10 +3076,11 @@ (loop (let ((l (read-line fh))) (if (eof-object? l) l (proc l))) (append result (list curr))) result)))) +;;====================================================================== ;; here is an example line where the shell is sh or bash ;; "find / -print 2&>1 > findall.log" (define (run-n-wait cmdline #!key (params #f)(print-cmd #f)(run-dir #f)) (if print-cmd (debug:print 0 *default-log-port* @@ -3090,15 +3164,15 @@ (let ((nums (map string->number (string-split-fields "\\d+" inl)))) (loop (read-line) (append res nums)))))))) - ;;====================================================================== ;; stuff from tests.scm ;;====================================================================== +;;====================================================================== ;; given a list of itemmaps (testname . map), return the first match ;; (define (tests:lookup-itemmap itemmaps testname) (let ((best-matches (filter (lambda (itemmap) (tests:match (car itemmap) testname #f)) @@ -3116,10 +3190,11 @@ ;;====================================================================== ;; stuff from tasks.scm ;;====================================================================== +;;====================================================================== ;; no elegance here ... ;; (define (tasks:kill-server hostname pid #!key (kill-switch "")) (debug:print-info 0 *default-log-port* "Attempting to kill server process " pid " on host " hostname) (setenv "TARGETHOST" hostname) @@ -3139,7 +3214,7 @@ (unsetenv "TARGETHOST_LOGF") (unsetenv "TARGETHOST")))) - +;;======================================================================the end ) Index: dashboard.scm ================================================================== --- dashboard.scm +++ dashboard.scm @@ -413,10 +413,11 @@ 3))) (define (get-curr-sort) (vector-ref *tests-sort-options* *tests-sort-reverse*)) +;;====================================================================== (common:debug-setup) ;; (define uidat #f) (define-inline (dboard:uidat-get-keycol vec)(vector-ref vec 0)) Index: dbmod.scm ================================================================== --- dbmod.scm +++ dbmod.scm @@ -4630,7 +4630,8 @@ (if prev-nbfake-log (setenv "NBFAKE_LOG" prev-nbfake-log) (unsetenv "NBFAKE_LOG")) )) ;; )) +;;======================================================================the end ) Index: dcommonmod.scm ================================================================== --- dcommonmod.scm +++ dcommonmod.scm @@ -216,7 +216,7 @@ ((last-db-time 0) : number) ;; last timestamp on megatest.db ((data-changed #f) : boolean) ((run-data-offset 0) : number) ;; get only 100 items per call, set back to zero when received less than 100 items (db-path #f)) - +;;======================================================================the end ) Index: launch.scm ================================================================== --- launch.scm +++ launch.scm @@ -263,11 +263,12 @@ (when do-sync ;;(with-output-to-file (conc (getenv "MT_TEST_RUN_DIR") "/last-loadinfo.log" #:append) ;; (lambda () (pp (list (current-seconds) new-cpu-load new-disk-free (calc-minutes))))) ;; (common:telemetry-log "zombie" (conc "launch:monitor-job - dosync started at "(current-seconds))) (tests:update-central-meta-info run-id test-id new-cpu-load new-disk-free (calc-minutes) #f #f) - #;(common:telemetry-log "zombie" (conc "launch:monitor-job - dosync finished at "(current-seconds)))) + ;;(common:telemetry-log "zombie" (conc "launch:monitor-job - dosync finished at "(current-seconds))) + ) (if kill-job? (begin (debug:print-info 0 *default-log-port* "proceeding to kill test: "kill-reason) (mutex-lock! m) @@ -532,11 +533,11 @@ (lambda (varval) (let ((var (car varval)) (val (cadr varval))) (if (and (string? var)(string? val)) (begin - (safe-setenv var (config:eval-string-in-environment val))) ;; val) + (safe-setenv var (configf:eval-string-in-environment val))) ;; val) (debug:print-error 0 *default-log-port* "bad variable spec, " var "=" val)))) (configf:get-section rconfig section))) (list "default" target))) ;;(bb-check-path msg: "launch:execute post block 1") Index: ods.scm ================================================================== --- ods.scm +++ ods.scm @@ -231,7 +231,9 @@ ;; process each sheet (map print (map ods:sheet data)) (map display ods:content-footer))) (system (conc "cd " path "; zip " fname " -n mimetype mimetype `find . |grep -v mimetype` > /dev/null"))))) + +;;======================================================================the end )