- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::acs::Cluster
::acs::Cluster create ... \
[ -allowed_command (default " set "" unset "" nsv_set "" nsv_unset "" nsv_incr "" nsv_dict "" bgdelivery "" callback "" ns_cache "^ns_cache\s+eval" ns_cache_flush "" util_memoize_flush_regexp_local "" ns_urlspace "" acs::cache_flush_all "" acs::cache_flush_pattern "" ::acs::cluster "^::acs::cluster\s+join_request" ") ] \
[ -allowed_host (default " "127.0.0.1" 1 ") ] \
[ -currentServerLocation (default "") ] \
[ -url (default "/acs-cluster-do") ]
Class Relations
::nx::Class create ::acs::Cluster \ -superclass ::nx::ObjectMethods (to be applied on instances)
broadcast (scripted)
if {[ns_ictl epoch] > 0} { catch {::throttle do incr ::count(cluster:broadcast)} } # Small optimization for cachingmode "none": no need to # send cache flushing requests to nodes, when there is no # caching in place. # if {[ns_config "ns/parameters" cachingmode "per-node"] eq "none" && [lindex $args 0] in { acs::cache_flush_pattern acs::cache_flush_all ns_cache} } { # # If caching mode is none, it is expected that all # nodes have this parameter set. Therefore, there is no # need to communicate cache flushing commands. # return } if {[nsv_get cluster cluster_peer_nodes locations]} { # # During startup the throttle thread might not be started, # so omit these statistic values # if {[ns_ictl epoch] > 0} { foreach location $locations { catch {::throttle do incr ::count(cluster:sent)} set t0 [clock clicks -microseconds] :send $location {*}$args set ms [expr {([clock clicks -microseconds] - $t0)/1000}] catch {::throttle do incr ::agg_time(cluster:sent) $ms} } } else { foreach location $locations { :send $location {*}$args } } }current_server_is_canonical_server (scripted)
if { ![info exists :canonicalServer] || ${:canonicalServer} eq "" } { ns_log Error "Your configuration is not correct for server clustering." "Please ensure that you have the CanonicalServer parameter set correctly." return 1 } set result 0 foreach location ${:currentServerLocations} { if {[:is_canonical_server $location]} { set result 1 break } } #:log "current_server_is_canonical_server $result" return $resultincoming_request (scripted)
catch {::throttle do incr ::count(cluster:received)} ad_try { #ns_logctl severity Debug(connchan) on #ns_logctl severity Debug(request) on #ns_logctl severity Debug(ns:driver) on #ns_logctl severity Debug on set r [:message decode] set receive_timestamp [clock clicks -milliseconds] dict with r { # # We could check here the provided timepstamp and # honor only recent requests (protection against # replay attacks). However, the allowed requests # are non-destructive. # nsv_set cluster $peer-last-contact $receive_timestamp nsv_set cluster $peer-last-request $receive_timestamp nsv_incr cluster $peer-count ns_log notice "--cluster got cmd='$cmd' from $peer after [expr {$receive_timestamp - $timestamp}]ms" set result [:execute $r] } } on error {errorMsg} { ns_log notice "--cluster error: $errorMsg" ns_return 417 text/plain $errorMsg } on ok {r} { #ns_log notice "--cluster success $result" ns_return 200 text/plain $result }is_canonical_server (scripted)
if { ![info exists :canonicalServer] || ${:canonicalServer} eq "" } { ns_log Error "Your configuration is not correct for server clustering." "Please ensure that you have the CanonicalServer parameter set correctly." return 1 } set result [expr {$location in ${:canonicalServerLocation}}] #ns_log notice "is_canonical_server $location -> $result" return $resultjoin_request (scripted)
ns_log notice "Cluster join_request from '$peerLocation'" set success 1 # # Was the join request received by a canonical server? # if {![:current_server_is_canonical_server]} { ns_log warning "Cluster join_request rejected," "since it was received by a non-canonical server" set success 0 } else { # # We know, we are running on the canonical server, an # we know that the request is trustworthy. # ns_log notice "Cluster join_request $peerLocation accepted from $peerLocation" set dynamicClusterNodes [parameter::get -package_id $::acs::kernel_id -parameter DynamicClusterPeers] set dynamicClusterNodes [lsort -unique [concat $dynamicClusterNodes $peerLocation]] # # The parameter::set_value operation causes a # clusterwide cache-flush for the parameters # parameter::set_value -package_id $::acs::kernel_id -parameter DynamicClusterPeers -value $dynamicClusterNodes ns_log notice "Cluster join_request leads to DynamicClusterPeers $dynamicClusterNodes" } return $successlast_contact (scripted)
if {[nsv_get cluster $location-last-contact clicksms]} { return $clicksms }last_request (scripted)
if {[nsv_get cluster $location-last-request clicksms]} { return $clicksms }preauth (scripted)
return filter_breakregister_nodes (scripted)
:log ":register_nodes startup $startup" # # Configure base configuration values # # set dynamic_peers [parameter::get -package_id $::acs::kernel_id -parameter DynamicClusterPeers] # At startup, when we are running on the canonical server, # check, whether the existing DynamicClusterPeers are # still reachable. When the canonical server is started # before the other cluster nodes, this parameter should be # empty. However, when the canonical server is restarted, # there might be some of the peer nodes already active. # if {$startup && ${:current_server_is_canonical_server} && $dynamic_peers ne "" } { # # When we are starting the canonical server, it resets # the potentially pre-existing dynamic nodes unless # these are reachable. # set old_peer_locations $dynamic_peers :log "canonical server starts with existing DynamicClusterPeers nodes: $old_peer_locations" # # Keep the reachable cluster nodes in # "DynamicClusterPeers". # set new_peer_locations {} foreach location $old_peer_locations { if {[:reachable $location]} { lappend new_peer_locations $location } } if {$new_peer_locations ne $old_peer_locations} { # # Update the DynamicClusterPeers in the database # such that the other nodes will pick it up as # well. # :log "updating DynamicClusterPeers to $new_peer_locations" parameter::set_value -package_id $::acs::kernel_id -parameter DynamicClusterPeers -value $new_peer_locations set dynamic_peers $new_peer_locations } } # # Determine the peer nodes. # set cluster_peer_nodes [:peer_nodes $dynamic_peers] nsv_set cluster cluster_peer_nodes $cluster_peer_nodes if {![:is_configured_server ${:currentServerLocations}]} { # # Current node is not pre-registered. # ns_log notice "Current host ${:currentServerLocation} is not included in ${:configured_cluster_hosts}" if {![:current_server_is_canonical_server]} { ns_log notice "... must join at canonical server ${:canonicalServerLocation}" :send_join_request ${:canonicalServerLocation} } } else { #ns_log notice "Current host ${:currentServerLocation} is included in ${:configured_cluster_hosts}" }secret_configured (scripted)
set secret [:secret] return [expr {$secret ne ""}]send (scripted)
:log "outgoing request to $location // $args" set t0 [clock clicks -microseconds] switch $delivery { #connchan - #udp - ns_http {set result [:${delivery}_send $location {*}$args]} default {error "unknown delivery method '$delivery'"} } ns_log notice "-cluster: $location $args sent" "total [expr {([clock clicks -microseconds] - $t0)/1000.0}]ms" return $resultsend_join_request (scripted)
:log "send_join_request to $location" set r [:send $location [self] join_request ${:currentServerLocation}] #:log "... join_request returned $r" if {[dict exists $r body]} { # # During startup/separation caches might not be in # sync. Therefore, we have lost confidence in our # caches and clear these. # :log "send_join_request returned [dict get $r body], flushing all my caches" acs::cache_flush_all }setup (scripted)
set :currentServerLocations [:current_server_locations] set :currentServerLocation [:preferred_location ${:currentServerLocations}] set :canonicalServer [parameter::get -package_id $::acs::kernel_id -parameter CanonicalServer] set :canonicalServerLocation [:preferred_location [:qualified_location ${:canonicalServer}]] set :current_server_is_canonical_server [:current_server_is_canonical_server] set :staticServerLocations [lmap entry [parameter::get -package_id $::acs::kernel_id -parameter ClusterPeerIP] { :preferred_location [:qualified_location $entry] }]update_node_info (scripted)
set dynamic_peers [parameter::get -package_id $::acs::kernel_id -parameter DynamicClusterPeers] if {!${:current_server_is_canonical_server}} { # # The current node might be a static or a dynamic # peer. Do we have contact to the canonical_server? # if {![:reachable ${:canonicalServerLocation}]} { # # We lost contact to the canonical server. This is # for our server not a big problem, since all # other peer-to-peer updates will continue to # work. # # During downtime of the canonical server, # scheduled procedures (e.g. mail delivery) will # be interrupted, and no new servers can register. # ns_log warning "cluster node lost contact to " "canonical server: ${:canonicalServerLocation}" } # # Are we an dynamic peer and not listed in # DynamicClusterPeers? This might happen in # situations, where the canonical server was # restarted (or separated for a while). # if {[:current_server_is_dynamic_cluster_peer] && ${:currentServerLocation} ni $dynamic_peers } { ns_log warning "cluster node is not listed in dynamic peers." "Must re-join canonical server: ${:canonicalServerLocation}" :send_join_request ${:canonicalServerLocation} } } # # Update cluster_peer_nodes if necessary # set oldConfig [lsort [nsv_get cluster cluster_peer_nodes]] set newConfig [lsort [:peer_nodes $dynamic_peers]] if {$newConfig ne $oldConfig} { # # The cluster configuration has changed # ns_log notice "cluster config changed:\nOLD $oldConfig\nNEW $newConfig" nsv_set cluster cluster_peer_nodes $newConfig }
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables