%3 ::nx::Object ::nx::Object ::acs::LockfreeCache ::acs::LockfreeCache eval flush get ::acs::LockfreeCache->::nx::Object

Class ::acs::LockfreeCache

::acs::LockfreeCache[i] create ... \
           [ -prefix prefix ]

Lockfree caches are provided either as per-thread caches or per-request caches, sharing the property that accessing these values does not require locks. Typical applications of these caches are the per_request_cache and per_thread_cache.
See Also:
Object ::acs::per_request_cache
Object ::acs::per_thread_cache
Defined in packages/acs-tcl/tcl/acs-cache-procs.tcl

Class Relations

  • class: ::nx::Class[i]
  • superclass: ::nx::Object[i]
::nx::Class create ::acs::LockfreeCache \
     -superclass ::nx::Object

Methods (to be applied on instances)

  • eval (scripted, public)

     <instance of acs::LockfreeCache[i]> eval -key key  \
        [ -no_cache no_cache ] [ -no_empty ] \
        [ -from_cache_indicator from_cache_indicator ] cmd

    Use the "prefix" to determine whether the cache is per-thread or per-request.

    Switches:
    -key (required)
    key for caching, should start with package-key and a dot to avoid name clashes
    -no_cache (optional)
    list of returned values that should not be cached
    -no_empty (optional, defaults to "false")
    don't cache empty values. This flag is deprecated, one should use the no_cache flag instead.
    -from_cache_indicator (optional)
    variable name to indicate whether the returned value was from cache or not
    Parameters:
    cmd (required)
    command to be executed.
    Returns:
    return the last value set (don't use "return").

    Testcases:
    No testcase defined.
    if {[info exists from_cache_indicator]} {
        :upvar $from_cache_indicator from_cache
    }
    
    #if {![info exists ${:prefix}]} {
    #    ns_log notice "### exists ${:prefix} ==> 0"
    #} else {
    #    ns_log notice "### [list dict exists [set ${:prefix}] $key] ==>  [dict exists [set ${:prefix}] $key]"
    #}
    
    if {![info exists ${:prefix}] || ![dict exists [set ${:prefix}$key]} {
        #ns_log notice "### call cmd <$cmd>"
        set from_cache 0
        set value [:uplevel $cmd]
        if {$no_empty} {
            ad_log warning "no_empty flag is deprecated and will be dropped in the future."
            lappend no_cache ""
        }
        if {[info exists no_cache] && $value in $no_cache} {
            #ns_log notice "### cache eval $key returns <$value> without caching"
            return $value
        }
        #if {$value eq "0"} {
        #    ns_log notice "### cache eval $key returns <$value> with caching"
        #}
        dict set ${:prefix} $key $value
        #ns_log notice "### [list dict set ${:prefix} $key $value]"
    } else {
        set from_cache 1
        set value [dict get [set ${:prefix}$key]
    }
    #ns_log notice "### will return [list dict get ${:prefix} $key]"
    return $value
  • flush (scripted, public)

     <instance of acs::LockfreeCache[i]> flush [ -pattern pattern ]

    Flush a cache entry based on the pattern (which might be wild-card-free). Currently, the clusterwide flushing is omitted. We have the per-request cache (clusterwide operations do not make sense for this) and per-thread caching. The per-thread caching application have to be aware that flushing is happening only in one thread, so clusterwide operations will only start to make sense, when the all threads of a server would be cleaned.

    Switches:
    -pattern (optional, defaults to "*")

    Testcases:
    No testcase defined.
    if {[info exists ${:prefix}]} {
        if {$pattern eq "*"} {
            #ns_log notice "### dict flush ${:prefix} <$pattern>"
            unset -nocomplain ${:prefix}
        } elseif {[string first "*" $pattern] != -1} {
            #
            # A real pattern with wild-card was provided.
            #
            set keys [dict keys [set ${:prefix}$pattern]
            #ns_log notice "### dict flush ${:prefix} <$pattern> -> [llength $keys]"
            foreach key $keys {
                dict unset ${:prefix} $key
            }
        } elseif [dict exists [set ${:prefix}$pattern] {
            #
            # A "pattern" without a wildcard was provided
            #
            dict unset ${:prefix} $pattern
        }
    }
  • get (scripted, public)

     <instance of acs::LockfreeCache[i]> get -key key  var

    Get entry with the provided key from this cache if it exists. In most cases, the "eval" method should be used.

    Switches:
    -key (required)
    cache key
    Parameters:
    var (required)
    Returns:
    return boolean value indicating success.

    Testcases:
    No testcase defined.
    if {[info exists ${:prefix}] && [dict exists [set ${:prefix}$key]} {
        :upvar $var value
        set value [dict get [set ${:prefix}$key]
        return 1
    }
    return 0