Index: openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl,v diff -u -r1.107 -r1.108 --- openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl 9 May 2018 15:33:29 -0000 1.107 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl 14 May 2018 13:21:52 -0000 1.108 @@ -166,12 +166,13 @@ # first delete package_id under this node... set package_id [site_node::get_object_id \ -node_id $node_id] + set url [site_node::get_url -node_id $node_id] if {$delete_package_p} { apm_package_instance_delete $package_id } # ...then the node itself db_exec_plsql delete_site_node {} - update_cache -node_id $node_id + update_cache -node_id $node_id -url $url } } @@ -215,7 +216,7 @@ set url_by_object_id [list $node(url)] if { [nsv_exists site_node_url_by_object_id $object_id] } { - set url_by_object_id [concat [nsv_get site_node_url_by_object_id $object_id] $url_by_object_id] + set url_by_object_id [linsert $url_by_object_id 0 [nsv_get site_node_url_by_object_id $object_id]] set url_by_object_id [lsort \ -decreasing \ -command util::string_length_compare \ @@ -226,7 +227,7 @@ if { $package_key ne "" } { set url_by_package_key [list $node(url)] if { [nsv_exists site_node_url_by_package_key $package_key] } { - set url_by_package_key [concat [nsv_get site_node_url_by_package_key $package_key] $url_by_package_key] + set url_by_package_key [linsert $url_by_package_key 0 [nsv_get site_node_url_by_package_key $package_key]] } nsv_set site_node_url_by_package_key $package_key $url_by_package_key } @@ -267,7 +268,7 @@ db_dml rename_node {} db_dml update_object_title {} - update_cache -sync_children -node_id $node_id + update_cache -sync_children -node_id $node_id -url $node_url } ad_proc -public site_node::instantiate_and_mount { @@ -360,10 +361,10 @@ -arg_list [list package_id $package_id node_id $node_id] } } - + set url [site_node::get_url -node_id $node_id] db_dml unmount_object {} db_dml update_object_package_id {} - update_cache -node_id $node_id + update_cache -node_id $node_id -url $url } ad_proc -private site_node::init_cache {} { @@ -376,13 +377,15 @@ set root_node_id [db_string get_root_node_id {} -default {}] if { $root_node_id ne "" } { - site_node::update_cache -sync_children -node_id $root_node_id + set url [site_node::get_url -node_id $root_node_id] + site_node::update_cache -sync_children -node_id $root_node_id -url $url } } ad_proc -private site_node::update_cache { {-sync_children:boolean} {-node_id:required} + {-url} } { Brings the in memory copy of the site nodes hierarchy in sync with the database version. Only updates the given node and its children. @@ -882,15 +885,15 @@ include_self is set. @param url The url of the node to start from. You must provide - either url or node_id. An empty url is taken to mean - the main site. + either url or node_id. An empty url is taken to mean + the main site. @param node_id The id of the node to start from. Takes precedence - over any provided url. + over any provided url. @param package_key Restrict search to objects of this package type. You - may supply a list of package_keys. + may supply a list of package_keys. @param include_self Return the package_id at the passed-in node if it is - of the desired package_key. Ignored if package_key is - empty. + of the desired package_key. Ignored if package_key is + empty. @return The id of the first object found and an empty string if no object is found. Throws an error if no node with given url can be found. @@ -1014,212 +1017,6 @@ } return $folder } - - - -############## -# -# Deprecated Procedures -# -############# - - -ad_proc -deprecated -public site_node_delete_package_instance { - {-node_id:required} -} { - Wrapper for apm_package_instance_delete - - @author Arjun Sanyal (arjun@openforc.net) - @creation-date 2002-05-02 - @see site_node::delete -} { - db_transaction { - set package_id [site_node::get_object_id -node_id $node_id] - site_node::unmount -node_id $node_id - apm_package_instance_delete $package_id - } on_error { - site_node::update_cache -node_id $node_id - } -} - -ad_proc -deprecated -public site_map_unmount_application { - { -sync_p "t" } - { -delete_p "f" } - node_id -} { - Unmounts the specified node. - - @author Michael Bryzek (mbryzek@arsdigita.com) - @creation-date 2001-02-07 - - @param sync_p If "t", we flush the in-memory site map - @param delete_p If "t", we attempt to delete the site node. This - will fail if you have not cleaned up child nodes - @param node_id The node_id to unmount - @see site_node::unmount - -} { - db_transaction { - site_node::unmount -node_id $node_id - - if {$delete_p == "t"} { - site_node::delete -node_id $node_id - } - } -} - -ad_proc -deprecated -public site_node_id {url} { - Returns the node_id of a site node. Throws an error if there is no - matching node. - @see site_node::get_node_id -} { - return [site_node::get_node_id -url $url] -} - -ad_proc -deprecated -public site_nodes_sync {args} { - Brings the in memory copy of the url hierarchy in sync with the - database version. - - @see site_node::init_cache -} { - site_node::init_cache -} - -ad_proc -deprecated -warn site_node_closest_ancestor_package { - { -default "" } - { -url "" } - package_keys -} { -

