Class ::nsmcp::AccessCardinalityStore
::nsmcp::AccessCardinalityStore
create ... \
[ -agentPending (default "0") ] \
[ -attached (default "false") ] \
[ -buffer (default "") ] \
[ -checkpoint:required checkpoint:required ] \
[ -data data ] \
[ -db (default "") ] \
[ -directory:required directory:required ] \
[ -events (default "0") ] \
[ -handle (default "") ] \
[ -limits:required limits:required ] \
[ -peerPending (default "0") ] \
[ -readResults:boolean (default "false") ]
Defined in /usr/local/ns/tcl/nsmcp/log-traffic-aggregate.tclClass Relations
- class: ::nx::Class
![[i]](/resources/acs-subsite/ZoomIn16.gif)
- superclass: ::nx::Object
![[i]](/resources/acs-subsite/ZoomIn16.gif)
::nx::Class create ::nsmcp::AccessCardinalityStore \
-superclass ::nx::Object
Methods (to be applied on instances)
add (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> add row redactor
- Parameters:
- row (required)
- redactor (required)
- Testcases:
-
No testcase defined.
set peer [dict get $row peerAddress]
set knownPeer [expr {$peer ni {{} - {[REDACTED]}}}]
set knownAgent [expr {[dict exists $row userAgent] && [dict get $row userAgent] ni {{} -}}]
if {[dict get ${:data} status] ne "active"} {
if {$knownPeer} {dict incr :data peerOmitted}
if {$knownAgent} {dict incr :data agentOmitted}
return
}
if {$knownPeer} {
set key [ns_crypto::md string -digest sha256 -- $peer]
:addKey 0 $key {} 0 0
incr :peerPending
}
if {$knownAgent} {
set agent [dict get $row userAgent]
set key [ns_crypto::md string -digest sha256 -- $agent]
set label [$redactor message $agent]
set redacted [expr {$label ne $agent}]
set bytes [encoding convertto utf-8 $label]
set clipped [expr {[string length $bytes]>1024}]
if {$clipped} {
set label [encoding convertfrom utf-8 [string range $bytes 0 1023]]
while {[string length [encoding convertto utf-8 $label]]>1024} {set label [string range $label 0 end-1]}
dict incr :data labelTruncatedRecords
}
if {$redacted} {dict incr :data labelRedactedRecords}
:addKey 1 $key $label $clipped $redacted
incr :agentPending
}
incr :events
if {${:events}>=512} {:flush}close (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> close
- Testcases:
-
No testcase defined.
:destroy
flush (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> flush
- Testcases:
-
No testcase defined.
if {${:events}==0} {return}
if {${:buffer} ne "" && ${:db} ne "" && [dict get ${:data} status] eq "active"} {
set values {}
dict for {id row} ${:buffer} {
lappend values "([dict get $row kind],[${:db} quote [dict get $row k]],[${:db} quote [dict get $row label]],[dict get $row clipped],[dict get $row redacted],[dict get $row n])"
}
try {
ns_db dml ${:handle} BEGIN
ns_db dml ${:handle} "INSERT INTO nsmcp_access_aggregate.counts VALUES [join $values ,] ON CONFLICT(kind,k) DO UPDATE SET n=n+excluded.n"
if {[:diskBytes]>[dict get ${:data} maxBytes]} {error "aggregation-disk-limit"}
ns_db dml ${:handle} COMMIT
} on error {message options} {
set exception [ns_db exception ${:handle}]
set disk [expr {$message eq "aggregation-disk-limit" || [string match -nocase {*full*} $exception]}]
:fail write-batch [expr {$disk ? "aggregation-disk-limit" : "sqlite-write-failed"}] $message $options [expr {$disk ? "limited" : "unavailable"}]
:disconnect true
dict incr :data peerOmitted ${:peerPending}
dict incr :data agentOmitted ${:agentPending}
}
}
set :buffer {}; set :events 0; set :peerPending 0; set :agentPending 0
dict set :data diskBytes [:diskBytes]readable (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> readable
- Testcases:
-
No testcase defined.
return [expr {${:db} ne {}}]results (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> results limit \
expectedPeers expectedAgents
- Parameters:
- limit (required)
- expectedPeers (required)
- expectedAgents (required)
- Testcases:
-
No testcase defined.
:flush
set result [dict create backend sqlite status [dict get ${:data} status] reason [dict get ${:data} reason] maxBytes [dict get ${:data} maxBytes] diskBytes [:diskBytes] peakBufferedKeys [expr {[dict exists ${:data} peakBufferedKeys] ? [dict get ${:data} peakBufferedKeys] : 0}] peerOmitted [dict get ${:data} peerOmitted] agentOmitted [dict get ${:data} agentOmitted] labelTruncatedRecords [dict get ${:data} labelTruncatedRecords] labelRedactedRecords [dict get ${:data} labelRedactedRecords]]
foreach key {failure poolWaitCount poolWaitMilliseconds poolWaitLimitMilliseconds} {dict set result $key [dict get ${:data} $key]}
foreach {field kind} {peers 0 agents 1} {
set rows {}; set totals [dict create distinct 0 records 0 top1 0 top10 0 top100 0 rankedRecords 0 clippedRecords 0 redactedRecords 0]
if {${:db} ne "" && [catch {
${:db} execute "SELECT count(*) AS distinctCount,coalesce(sum(n),0) AS records,coalesce(sum(n*clipped),0) AS clippedRecords,coalesce(sum(n*redacted),0) AS redactedRecords FROM nsmcp_access_aggregate.counts WHERE kind=$kind" r {
dict set totals distinct $r(distinctCount); dict set totals records $r(records)
dict set totals clippedRecords $r(clippedRecords); dict set totals redactedRecords $r(redactedRecords)
}
set i 0
${:db} execute "SELECT label,clipped,redacted,n FROM nsmcp_access_aggregate.counts WHERE kind=$kind ORDER BY n DESC,k LIMIT 100" r {
incr i
if {$i==1} {dict set totals top1 $r(n)}
if {$i<=10} {dict incr totals top10 $r(n)}
dict incr totals top100 $r(n)
if {$i<=$limit} {
dict incr totals rankedRecords $r(n)
lappend rows [dict create value $r(label) count $r(n) valueTruncated $r(clipped) valueRedacted $r(redacted)]
}
}
} readError readOptions]} {
:fail read-results sqlite-read-failed $readError $readOptions
foreach key {status reason failure} {dict set result $key [dict get ${:data} $key]}
set rows {}; set totals {distinct 0 records 0 top1 0 top10 0 top100 0 rankedRecords 0 clippedRecords 0 redactedRecords 0}
:disconnect true
}
dict set result $field $rows; dict set result ${field}Totals $totals
}
dict set result labelTruncatedRecords [dict get $result agentsTotals clippedRecords]
dict set result labelRedactedRecords [dict get $result agentsTotals redactedRecords]
if {[dict get $result peersTotals records]+[dict get $result peerOmitted]!=$expectedPeers
|| [dict get $result agentsTotals records]+[dict get $result agentOmitted]!=$expectedAgents} {
if {[dict get $result status] ne "unavailable"} {dict set result reason aggregation-count-mismatch}
dict set result status unavailable
foreach {field expected omitted} [list peers $expectedPeers peerOmitted agents $expectedAgents agentOmitted] {
dict set result $field {}; dict set result ${field}Totals {distinct 0 records 0 top1 0 top10 0 top100 0 rankedRecords 0 clippedRecords 0 redactedRecords 0}
dict set result $omitted $expected
}
}
return $resultsnapshot (scripted, public)
<instance of nsmcp::AccessCardinalityStore
> snapshot
- Testcases:
-
No testcase defined.
:flush; return ${:data}