Index: openacs-4/packages/acs-tcl/tcl/site-nodes-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/site-nodes-init.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/packages/acs-tcl/tcl/site-nodes-init.tcl 10 Sep 2002 22:22:14 -0000 1.3 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-init.tcl 27 Nov 2003 15:25:18 -0000 1.4 @@ -6,4 +6,6 @@ } +nsv_set site_nodes_mutex mutex [ns_mutex create] + site_node::init_cache Index: openacs-4/packages/acs-tcl/tcl/site-nodes-procs-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/site-nodes-procs-oracle.xql,v diff -u -r1.16 -r1.17 --- openacs-4/packages/acs-tcl/tcl/site-nodes-procs-oracle.xql 30 Sep 2003 12:10:03 -0000 1.16 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-procs-oracle.xql 27 Nov 2003 15:25:18 -0000 1.17 @@ -9,52 +9,47 @@ - + - select site_node.url(site_nodes.node_id) as url, - site_nodes.node_id, - site_nodes.parent_id, - site_nodes.name, - site_nodes.directory_p, - site_nodes.pattern_p, - site_nodes.object_id, - (select acs_objects.object_type - from acs_objects - where acs_objects.object_id = site_nodes.object_id) as object_type, - apm_packages.package_key, - apm_packages.package_id, - apm_packages.instance_name, - apm_package_types.package_type - from site_nodes, - apm_packages, - apm_package_types - where site_nodes.object_id = apm_packages.package_id(+) - and apm_package_types.package_key (+) = apm_packages.package_key + select n.node_id, + n.parent_id, + n.name, + n.directory_p, + n.pattern_p, + n.object_id, + p.package_key, + p.package_id, + p.instance_name, + t.package_type + from apm_packages p, + apm_package_types t, + (select node_id, parent_id, name, directory_p, pattern_p, object_id, + rownum as nodes_rownum + from site_nodes + connect by parent_id = prior node_id + start with node_id = :node_id) n + where n.object_id = p.package_id(+) + and t.package_key (+) = p.package_key + order by n.nodes_rownum - select site_node.url(site_nodes.node_id) as url, - site_nodes.node_id, - site_nodes.parent_id, - site_nodes.name, - site_nodes.directory_p, - site_nodes.pattern_p, - site_nodes.object_id, - (select acs_objects.object_type - from acs_objects - where acs_objects.object_id = site_nodes.object_id) as object_type, - apm_packages.package_key, - apm_packages.package_id, - apm_packages.instance_name, - apm_package_types.package_type - from site_nodes, - apm_packages, - apm_package_types - where site_nodes.node_id = :node_id - and site_nodes.object_id = apm_packages.package_id (+) - and apm_package_types.package_key (+) = apm_packages.package_key + select n.node_id, + n.parent_id, + n.name, + n.directory_p, + n.pattern_p, + n.object_id, + p.package_key, + p.package_id, + p.instance_name, + t.package_type + from apm_packages p, apm_package_types t, site_nodes n + where n.node_id = :node_id + and n.object_id = p.package_id(+) + and t.package_key (+) = p.package_key Index: openacs-4/packages/acs-tcl/tcl/site-nodes-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/site-nodes-procs-postgresql.xql,v diff -u -r1.17 -r1.18 --- openacs-4/packages/acs-tcl/tcl/site-nodes-procs-postgresql.xql 28 Aug 2003 09:41:43 -0000 1.17 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-procs-postgresql.xql 27 Nov 2003 15:25:18 -0000 1.18 @@ -9,48 +9,43 @@ - + - select site_node__url(site_nodes.node_id) as url, - site_nodes.node_id, - site_nodes.parent_id, - site_nodes.name, - site_nodes.directory_p, - site_nodes.pattern_p, - site_nodes.object_id, - (select acs_objects.object_type - from acs_objects - where acs_objects.object_id = site_nodes.object_id) as object_type, - apm_packages.package_key, - apm_packages.package_id, - apm_packages.instance_name, - apm_package_types.package_type - from site_nodes left join - apm_packages on site_nodes.object_id = apm_packages.package_id left join - apm_package_types using (package_key) + select n.node_id, + n.parent_id, + n.name, + n.directory_p, + n.pattern_p, + n.object_id, + p.package_key, + p.package_id, + p.instance_name, + t.package_type + from site_nodes n left join + apm_packages p on n.object_id = p.package_id left join + apm_package_types t using (package_key) + where n.tree_sortkey between site_node_get_tree_sortkey(:node_id) + and tree_right(site_node_get_tree_sortkey(:node_id)) + order by n.tree_sortkey - select site_node__url(site_nodes.node_id) as url, - site_nodes.node_id, - site_nodes.parent_id, - site_nodes.name, - site_nodes.directory_p, - site_nodes.pattern_p, - site_nodes.object_id, - (select acs_objects.object_type - from acs_objects - where acs_objects.object_id = site_nodes.object_id) as object_type, - apm_packages.package_key, - apm_packages.package_id, - apm_packages.instance_name, - apm_package_types.package_type - from site_nodes left join - apm_packages on site_nodes.object_id = apm_packages.package_id left join - apm_package_types using (package_key) - where site_nodes.node_id = :node_id + select n.node_id, + n.parent_id, + n.name, + n.directory_p, + n.pattern_p, + n.object_id, + p.package_key, + p.package_id, + p.instance_name, + t.package_type + from site_nodes n left join + apm_packages p on n.object_id = p.package_id left join + apm_package_types t using (package_key) + where n.node_id = :node_id 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.47 -r1.48 --- openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl 25 Nov 2003 04:13:47 -0000 1.47 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-procs.tcl 27 Nov 2003 15:25:18 -0000 1.48 @@ -65,14 +65,7 @@ db_dml rename_node {} - # Unset all cache entries under the old path - foreach name [nsv_array names site_nodes "${node_url}*"] { - nsv_unset site_nodes $name - } - - foreach node_id [concat $node_id $child_node_ids] { - update_cache -node_id $node_id - } + update_cache -sync_children -node_id $node_id } ad_proc -public site_node::instantiate_and_mount { @@ -162,33 +155,82 @@ ad_proc -private site_node::init_cache {} { initialize the site node cache } { - nsv_array reset site_nodes [list] - nsv_array reset site_node_urls [list] - - db_foreach select_site_nodes {} -column_array node { - nsv_set site_nodes $node(url) [array get node] - nsv_set site_node_urls $node(node_id) $node(url) - } - + set root_node_id [db_string get_root_node_id {}] + site_node::update_cache -sync_children -node_id $root_node_id } ad_proc -private site_node::update_cache { + {-sync_children:boolean} {-node_id:required} } { - if { [db_0or1row select_site_node {} -column_array node] } { - nsv_set site_nodes $node(url) [array get node] - nsv_set site_node_urls $node(node_id) $node(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. +} { + # don't let any other thread try to do a concurrent update + # until cache is fully updated + ns_mutex lock [nsv_get site_nodes_mutex mutex] - } else { - set url [get_url -node_id $node_id] + with_finally -code { - if {[nsv_exists site_nodes $url]} { - nsv_unset site_nodes $url - } + array set nodes [nsv_array get site_nodes] + array set urls [nsv_array get site_node_urls] - if {[nsv_exists site_node_urls $node_id]} { - nsv_unset site_node_urls $node_id - } + if {[catch {set old_url $urls($node_id)}]} { + set old_url "" + } + + if { ![empty_string_p $old_url] } { + # unset old nodes-subtree + if { $sync_children_p } { + array unset nodes "${old_url}*" + } else { + array unset nodes $old_url + } + } + + # Note that in the queries below, we use connect by instead of site_node.url + # to get the URLs. This is less expensive. + + if { $sync_children_p } { + set query_name select_child_site_nodes + } else { + set query_name select_site_node + } + + db_foreach $query_name {} { + if {[empty_string_p $parent_id]} { + # url of root node + set url "/" + } else { + # append directory to url of parent node + set url $urls($parent_id) + append url $name + if { $directory_p == "t" } { append url "/" } + } + # save new url + set urls($node_id) $url + + if { [empty_string_p package_id] } { + set object_type "" + } else { + set object_type "apm_package" + } + + # save new node + set nodes($url) \ + [list url $url node_id $node_id parent_id $parent_id name $name \ + directory_p $directory_p pattern_p $pattern_p \ + object_id $object_id object_type $object_type \ + package_key $package_key package_id $package_id \ + instance_name $instance_name package_type $package_type] + } + + # update arrays + nsv_array reset site_nodes [array get nodes] + nsv_array reset site_node_urls [array get urls] + + } -finally { + ns_mutex unlock [nsv_get site_nodes_mutex mutex] } } Index: openacs-4/packages/acs-tcl/tcl/site-nodes-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/site-nodes-procs.xql,v diff -u -r1.6 -r1.7 --- openacs-4/packages/acs-tcl/tcl/site-nodes-procs.xql 28 Aug 2003 09:41:43 -0000 1.6 +++ openacs-4/packages/acs-tcl/tcl/site-nodes-procs.xql 27 Nov 2003 15:25:18 -0000 1.7 @@ -25,4 +25,12 @@ + + + select node_id + from site_nodes + where parent_id is null + + + Index: openacs-4/packages/acs-tcl/tcl/utilities-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/utilities-procs.tcl,v diff -u -r1.58 -r1.59 --- openacs-4/packages/acs-tcl/tcl/utilities-procs.tcl 10 Nov 2003 17:23:02 -0000 1.58 +++ openacs-4/packages/acs-tcl/tcl/utilities-procs.tcl 27 Nov 2003 15:25:18 -0000 1.59 @@ -4107,6 +4107,59 @@ return [string range [sec_random_token] 0 $length] } +ad_proc -public with_finally { + -code:required + -finally:required +} { + Execute CODE, then execute cleanup code FINALLY. + If CODE completes normally, its value is returned after + executing FINALLY. + If CODE exits non-locally (as with error or return), FINALLY + is executed anyway. + + @param code Code to be executed that could throw and error + @param finally Cleanup code to be executed even if an error occurs +} { + global errorInfo errorCode + + # Execute CODE. + set return_code [catch {uplevel $code} string] + set s_errorInfo $errorInfo + set s_errorCode $errorCode + + # As promised, always execute FINALLY. If FINALLY throws an + # error, Tcl will propagate it the usual way. If FINALLY contains + # stuff like break or continue, the result is undefined. + uplevel $finally + + switch $return_code { + 0 { + # CODE executed without a non-local exit -- return what it + # evaluated to. + return $string + } + 1 { + # Error + return -code error -errorinfo $s_errorInfo -errorcode $s_errorCode $string + } + 2 { + # Return from the caller. + return -code return $string + } + 3 { + # break + return -code break + } + 4 { + # continue + return -code continue + } + default { + return -code $return_code $string + } + } +} + ad_proc util_background_exec { {-pass_vars ""} {-name:required} Index: openacs-4/packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl 25 Nov 2003 04:13:48 -0000 1.2 +++ openacs-4/packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl 27 Nov 2003 15:24:46 -0000 1.3 @@ -8,6 +8,85 @@ aa_register_case -cats { script +} site_node_update_cache { + Test site_node::update_cache +} { + aa_run_with_teardown -rollback -test_code { + # 1) mount /doc1 /doc2 /doc1/doc3 + set doc1_name [ad_generate_random_string] + set doc2_name [ad_generate_random_string] + set doc3_name [ad_generate_random_string] + set node1_pkg_id [site_node::instantiate_and_mount \ + -node_name $doc1_name \ + -package_key acs-core-docs] + set node1_node_id [site_node::get_node_id -url "/$doc1_name"] + set node2_pkg_id [site_node::instantiate_and_mount \ + -node_name $doc2_name \ + -package_key acs-core-docs] + set node2_node_id [site_node::get_node_id -url "/$doc2_name"] + set node3_pkg_id [site_node::instantiate_and_mount \ + -parent_node_id $node1_node_id \ + -node_name $doc3_name \ + -package_key acs-core-docs] + set node3_node_id [site_node::get_node_id -url "/$doc1_name/$doc3_name"] + set root_node_id [site_node::get_node_id -url /] + aa_equals "Verify url /doc1 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc1_name/" + aa_equals "Verify url /doc1/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc1_name/$doc3_name/" + aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" + # 2) rename /doc1 => doc4: Test /doc4 /doc4/doc3 /doc2 + set doc4_name [ad_generate_random_string] + site_node::rename -node_id $node1_node_id -name $doc4_name + aa_equals "Check new url /doc4" [site_node::get_node_id -url "/$doc4_name"] $node1_node_id + aa_equals "Check new url /doc4/doc3" [site_node::get_node_id -url "/$doc4_name/$doc3_name"] $node3_node_id + aa_equals "Check old url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id + aa_equals "Make sure old url /doc1 now matches /" [site_node::get_node_id -url "/$doc1_name/"] $root_node_id + aa_equals "Make sure old url /doc1/doc3 now matches /" [site_node::get_node_id -url "/$doc1_name/$doc3_name/"] $root_node_id + aa_equals "Verify url /doc4 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc4_name/" + aa_equals "Verify url /doc4/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc4_name/$doc3_name/" + aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" + # 3) rename /node4 => doc5 without updating children in the cache: Test /doc5 /doc4/doc3 /doc2 + set doc5_name [ad_generate_random_string] + db_dml rename_node1 { + update site_nodes + set name = :doc5_name + where node_id = :node1_node_id + } + site_node::update_cache -node_id $node1_node_id + aa_equals "Check url /doc5" [site_node::get_node_id -url "/$doc5_name"] $node1_node_id + aa_equals "Check url /doc4/doc3" [site_node::get_node_id -url "/$doc4_name/$doc3_name"] $node3_node_id + aa_equals "Check url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id + aa_equals "Make sure old url /doc1 now matches /" [site_node::get_node_id -url "/$doc1_name/"] $root_node_id + aa_equals "Make sure old url /doc1/doc3 now matches /" [site_node::get_node_id -url "/$doc1_name/$doc3_name/"] $root_node_id + aa_equals "Make sure old url /doc4 now matches /" [site_node::get_node_id -url "/$doc4_name/"] $root_node_id + aa_equals "Make sure url /doc5/doc3 now matches /doc5" [site_node::get_node_id -url "/$doc5_name/$doc3_name/"] $node1_node_id + aa_equals "Verify url /doc5 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc5_name/" + aa_equals "Verify url /doc4/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc4_name/$doc3_name/" + aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" + # 4) init_cache: Test /doc5 /doc5/doc3 /doc2 + site_node::init_cache + aa_equals "Check url /doc5" [site_node::get_node_id -url "/$doc5_name"] $node1_node_id + aa_equals "Check url /doc5/doc3" [site_node::get_node_id -url "/$doc5_name/$doc3_name"] $node3_node_id + aa_equals "Check url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id + aa_equals "Make sure old url /doc1 now matches" [site_node::get_node_id -url "/$doc1_name/"] $root_node_id + aa_equals "Make sure old url /doc1/doc3 now matches" [site_node::get_node_id -url "/$doc1_name/$doc3_name/"] $root_node_id + aa_equals "Make sure old url /doc4 now matches" [site_node::get_node_id -url "/$doc4_name/"] $root_node_id + aa_equals "Make sure old url /doc4/doc3 now matches" [site_node::get_node_id -url "/$doc4_name/$doc3_name/"] $root_node_id + aa_equals "Verify url /doc5 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc5_name/" + aa_equals "Verify url /doc5/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc5_name/$doc3_name/" + aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" + # 5) delete doc3: Test /doc5 /doc2, nonexisting /doc5/doc3 + site_node::unmount -node_id $node3_node_id + site_node::delete -node_id $node3_node_id + aa_equals "Check url /doc5" [site_node::get_node_id -url "/$doc5_name"] $node1_node_id + aa_equals "Check url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id + aa_equals "Make sure old url /doc5/doc3 now matches /doc5" [site_node::get_node_id -url "/$doc5_name/$doc3_name/"] $node1_node_id + aa_equals "Verify url /doc5 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc5_name/" + aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" + } +} + +aa_register_case -cats { + script } site_node_closest_ancestor_package { Test site_node::closest_ancestor_package } {