- Use site_node::closest_ancestor_package. Note that - site_node_closest_ancestor_package will include the passed-in node in the - search, whereas the new proc doesn't by default. If you want to include - the passed-in node, call site_node::closest_ancestor_package with the - -include_self flag -

- -

- Finds the package id of a package of specified type that is - closest to the node id represented by url (or by ad_conn url).Note - that closest means the nearest ancestor node of the specified - type, or the current node if it is of the correct type. - -

- - Usage: - -

-    # Pull out the package_id of the subsite closest to our current node
-    set pkg_id [site_node::closest_ancestor_package -include_self -package_key "acs-subsite"]
-    
- - @author Michael Bryzek (mbryzek@arsdigita.com) - @creation-date 1/17/2001 - - @param default The value to return if no package can be found - @param current_node_id The node from which to start the search - @param package_keys The type(s) of the package(s) for which we are looking - - @return package_id of the nearest package of the - specified type (package_key). Returns $default if no - such package can be found. - - @see site_node::closest_ancestor_package -} { - if {$url eq ""} { - set url [ad_conn url] - } - - # Try the URL as is. - if {[catch {nsv_get site_nodes $url} result] == 0} { - array set node $result - if {$node(package_key) in $package_keys} { - return $node(package_id) - } - } - - # Add a trailing slash and try again. - if {[string index $url end] ne "/"} { - append url "/" - if {[catch {nsv_get site_nodes $url} result] == 0} { - array set node $result - if {$node(package_key) in $package_keys} { - return $node(package_id) - } - } - } - - # Try successively shorter prefixes. - while {$url ne ""} { - # Chop off last component and try again. - set url [string trimright $url /] - set url [string range $url 0 [string last / $url]] - - if {[catch {nsv_get site_nodes $url} result] == 0} { - array set node $result - if {$node(pattern_p) == "t" - && $node(object_id) ne "" - && $node(package_key) in $package_keys} { - return $node(package_id) - } - } - } - - return $default -} - -ad_proc -deprecated -public site_node_closest_ancestor_package_url { - { -default "" } - { -package_key {} } -} { - Returns the url stub of the nearest application of the specified - type. - - @author Michael Bryzek (mbryzek@arsdigita.com) - @creation-date 2001-02-05 - - @param package_key The types of packages for which we're looking (defaults to subsite packages) - @param default The default value to return if no package of the - specified type was found - - @see site::node::closest_ancestor_package -} { - if {$package_key eq ""} { - set package_key [subsite::package_keys] - } - - set subsite_pkg_id [site_node::closest_ancestor_package \ - -include_self \ - -package_key $package_key \ - -url [ad_conn url] ] - - if {$subsite_pkg_id eq ""} { - # No package was found... return the default - return $default - } - - return [lindex [site_node::get_url_from_object_id -object_id $subsite_pkg_id] 0] -} - -ad_proc -deprecated -public site_node::conn_url { -} { - Use this in place of ns_conn url when referencing host_nodes. - This proc returns the appropriate ns_conn url value, depending on - if host_node_map is used for current connection, or hostname's - domain. - @see ad_conn -} { - set ns_conn_url [ns_conn url] - set subsite_get_url [subsite::get_url] - set joined_url [file join $subsite_get_url $ns_conn_url] - # join drops ending slash for some cases. Add back if appropriate. - if { [string index $ns_conn_url end] eq "/" && [string index $joined_url end] ne "/" } { - append joined_url "/" - } - return $joined_url -} - - ##################################################################### # old end of file ##################################################################### @@ -1242,7 +1039,7 @@ ##################################################### # # This class capsulates access to site-nodes stored in the - # database. It is written in a style to support the the needs + # database. It is written in a style to support the needs # of the Tcl-based API above. # # @author Gustaf Neumann @@ -1278,12 +1075,12 @@ # :protected method properties { - -node_id:integer,required - } { + -node_id:integer,required + } { # # Get url, since it is not returned by the later query. - # TODO: I did not want to modifiy the query for the time + # TODO: I did not want to modify the query for the time # being. When doing the Oracle support, the retrieval of the URL # should be moved into the query below.... # @@ -1463,7 +1260,7 @@ # @method flush_cache # a stub to be overloaded by the cache manager # - :public method flush_cache {{-node_id ""} {-with_subtree:boolean}} {;} + :public method flush_cache {{-node_id ""} {-with_subtree:boolean} {-url ""}} {;} # Create an object "site_node" to provide a user-interface close # to the classical one. @@ -1534,7 +1331,7 @@ } :public method get_node_id {-url:required} { - return [ns_cache_eval xo_site_nodes_id id-$url { next }] + ns_cache_eval xo_site_nodes_id id-$url { next } } :protected method properties {-node_id:required} { @@ -1575,7 +1372,8 @@ } } - :public method flush_cache {{-node_id ""} {-with_subtree:boolean true}} { + :public method flush_cache {{-node_id ""} {-with_subtree:boolean true} {-url ""}} { + # # Flush entries from site-node tree, including the current node, # the root of flushed (sub)tree. If the node_id is not provided, @@ -1594,13 +1392,13 @@ # # The following query is just for PG, TODO: Oracle is missing # - set tree [::xo::dc list_of_lists [current method]-flush-tree " - select site_node__url(children.node_id), children.node_id, children.object_id - from site_nodes as parent, site_nodes as children - where parent.node_id = :node_id - and children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) - $limit_clause - "] + set tree [::xo::dc list_of_lists [current method]-flush-tree [subst { + select site_node__url(children.node_id), children.node_id, children.object_id + from site_nodes as parent, site_nodes as children + where parent.node_id = :node_id + and children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) + $limit_clause + }]] foreach entry $tree { lassign $entry url node_id object_id foreach key [list p-$node_id url-$node_id urls-$object_id] { @@ -1612,16 +1410,102 @@ :flush_all id-$old_url* } } - } + + ::nx::Class create SiteNodeUrlspaceCache { + # + # Cache site-node information via ns_urlspace. We can use + # the URL trie, which supports tree match operations, for + # tree information. This means that for example for .vuh + # handlers it is not necessary to cache the full url for + # obtaining the site-node, like it was until now: + # + # 3839 id-/storage/view/installers/windows-installer/installer.htm + # 3839 id-/storage/view/aolserver/install.tgz + # 3839 id-/storage/view/tutorial/OpenACS_Tutorial.htm + # 3839 id-/storage/view/openacs-dotlrn-conference-2007-spring/Methodology_ALPE.pdf + # 3839 id-/storage/view/xowiki-resources/Assessment.jpg + # 3839 id-/storage/view/tutorial-page-map.png + # ... + # + # Providing a single entry like + # + # ns_urlspace set -key sitenode /storage/* 3839 + # + # is sufficient. - # Turn on caching by registering the mixin (backward compatibility - # for early XOTcl2-versions, probably not needed anymore). - if {[package require nsf] >= "2.0.0"} { - site_node object mixins add SiteNodeCache - } else { - site_node object mixin add SiteNodeCache + :public method get_node_id {-url:required} { + # + # Try per-request caching + # + set key ::__node_id($url) + if {[info exists $key]} { + return [set $key] + } + # + # Try to get value from urlspace + # + set ID [ns_urlspace get -key sitenode $url] + #ns_log notice "--- get_node_id from urlspace <$url> -> <$ID>" + if {$ID ne ""} { + return [set $key $ID] + } else { + # + # Get value the classical way, caching potentially + # the full url path in the xo_site_nodes_id cache. + # + set ID [next] + #ns_log notice "--- get_node_id from xo_site_nodes_id <$url> -> <$ID>" + if {$ID ne ""} { + # + # We got a valid ID. If we would add blindly a + # node_id for the returned URL (e.g. for "/*") + # and some other subnode is not jet resolved, + # we would obtain later the node-ide of the + # parent-node although there is a subnode. + # + # We could address this by e.g. preaching all + # "inner nodes" or similar, but this requires + # a deeper analysis of larger sites. + # + if {[llength [site_node::get_children -node_id $ID]] == 0} { + # + # We are on a leaf-node of the site node + # tree. Get the shortened url and save it + # in the urlspace. + # + set short_url [site_node::get_url -node_id $ID] + set cmd [list ns_urlspace set -key sitenode $short_url* $ID] + ns_log notice "--- get_node_id save in urlspace <$cmd> -> <$ID>" + {*}$cmd + #ns_log notice "---\n[join [ns_urlspace list] \n]" + } + return [set $key $ID] + } + } + } + + :public method flush_cache {{-node_id ""} {-with_subtree:boolean true} {-url ""}} { + # + # Cleanup in the urspace tree: Clear always the + # full subtree via "-recurse" (maybe not always + # necessary). + # + + #ns_log notice ==========flush_cache=================[list ns_urlspace unset -recurse -key sitenode $url] + ns_urlspace unset -recurse -key sitenode $url + + next + } + + } + site_node object mixins add SiteNodeCache + if {[info commands ns_urlspace] ne ""} { + ns_log notice "... using NaviServer's ns_urlspace for reduced redundancy in site node caches" + site_node object mixins add SiteNodeUrlspaceCache + } + } ##################################################################### @@ -1657,29 +1541,34 @@ } { mount object at site node } { + db_dml mount_object {} db_dml update_object_package_id {} # We might have for this node_id (or under it) some entries in # the cache, so flush these first. Since the cache might # contain children, we have to flush on all ancestor nodes up # to the top node. - #set ancestors [site_node::get_ancestors -node_id $node_id -element node_id] #foreach n $ancestors { - #site_node::update_cache -sync_children -node_id $n + #site_node::update_cache -sync_children -node_id $n #} - site_node::update_cache -sync_children -node_id $node_id + # + # We have to flush from the parent_url (which might be a leaf + # turning into an inner node) + # set parent_node_id [site_node::get_parent_id -node_id [site_node::get_parent_id -node_id $node_id]] + set url [site_node::get_url -node_id $parent_node_id] + + site_node::update_cache -sync_children -node_id $node_id -url $url ::xo::site_node flush_all get_children-$parent_node_id-* - # DAVEB update context_id if it is passed in - # some code relies on context_id to be set by - # instantiate_and_mount so we can't assume - # anything at this point. Callers that need to set context_id - # for example, when an unmounted package is mounted, - # should pass in the correct context_id + # DAVEB update context_id if it is passed in some code relies + # on context_id to be set by instantiate_and_mount so we can't + # assume anything at this point. Callers that need to set + # context_id for example, when an unmounted package is + # mounted, should pass in the correct context_id if {[info exists context_id]} { db_dml update_package_context_id "" } @@ -1712,12 +1601,13 @@ ad_proc -private site_node::update_cache { {-sync_children:boolean} {-node_id:required} + {-url ""} } { Brings the in memory copy of the site nodes hierarchy in sync with the database version. Only updates the given node and its children. } { - #ns_log Notice "site_node::update_cache for node_id $node_id" - ::xo::site_node flush_cache -node_id $node_id -with_subtree $sync_children_p + #ns_log Notice "================================== site_node::update_cache for node_id $node_id <$url>" + ::xo::site_node flush_cache -node_id $node_id -with_subtree $sync_children_p -url $url set parent_node_id [site_node::get_parent_id -node_id $node_id] ::xo::site_node flush_all get_children-$parent_node_id-* @@ -1924,6 +1814,207 @@ } + +######################################################################## +# deprecated site-nodes-procs.tcl +######################################################################## + +ad_proc -deprecated site_node_delete_package_instance { + {-node_id:required} +} { + Wrapper for apm_package_instance_delete + + @author Arjun Sanyal (arjun@openforc.net) + @creation-date 2002-05-02 + @see site_node::delete +} { + db_transaction { + set package_id [site_node::get_object_id -node_id $node_id] + site_node::unmount -node_id $node_id + apm_package_instance_delete $package_id + } on_error { + site_node::update_cache -node_id $node_id + } +} + +ad_proc -deprecated site_map_unmount_application { + { -sync_p "t" } + { -delete_p "f" } + node_id +} { + Unmounts the specified node. + + @author Michael Bryzek (mbryzek@arsdigita.com) + @creation-date 2001-02-07 + + @param sync_p If "t", we flush the in-memory site map + @param delete_p If "t", we attempt to delete the site node. This + will fail if you have not cleaned up child nodes + @param node_id The node_id to unmount + @see site_node::unmount + +} { + db_transaction { + site_node::unmount -node_id $node_id + + if {$delete_p == "t"} { + site_node::delete -node_id $node_id + } + } +} + +ad_proc -deprecated site_node_id {url} { + Returns the node_id of a site node. Throws an error if there is no + matching node. + @see site_node::get_node_id +} { + return [site_node::get_node_id -url $url] +} + +ad_proc -deprecated site_nodes_sync {args} { + Brings the in memory copy of the url hierarchy in sync with the + database version. + + @see site_node::init_cache +} { + site_node::init_cache +} + +ad_proc -deprecated -warn site_node_closest_ancestor_package { + { -default "" } + { -url "" } + package_keys +} { +

+ Use site_node::closest_ancestor_package. Note that + site_node_closest_ancestor_package will include the passed-in node in the + search, whereas the new proc doesn't by default. If you want to include + the passed-in node, call site_node::closest_ancestor_package with the + -include_self flag +

+ +

+ Finds the package id of a package of specified type that is + closest to the node id represented by url (or by ad_conn url).Note + that closest means the nearest ancestor node of the specified + type, or the current node if it is of the correct type. + +

+ + Usage: + +

+    # Pull out the package_id of the subsite closest to our current node
+    set pkg_id [site_node::closest_ancestor_package -include_self -package_key "acs-subsite"]
+    
+ + @author Michael Bryzek (mbryzek@arsdigita.com) + @creation-date 1/17/2001 + + @param default The value to return if no package can be found + @param current_node_id The node from which to start the search + @param package_keys The type(s) of the package(s) for which we are looking + + @return package_id of the nearest package of the + specified type (package_key). Returns $default if no + such package can be found. + + @see site_node::closest_ancestor_package +} { + if {$url eq ""} { + set url [ad_conn url] + } + + # Try the URL as is. + if {[catch {nsv_get site_nodes $url} result] == 0} { + array set node $result + if {$node(package_key) in $package_keys} { + return $node(package_id) + } + } + + # Add a trailing slash and try again. + if {[string index $url end] ne "/"} { + append url "/" + if {[catch {nsv_get site_nodes $url} result] == 0} { + array set node $result + if {$node(package_key) in $package_keys} { + return $node(package_id) + } + } + } + + # Try successively shorter prefixes. + while {$url ne ""} { + # Chop off last component and try again. + set url [string trimright $url /] + set url [string range $url 0 [string last / $url]] + + if {[catch {nsv_get site_nodes $url} result] == 0} { + array set node $result + if {$node(pattern_p) == "t" + && $node(object_id) ne "" + && $node(package_key) in $package_keys + } { + return $node(package_id) + } + } + } + + return $default +} + +ad_proc -deprecated site_node_closest_ancestor_package_url { + { -default "" } + { -package_key {} } +} { + Returns the url stub of the nearest application of the specified + type. + + @author Michael Bryzek (mbryzek@arsdigita.com) + @creation-date 2001-02-05 + + @param package_key The types of packages for which we're looking (defaults to subsite packages) + @param default The default value to return if no package of the + specified type was found + + @see site::node::closest_ancestor_package +} { + if {$package_key eq ""} { + set package_key [subsite::package_keys] + } + + set subsite_pkg_id [site_node::closest_ancestor_package \ + -include_self \ + -package_key $package_key \ + -url [ad_conn url] ] + + if {$subsite_pkg_id eq ""} { + # No package was found... return the default + return $default + } + + return [lindex [site_node::get_url_from_object_id -object_id $subsite_pkg_id] 0] +} + +ad_proc -deprecated site_node::conn_url { +} { + Use this in place of ns_conn url when referencing host_nodes. + This proc returns the appropriate ns_conn url value, depending on + if host_node_map is used for current connection, or hostname's + domain. + @see ad_conn +} { + set ns_conn_url [ns_conn url] + set subsite_get_url [subsite::get_url] + set joined_url [file join $subsite_get_url $ns_conn_url] + # join drops ending slash for some cases. Add back if appropriate. + if { [string index $ns_conn_url end] eq "/" && [string index $joined_url end] ne "/" } { + append joined_url "/" + } + return $joined_url +} + # # Local variables: # mode: tcl