nsmcp::AccessAnalytics method summary (public)

 <instance of nsmcp::AccessAnalytics[i]> summary options

Defined in /usr/local/ns/tcl/nsmcp/lib/access-analytics.tcl

Use the scanner coverage and a single snapshot for all aggregates. Hold a single SQLite snapshot for coverage and all aggregate queries.

Parameters:
options (required)

Testcases:
No testcase defined.
Source code:
ns_mutex lock ${:mutex}
try {
    set :db [${:database} connect]
    set :batchRows 0
    ${:db} execute {BEGIN}
    set options [:validateWindow $options]
    :peerSchema ${:db}
    set plain $options
    foreach key {path status pool peer windowSeconds includePeerAddresses} {dict unset plain $key}
    # Coverage and counts share the same read transaction.
    set result [:summaryLocked $plain]
    set filters {}; foreach key {path status pool peer} {if {[dict exists $options $key]} {dict set filters $key [dict get $options $key]}}
    dict set result filters $filters
    set db ${:db}; set from [dict get $result from]; set to [dict get $result to]
    set where {start >= $from AND start < $to}
    foreach key {path status pool peer} {
        if {[dict exists $options $key]} {set $key [dict get $options $key]; append where " AND $key = \$$key"}
    }
    $db execute "SELECT count(*) AS requestCount,coalesce(sum(bytes),0) AS responseBytes,
        coalesce(sum(fallback),0) AS fallbackCount,coalesce(sum(excluded),0) AS excludedPaths,
        count(run) AS timingCount,coalesce(sum(accept),0) AS acceptTotal,
        coalesce(sum(queue),0) AS queueTotal,coalesce(sum(filter),0) AS filterTotal,
        coalesce(sum(run),0) AS runTotal,coalesce(max(run),0) AS runMax FROM nsmcp_access_requests WHERE $where" row {
        foreach key $row(*) {dict set result $key $row($key)}
    }
    foreach {dimension column} {pools pool methods method statuses status paths path} {
        set counts {}
        # Bounded output, but count all matching rows in totals above.
        $db execute "SELECT $column AS label,count(*) AS n FROM nsmcp_access_requests WHERE $where GROUP BY $column ORDER BY n DESC LIMIT 1000" row {
            if {$dimension eq "paths" && $row(label) eq ""} continue
            dict set counts $row(label) $row(n)
        }
        dict set result $dimension $counts
    }
    set tracked 0
    dict for {label count} [dict get $result paths] {incr tracked $count}
    dict set result excludedPaths [expr {[dict get $result requestCount]-$tracked}]
    set statusTimings {}
    $db execute "SELECT status,count(*) AS n,count(run) AS timed,coalesce(sum(filter),0) AS filters,
        coalesce(sum(run),0) AS runs,coalesce(max(run),0) AS maximum FROM nsmcp_access_requests WHERE $where GROUP BY status" row {
        lappend statusTimings [dict create status $row(status) requestCount $row(n) timingCount $row(timed) filterTotal $row(filters) runTotal $row(runs) runMax $row(maximum)]
    }
    dict set result statusTimings $statusTimings
    set unknownPeers [$db scalar "SELECT count(*) FROM nsmcp_access_requests WHERE $where AND peer = ''"]
    dict set result coverage unknownPeerCount $unknownPeers
    dict set result coverage peerCountsComplete [expr {$unknownPeers==0 && [dict get $result coverage windowComplete]}]
    if {[dict exists $options windowSeconds]} {
        # RANGE counts all equal timestamps together and uses an inclusive
        # [end-windowSeconds,end] range clipped to the selected period.
        # SQLite performs the rolling calculation rather than Tcl fetching rows.
        set seconds [dict get $options windowSeconds]
        set burst [dict create windowSeconds $seconds requestCount 0 from {} to {}]
        $db execute "SELECT peer,start,n FROM (
            SELECT peer,start,count(*) OVER (
                PARTITION BY peer ORDER BY start RANGE BETWEEN \$seconds PRECEDING AND CURRENT ROW) AS n
            FROM nsmcp_access_requests WHERE $where AND peer != ''
        ) ORDER BY n DESC,start,peer LIMIT 1" row {
            dict set burst requestCount $row(n)
            dict set burst from [expr {max(double($from),$row(start)-$seconds)}]
            dict set burst to $row(start)
            if {[dict exists $options includePeerAddresses] && [dict get $options includePeerAddresses]} {
                dict set burst peerAddress $row(peer)
            }
        }
        dict set result peerBurst $burst
    }
    set size [dict get $result bucketSeconds]; set counts [dict get $result buckets]
    $db execute "SELECT cast(start/\$size AS INTEGER)*\$size AS slot,count(*) AS n FROM nsmcp_access_requests WHERE $where GROUP BY slot" row {
        dict set counts $row(slot) $row(n)
    }
    dict set result buckets $counts
    dict set result pathCountsComplete [expr {[dict get $result excludedPaths]==0}]
    set retained [$db scalar {SELECT coalesce(min(start),'') FROM nsmcp_access_requests}]
    set through [$db scalar {SELECT value FROM nsmcp_access_metadata WHERE key='droppedThrough'}]
    set evictionAt [$db scalar {SELECT value FROM nsmcp_access_metadata WHERE key='lastEvictionAt'}]
    dict set result coverage source ${:path}
    dict set result coverage retainedRequestFrom $retained
    dict set result coverage droppedThrough $through
    dict set result coverage lastEvictionAt $evictionAt
    set evicted [expr {$through ne "" && $from <= $through}]
    dict set result coverage evictionOverlap $evicted
    if {$evicted} {dict set result coverage windowComplete false; set reasons [dict get $result coverage incompleteReasons]; lappend reasons eviction; dict set result coverage incompleteReasons $reasons}
    dict set result coverage peerCountsComplete [expr {$unknownPeers==0 && [dict get $result coverage windowComplete]}]
    dict set result coverage databaseBytes [file size [${:database} path]]
    dict set result coverage storageBudgetBytes [${:database} cget -maxBytes]
    set events {}
    $db execute {SELECT * FROM nsmcp_access_evictions ORDER BY id DESC} row {
        lappend events [dict create droppedAt $row(dropped_at) from $row(first_time) to $row(last_time) rowCount $row(rows) reason $row(reason)]
    }
    dict set result evictions $events
    ${:db} execute {COMMIT}
    return $result
} finally {if {[info exists :db]} {${:db} close; unset :db}; unset -nocomplain :batchRows; ns_mutex unlock ${:mutex}}
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: