nsmcp::ServerHistory method compactHistory (protected)

 <instance of nsmcp::ServerHistory[i]> compactHistory context \
    options

Defined in /usr/local/ns/tcl/nsmcp/stats-tools.tcl

Bounded paging stays inside the server: raw topology/sample payloads are never sent to the model in summary mode. Each call covers at most 1000 samples; continuation explicitly describes the remaining window.

Parameters:
context (required)
options (required)

Testcases:
No testcase defined.
Source code:
set from [dict get $options from]; set to [dict get $options to]
set cursor [dict get $options cursor]; set initialCursor $cursor
set metrics {}; set samples 0; set unusable 0; set boundary 0
set omitted 0; set pages 0
for {set page 0} {$page < 10} {incr page} {
    set h [${:command} history query -server [$context server] -from $from -to $to -limit 100 -cursor $cursor]
    incr pages
    foreach record [dict get $h records] {
        incr samples
        set usable true
        foreach key {ready from to elapsedSeconds} {
            if {![dict exists $record sampling $key] || [dict get $record sampling $key] eq ""} {set usable false}
        }
        if {!$usable || ![dict get $record sampling ready]
            || ([dict exists $record sampling reset] && [dict get $record sampling reset])
            || [dict get $record sampling elapsedSeconds] <= 0} {incr unusable; continue}
        set a [dict get $record sampling from]; set b [dict get $record sampling to]
        if {$a < $from || $b > $to} {incr boundary}
        set groups {}
        if {[dict exists $record servers [$context server] pools]} {
            set totalRate 0.0; set totalKnown true; set poolCount 0
            dict for {pool entry} [dict get $record servers [$context server] pools] {
                incr poolCount
                if {![dict exists $entry rates requests] || ![string is double -strict [dict get $entry rates requests]]
                    || [catch {expr {abs([dict get $entry rates requests]) < 1e300}} finite] || !$finite} {
                    set totalKnown false
                } else {set totalRate [expr {$totalRate+[dict get $entry rates requests]}]}
                # Never summarize cumulative counters as interval work.
                foreach kind {rates gauges timingAverageSeconds} {
                    if {[dict exists $entry $kind]} {lappend groups [list [list servers [$context server] pools $pool $kind] [dict get $entry $kind]]}
                }
            }
        }
        if {[info exists poolCount] && $poolCount > 0} {
            lappend groups [list [list servers [$context server] allPools rates] [dict create requests [expr {$totalKnown ? $totalRate : ""}]]]
        }
        unset -nocomplain poolCount
        if {[dict exists $record cpuPercent groups]} {lappend groups [list {cpuPercent groups} [dict get $record cpuPercent groups]]}
        foreach group $groups {
            lassign $group prefix values
            dict for {name value} $values {
                set path [concat $prefix [list $name]]
                if {![dict exists $metrics $path]} {
                    if {[dict size $metrics] >= 128} {incr omitted; continue}
                    dict set metrics $path [dict create count 0 unknown 0 sum 0.0 min {} max {} peakFrom {} peakTo {}]
                }
                set row [dict get $metrics $path]
                # Missing and nonfinite values are unknown, never zero.
                if {![string is double -strict $value] || [catch {expr {abs($value) < 1e300}} finite] || !$finite} {
                    dict incr row unknown
                } else {
                    dict incr row count
                    dict set row sum [expr {[dict get $row sum]+$value}]
                    if {[dict get $row min] eq "" || $value < [dict get $row min]} {dict set row min $value}
                    if {[dict get $row max] eq "" || $value > [dict get $row max]} {
                        dict set row max $value; dict set row peakFrom $a; dict set row peakTo $b
                    }
                }
                dict set metrics $path $row
            }
        }
    }
    if {![dict get $h more]} break
    set next [dict get $h nextCursor]
    if {![string is entier -strict $next] || $next <= $cursor} {error "History cursor did not advance"}
    set cursor $next
}
set rows {}; set i 0
dict for {path row} $metrics {
    set fields {}; set parts {}; set j 0
    foreach part $path {lappend parts $j string $part; incr j}
    lappend fields path array $parts
    foreach key {count unknown min max peakFrom peakTo} {
        set value [dict get $row $key]
        lappend fields $key [expr {$value eq "" ? "null" : "number"}] $value
    }
    # Missing fields in other usable records are accounted separately
    # from explicit nulls; topology changes need not be parser errors.
    lappend fields absentSamples number [expr {$samples-$unusable-[dict get $row count]-[dict get $row unknown]}]
    set mean [expr {[dict get $row count] ? [dict get $row sum]/double([dict get $row count]) : ""}]
    lappend fields sampleMean [expr {$mean eq "" ? "null" : "number"}] $mean
    lappend rows $i object $fields; incr i
}
set more [dict get $h more]
set summary [list from number $from to number $to initialCursor number $initialCursor  sampleCount number $samples unusableSamples number $unusable boundaryOverlapSamples number $boundary  pagesExamined number $pages more boolean $more metrics array $rows  omittedMetricObservations number $omitted  coverage object [:encode coverage [dict get $h coverage]]  limitations string {Metrics summarize retained sampling intervals, not instantaneous or one-second peaks. Rates and timings are supplied by ns_stats; sampleMean is unweighted, not a request-weighted latency. Peak bounds may overlap the requested window. Cumulative counters are excluded. Missing, reset and not-ready samples are not zero. CPU groups remain process-wide. At most 1000 samples and 128 metric series per call; missing series can reflect topology changes. Coverage is native history coverage; more=true requires continuation before claiming the window was examined.}]
if {[dict exists $h storage]} {lappend summary storage object [:encode metrics [dict get $h storage]]}
set nextFields {}
if {$more} {set nextFields [list from number $from to number $to cursor number $cursor mode string summary]}
return [list $summary $nextFields]
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: