ns::stats::SQLiteHistory method history query (public)
<instance of ns::stats::SQLiteHistory> history query -from from \ -to to [ -server server ] [ -limit limit ] [ -cursor cursor ]
Return stored samples, associated topology, paging information and coverage for an epoch interval. Queries run in the configuring virtual server and use an operation-local database handle. Historical server selection may include servers no longer active.
- Switches:
- -from (required, integer)
- Inclusive lower bound in epoch seconds; must be nonnegative.
- -to (required, integer)
- Exclusive upper bound in epoch seconds; after from, at most 24 hours later and no later than now.
- -server (optional)
- Optional historical virtual-server name, including one no longer configured; empty returns all stored server data.
- -limit (optional, integer, defaults to
"1000")- Maximum records per page, 1..1000; default 1000.
- -cursor (optional, integer, defaults to
"0")- Nonnegative timestamp cursor in microseconds, default 0; pass nextCursor unchanged for continuation.
- Returns:
- Dictionary containing records, referenced topologies, storage statistics, coverage, more and nextCursor. Final-page coverage examines the full requested window.
- Testcases:
- No testcase defined.
Source code: if {$from < 0 || $to <= $from || $to - $from > 86400 || $to > [clock seconds] || $limit < 1 || $limit > 1000 || $cursor < 0 } { error "expected an epoch window up to 24 hours, limit 1..1000 and nonnegative cursor" } if {[string length $server]>512 || [string first \x00 $server] >= 0} { error "invalid server name" } set config [nsv_get ns_stats history] if {$config eq ""} { error "history is not configured" } if {[dict get $config owner] ne [ns_info server]} { error "query history from its configured owner server" } set db [:historyConnect $config] set transaction false try { :sql $db {BEGIN} set transaction true set low [expr {$from * 1000000}] set high [expr {$to * 1000000}] set count [expr {$limit + 1}] set rows [:sql $db "SELECT at,topology,payload FROM ns_stats_samples WHERE at >= $low AND at < $high AND at > $cursor ORDER BY at LIMIT $count"] set more [expr {[llength $rows] > $limit}] set rows [lrange $rows 0 [expr {$limit - 1}]] set records {} set gaps {} set restarts {} set previous {} set topology {} set resets 0 set boundary [expr {max($low,$cursor)}] set operator [expr {$cursor >= $low ? "<=" : "<"}] set prior [:scalar $db "SELECT payload FROM ns_stats_samples WHERE at $operator $boundary ORDER BY at DESC LIMIT 1"] if {$prior ne ""} { set previous [:unpack $prior] } foreach row $rows { set record [:unpack [dict get $row payload]] if {![dict get $record sampling ready]} { incr resets } if {$previous ne ""} { if {[dict get $previous instance] ne [dict get $record instance]} { lappend restarts [dict get $record sampling to] } set delta [expr {([dict get $record timestamp]-[dict get $previous timestamp]) / 1000000.0}] if {$delta > 1.5 * max([dict get $previous sampling intervalSeconds],[dict get $record sampling intervalSeconds])} { lappend gaps [dict create from [dict get $previous sampling to] to [dict get $record sampling to]] } } set previous $record set id [dict get $row topology] dict set record topologyId $id if {![dict exists $topology $id]} { dict set topology $id [:selectServer [:unpack [:scalar $db "SELECT payload FROM ns_stats_topology WHERE id=[:quote $id]"]] $server false] } lappend records [:selectServer $record $server false] } if {!$more && $previous ne ""} { set following [:scalar $db "SELECT payload FROM ns_stats_samples WHERE at >= $high ORDER BY at LIMIT 1"] if {$following ne ""} { set nextRecord [:unpack $following] set delta [expr {([dict get $nextRecord timestamp]-[dict get $previous timestamp]) / 1000000.0}] if {$delta > 1.5 * max([dict get $previous sampling intervalSeconds],[dict get $nextRecord sampling intervalSeconds])} { lappend gaps [dict create from [dict get $previous sampling to] to [dict get $nextRecord sampling to]] } } } set bounds [lindex [:sql $db {SELECT coalesce(min(at),0) AS first,coalesce(max(at),0) AS last FROM ns_stats_samples}] 0] set events [:sql $db {SELECT at,first,last,n,reason FROM ns_stats_events ORDER BY id DESC}] set first [dict get $bounds first] set last [dict get $bounds last] set overlap false foreach event $events { if {[dict get $event first] < $high && [dict get $event last] >= $low} { set overlap true } } set through [:scalar $db {SELECT value FROM ns_stats_meta WHERE key='droppedThrough'}] if {$through ne "" && $through >= $low} { set overlap true } set next {} if {$more} { set next [dict get [lindex $rows end] at] } # Intermediate coverage describes this page. The final response # examines all retained intervals in the requested window again, # within this read transaction, independently of the paging cursor. if {!$more} { set window [:historyWindowCoverage $db $low $high] set gaps [dict get $window gaps] set restarts [dict get $window restartBoundaries] set resets [dict get $window resetSamples] } set complete [expr {$first>0 && $first<=$low && $last>=$high && !$more && !$overlap && $gaps eq "" && $restarts eq "" && $resets==0}] set reasons {} if {$more} {lappend reasons more-pages} if {$first==0 || $first>$low} {lappend reasons before-retained-history} if {$last<$high} {lappend reasons after-latest-sample} if {$overlap} {lappend reasons eviction-or-write-failure} if {$gaps ne ""} {lappend reasons gaps} if {$restarts ne ""} {lappend reasons restarts} if {$resets>0} {lappend reasons baseline-or-reset} set result [dict create schemaVersion 1 from $from to $to records $records topologies $topology nextCursor $next more $more storage [:historyStorage $db $config] coverage [dict create complete $complete windowExamined [expr {!$more}] scope [expr {$more ? "page" : "window"}] incompleteReasons $reasons retainedFrom [expr {$first / 1000000.0}] retainedTo [expr {$last / 1000000.0}] gaps $gaps restartBoundaries $restarts resetSamples $resets events $events evictionOrFailureOverlap $overlap droppedThrough $through writeFailuresSinceStart [dict get $config failures]]] :sql $db {COMMIT} set transaction false return $result } finally { if {$transaction} { catch {:sql $db {ROLLBACK}} } ns_db releasehandle $db }XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)