- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::nsmcp::AccessCardinalityStore
::nsmcp::AccessCardinalityStorecreate ... \
[ -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.tcl
Class Relations
::nx::Class create ::nsmcp::AccessCardinalityStore \ -superclass ::nsmcp::ObjectMethods (to be applied on instances)
add (scripted, public)
<instance of nsmcp::AccessCardinalityStore> add row redactor
Accumulate peer and user-agent observations from a request. Apply the redactor and configured capacity limits before buffering distinct-observation updates.
- Parameters:
- row (required)
- Parsed access-request record.
- redactor (required)
- Redactor object applied before returning diagnostic evidence.
- Returns:
- The observation update result.
- 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
Release cardinality-store resources. Destroy the accumulator and allow its destructor to flush or close owned resources.
- Returns:
- The object destruction result.
- Testcases:
- No testcase defined.
:destroyflush (scripted, public)
<instance of nsmcp::AccessCardinalityStore> flush
Persist buffered cardinality observations. Write pending observations to the optional cache and retain explicit capacity or storage failure state.
- Returns:
- The flush result, or an empty result when no observations are pending.
- 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 "([ns_dbquotelist [list [dict get $row kind] [dict get $row k] [dict get $row label] [dict get $row clipped] [dict get $row redacted] [dict get $row n]]])" } try { ns_db dml ${:handle} BEGIN # Values are quoted individually. Do not cache this bounded # batch as a distinct SQL template in DatabaseSession. 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}] # Closing the native connection rolls back atomically even # when SQLite FULL has already ended the transaction. Avoid a # speculative ROLLBACK that logs a second spurious error. 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
Report whether the cardinality cache owns a readable database session. This is a current-state check, not a new pool checkout.
- Returns:
- True when a database session is present, otherwise false.
- Testcases:
- No testcase defined.
return [expr {${:db} ne {}}]results (scripted, public)
<instance of nsmcp::AccessCardinalityStore> results limit \ expectedPeers expectedAgents
Build bounded peer and agent cardinality evidence. Flush observations and compare observed diversity with expected counts to report lower bounds and omissions.
- Parameters:
- limit (required)
- Maximum number of records or entries to return.
- expectedPeers (required)
- Expected peer observation count used to assess completeness.
- expectedAgents (required)
- Expected user-agent observation count used to assess completeness.
- Returns:
- The cardinality result dictionary.
- 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 [:dict getdef ${: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 -arrayName r -script { dict set totals distinct $r(distinctCount) dict set totals records $r(records) dict set totals clippedRecords $r(clippedRecords) dict set totals redactedRecords $r(redactedRecords) } "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" set i 0 ${:db} execute -arrayName r -script { 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)] } } "SELECT label,clipped,redacted,n FROM nsmcp_access_aggregate.counts WHERE kind=$kind ORDER BY n DESC,k LIMIT 100" } 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
Return current cardinality accumulator state. Flush pending observations before reading the stored counters and completeness flags.
- Returns:
- The cardinality state dictionary.
- Testcases:
- No testcase defined.
:flush return ${:data}
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
![[i]](/resources/acs-subsite/ZoomIn16.gif)