nsmcp::AccessDiagnosticTool method scanStep (public)

 <instance of nsmcp::AccessDiagnosticTool[i]> scanStep context state

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

Run one bounded routing-diagnostic scan slice. Retain immutable bounds, filters, aggregation and coverage state so later slices continue the same scan.

Parameters:
context (required)
Authenticated request context carrying the principal, grants and selected server.
state (required)
Opaque retained provider continuation or scan state.
Returns:
The updated scan state and diagnostic evidence.

Testcases:
No testcase defined.
Source code:
set options [dict get $state options]
if {![dict exists $state bounds]} {
    if {![dict exists $options scanStrategy]} {
        dict set options scanStrategy window
    }
    set bounds [:scanBounds $context $options]
    dict set state bounds $bounds
    if {[dict get $bounds strategy] eq "completion-window"} {
        dict set options beforeOffset [dict get $bounds to]
        dict set options sourceBytes [dict get $bounds sourceBytes]
        dict set options sourceIdentity [dict get $bounds identity]
    }
}
set bounds [dict get $state bounds]
set aggregateTraffic [expr {[dict exists $options aggregateTraffic] && [dict get $options aggregateTraffic]}]
set traffic {}
if {$aggregateTraffic} {
    if {[dict exists $state traffic]} {
        set traffic [dict get $state traffic]
    } else {
        set traffic {sources {} agents {} authenticationStates {} requestCount 0 status503Count 0 successfulCount 0 successfulTimingCount 0 successfulRunTotal 0.0 unknownPeerCount 0 untrackedSourceRecords 0 unknownUserAgentCount 0 untrackedUserAgentRecords 0}
        dict set traffic salt [ns_crypto::randombytes -encoding hex 32]
    }
}
set page [:page $context [:argumentTriples $options] [dict get $bounds from] [expr {$aggregateTraffic ? "traffic" : ""}]]
if {$aggregateTraffic} {
    dict set state traffic $traffic
}
set value [ns_json parse [ns_json value -- $page]]
if {![dict get $value available]} {
    return [list $page {} {}]
}
if {![dict exists $state fields]} {
    dict set state fields [lindex $page 2]
    dict set state groups {}
    dict set state totals {}
    dict set state matches 0
    dict set state selected 0
    dict set state pages 0
    dict set state coverage [dict get $value coverage]
} else {
    set initial [ns_json parse [ns_json value -- [list {} object [dict get $state fields]]]]
    foreach key {sourceIdentity mappingIdentity from to lookupMode selectedCategory} {
        if {[dict get $initial $key] ne [dict get $value $key]} {
            error "Routing scan identity changed; start a new query"
        }
    }
    set coverage [dict get $state coverage]
    set nextCoverage [dict get $value coverage]
    foreach key {unrecognizedRecords oversizedRecords missingUserAgent missingPool} {
        dict incr coverage $key [dict get $nextCoverage $key]
    }
    dict set coverage pendingFinalRecord [expr {[dict get $coverage pendingFinalRecord] || [dict get $nextCoverage pendingFinalRecord]}]
    dict set coverage examinedFromOffset [dict get $nextCoverage examinedFromOffset]
    dict set coverage unreadEarlierBytes [dict get $nextCoverage unreadEarlierBytes]
    dict set state coverage $coverage
}
dict incr state pages
dict incr state matches [dict get $value matches]
dict incr state selected [dict get $value selectedMatches]
set totals [dict get $state totals]
dict for {category count} [dict get $value categoryTotals] {
    dict incr totals $category $count
}
dict set state totals $totals
set groups [dict get $state groups]
foreach record [dict get $value records] {
    set key [:aggregateKey $record]
    if {[dict exists $groups $key]} {
        set group [dict get $groups $key]
        foreach field {count timingCount} {
            dict incr group $field [dict get $record $field]
        }
        dict set group runTotal [expr {[dict get $group runTotal]+[dict get $record runTotal]}]
        dict set group runMax [expr {max([dict get $group runMax],[dict get $record runMax])}]
        dict set group firstAt [expr {min([dict get $group firstAt],[dict get $record firstAt])}]
        dict set group lastAt [expr {max([dict get $group lastAt],[dict get $record lastAt])}]
        dict set groups $key $group
    } else {
        if {[dict size $groups]>=[dict get $options limit]} {
            set worst [:evidencePriority [dict get $record category]]
            set victim {}
            dict for {otherKey otherRecord} $groups {
                set rank [:evidencePriority [dict get $otherRecord category]]
                if {$rank>$worst} {
                    set worst $rank
                    set victim $otherKey
                }
            }
            if {$victim eq ""} {
                continue
            }
            dict unset groups $victim
        }
        dict set groups $key $record
    }
}
# Bound state by the same evidence byte budget used for individual pages.
set ordered {}
dict for {key group} $groups {
    lappend ordered [list [:evidencePriority [dict get $group category]] $key $group]
}
set groups {}
set entries {}
set index 0
set bytes 0
set returned 0
set omitted {}
dict for {category count} $totals {
    if {[dict get $value selectedCategory] eq "" || [dict get $value selectedCategory] eq $category} {
        dict set omitted $category $count
    }
}
foreach pair [lsort -integer -index 0 $ordered] {
    lassign $pair priority key record
    set fields [:recordFields $record]
    set size [string bytelength [ns_json value -- [list {} object $fields]]]
    if {$bytes+$size>65536} {
        continue
    }
    incr bytes $size
    dict set groups $key $record
    lappend entries $index object $fields
    incr index
    incr returned [dict get $record count]
    dict incr omitted [dict get $record category] [expr {-[dict get $record count]}]
}
dict set state groups $groups
set counts {}
dict for {category count} $totals {
    lappend counts $category number $count
}
set omittedCounts {}
dict for {category count} $omitted {
    lappend omittedCounts $category number $count
}
set coverage [dict get $state coverage]
set coverageFields {}
foreach {key type original} [ns_json triples getvalue -output triples -path coverage -- $page] {
    lappend coverageFields $key $type [dict get $coverage $key]
}
lappend coverageFields scanStrategy string [dict get $bounds strategy] seekReason string [dict get $bounds reason]  seekMarginSeconds number 300 seekProbeBytes number [dict get $bounds probeBytes]  skippedEarlierBytes number [dict get $bounds from] skippedLaterBytes number [expr {[dict get $bounds sourceBytes]-[dict get $bounds to]}]  completionOrderAssumed boolean [expr {[dict get $bounds strategy] eq "completion-window"}]
lappend coverageFields pages number [dict get $state pages] aggregationScope string all-examined-pages  sourceFullyExamined boolean [expr {[dict get $coverage unreadEarlierBytes]==0 && [dict get $coverage examinedToOffset]==[dict get $coverage sourceBytes]}]
set fields {}
foreach {key type original} [dict get $state fields] {
    switch -- $key {
        matches {
            set original [dict get $state matches]
        }
        selectedMatches {
            set original [dict get $state selected]
        }
        filteredOutRecords {
            set original [expr {[dict get $state matches]-[dict get $state selected]}]
        }
        categoryTotals {
            set original $counts
        }
        omittedRecords {
            set original [expr {[dict get $state selected]-$returned}]
        }
        omittedCategoryTotals {
            set original $omittedCounts
        }
        records {
            set original $entries
        }
        more {
            set original false
        }
        nextArguments {
            set original {}
        }
        coverage {
            set original $coverageFields
        }
    }
    lappend fields $key $type $original
}
if {$aggregateTraffic} {
    lappend fields trafficAggregation object [:trafficTriples $traffic [expr {[dict get $options to]-[dict get $options from]}] [expr {![dict get $value more]}]]
}
lappend fields scanComplete boolean [expr {![dict get $value more]}]
set continuation {}
if {[dict get $value more]} {
    set nextOptions [dict get $value nextArguments]
    dict set nextOptions aggregateTraffic $aggregateTraffic
    dict set state options $nextOptions
    set continuation $state
}
set progress [list examinedBytes number [expr {[dict get $bounds to]-[dict get $coverage unreadEarlierBytes]}]  sourceBytes number [expr {[dict get $bounds to]-[dict get $bounds from]}]]
return [list [list {} object $fields] $continuation $progress]
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: