::nsmcp::Object ::nsmcp::Object dict getdef ::nx::Object ::nx::Object ::nsmcp::Object->::nx::Object ::nsmcp::BoundedLogScanner ::nsmcp::BoundedLogScanner destroy find first init load nextLine prepareNative setBuffer ::nsmcp::BoundedLogScanner->::nsmcp::Object

Class ::nsmcp::BoundedLogScanner

::nsmcp::BoundedLogScanner[i] create ... \
           [ -blockBytes:integer (default "4194304") ] \
           [ -buffer (default "") ] \
           [ -bufferEnd (default "0") ] \
           [ -bufferFrom (default "0") ] \
           [ -cacheDirectory:required cacheDirectory:required ] \
           [ -channel (default "") ] \
           [ -keys (default "") ] \
           [ -limit (default "") ] \
           [ -literals:required literals:required ] \
           [ -native:boolean (default "true") ] \
           [ -nativePrepared (default "false") ] \
           [ -nativeThreshold:integer (default "32") ] \
           [ -overlap (default "0") ] \
           [ -readBytes (default "65536") ] \
           [ -temporaryChannel (default "") ] \
           [ -temporaryPath (default "") ] \
           [ -windowCeiling (default "-1") ] \
           [ -windowHits (default "0") ]

Defined in /usr/local/ns/tcl/nsmcp/log-01-scanner.tcl

Class Relations

  • class: ::nx::Class[i]
  • superclass: ::nsmcp::Object[i]
::nx::Class create ::nsmcp::BoundedLogScanner \
     -superclass ::nsmcp::Object

Methods (to be applied on instances)

  • destroy (scripted, public)

     <instance of nsmcp::BoundedLogScanner[i]> destroy

    Release the scanner's private temporary channel and file. Close and remove temporary resources when present, then continue NX destruction.

    Returns:
    The superclass destruction result.

    Testcases:
    No testcase defined.
    if {[info exists :temporaryChannel] && ${:temporaryChannel} ne ""} {
        catch {
            close ${:temporaryChannel}
        }
    }
    if {[info exists :temporaryPath] && ${:temporaryPath} ne ""} {
        catch {
            file delete -- ${:temporaryPath}
        }
    }
    next
  • find (scripted, public)

     <instance of nsmcp::BoundedLogScanner[i]> find from [ ceiling ]

    Find the earliest candidate within a fixed byte interval. Use overlapping bounded windows for channels or the current memory chunk; never read beyond the ceiling.

    Parameters:
    from (required)
    Inclusive starting byte offset within the fixed scan interval.
    ceiling (optional)
    Exclusive upper byte bound; empty uses the configured scanner limit.
    Returns:
    The candidate byte offset, or -1 when no candidate is found.

    Testcases:
    No testcase defined.
    if {$ceiling eq ""} {
        set ceiling ${:limit}
    }
    if {![string is entier -strict $from] || ![string is entier -strict $ceiling]
        || $from<0 || $ceiling<$from || $ceiling>${:limit}} {
        error "invalid scanner byte interval"
    }
    set position $from
    while {$position<$ceiling} {
        if {${:channel} eq ""} {
            set found [:first $position $ceiling]
            if {$found>=0} {
                incr :windowHits
            }
            return $found
        }
        if {$position<${:bufferFrom} || $position>=${:bufferEnd} || ${:windowCeiling}!=$ceiling} {
            seek ${:channel} $position
            set expected [expr {min(${:readBytes},$ceiling-$position)}]
            set bytes [read ${:channel} $expected]
            if {[string length $bytes]<$expected} {
                error "source ended before its fixed scanner bound"
            }
            :setBuffer $bytes $position $ceiling
        }
        set found [:first $position [expr {min($ceiling,${:bufferEnd})}]]
        # A short batch key near the end cannot win before a longer key
        # beginning earlier but crossing this boundary has been checked.
        if {$found>=0 && (${:bufferEnd}>=$ceiling || $found<${:bufferEnd}-${:overlap})} {
            incr :windowHits
            return $found
        }
        if {${:bufferEnd}>=$ceiling} {
            return -1
        }
        if {${:windowHits}==0} {
            set :readBytes [expr {min(${:blockBytes},2*${:readBytes})}]
        } else {
            set :readBytes [expr {min(${:blockBytes},65536)}]
        }
        set position [expr {max($from,${:bufferEnd}-${:overlap})}]
        # Refill even though the overlap is inside the previous buffer.
        set :windowCeiling -1
    }
    return -1
  • load (scripted, public)

     <instance of nsmcp::BoundedLogScanner[i]> load bytes

    Load a bounded in-memory byte chunk for candidate scanning. Reject channel-backed scanners and chunks larger than the configured block bound.

    Parameters:
    bytes (required)
    Raw binary chunk, no larger than the configured block limit.
    Returns:
    The new in-memory byte limit.

    Testcases:
    No testcase defined.
    if {${:channel} ne ""} {
        error "load requires an in-memory scanner"
    }
    if {[string length $bytes]>${:blockBytes}} {
        error "scanner chunk exceeds its byte bound"
    }
    :setBuffer $bytes 0 [string length $bytes]
    set :limit ${:bufferEnd}
  • nextLine (scripted, public)

     <instance of nsmcp::BoundedLogScanner[i]> nextLine position \
        [ filter ]

    Read an in-memory physical line, optionally using the literal prefilter. Return physical byte bounds and newline status without parsing or redacting the record.

    Parameters:
    position (required)
    Physical byte cursor within the loaded chunk.
    filter (optional, defaults to "true")
    Whether to apply the literal candidate prefilter; false reads sequentially. Defaults to 'true'.
    Returns:
    A dictionary with start, end, raw and terminated fields, or an empty result at exhaustion.

    Testcases:
    No testcase defined.
    if {${:channel} ne ""} {
        error "nextLine requires an in-memory scanner"
    }
    if {$position<0 || $position>${:limit}} {
        error "invalid line cursor"
    }
    if {$position==${:limit}} {
        return {}
    }
    if {$filter} {
        set found [:find $position]
        if {$found<0} {
            return {}
        }
        set start [expr {[string last \n ${:buffer} [expr {$found-1}]]+1}]
    } else {
        set start $position
    }
    set end [string first \n ${:buffer} $start]
    set terminated [expr {$end>=0}]
    if {!$terminated} {
        set end ${:limit}
    }
    return [dict create start $start end [expr {$end+($terminated ? 1 : 0)}]  raw [string range ${:buffer} $start [expr {$end-1}]] terminated $terminated]