ns::stats::SQLiteHistory method history query (public)

 <instance of ns::stats::SQLiteHistory[i]> history query -from from  \
    -to to  [ -server server ] [ -limit limit ] [ -cursor cursor ]

Defined in

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)
-to (required, integer)
-server (optional)
-limit (optional, integer, defaults to "1000")
-cursor (optional, integer, defaults to "0")

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 {
    ::ns::stats::sql $db {BEGIN}
    set transaction true
    set low [expr {$from * 1000000}]
    set high [expr {$to * 1000000}]
    set count [expr {$limit + 1}]
    set rows [::ns::stats::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 [::ns::stats::scalar $db "SELECT payload FROM ns_stats_samples WHERE at $operator $boundary ORDER BY at DESC LIMIT 1"]

    if {$prior ne ""} {
        set previous [::ns::stats::unpack $prior]
    }
    foreach row $rows {
        set record [::ns::stats::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  [::ns::stats::unpack [::ns::stats::scalar $db "SELECT payload FROM ns_stats_topology WHERE id=[::ns::stats::quote $id]"]]  $server false]
        }
        lappend records [:selectServer $record $server false]
    }

    if {!$more && $previous ne ""} {
        set following [::ns::stats::scalar $db "SELECT payload FROM ns_stats_samples WHERE at >= $high ORDER BY at LIMIT 1"]
        if {$following ne ""} {
            set nextRecord [::ns::stats::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 [::ns::stats::sql $db {SELECT coalesce(min(at),0) AS first,coalesce(max(at),0) AS last FROM ns_stats_samples}] 0]
    set events [::ns::stats::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 [::ns::stats::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]
    }
    set complete [expr {$first > 0 && $first <= $low && $last >= $high && !$more && $cursor == 0
                        && !$overlap && $gaps eq "" && $restarts eq "" && $resets == 0}]
    set result [dict create  schemaVersion 1 from $from to $to records $records  topologies $topology nextCursor $next more $more  coverage [dict create  complete $complete  windowExamined [expr {!$more && $cursor == 0}]  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]]]
    ::ns::stats::sql $db {COMMIT}
    set transaction false
    return $result
} finally {
    if {$transaction} {
        catch {::ns::stats::sql $db {ROLLBACK}}
    }
    ns_db releasehandle $db
}
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: