Ticket #42252: 42252.8.diff
File 42252.8.diff, 20.3 KB (added by , 3 years ago) |
---|
-
src/wp-includes/class-wp-site-query.php
240 240 */ 241 241 do_action_ref_array( 'pre_get_sites', array( &$this ) ); 242 242 243 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. 244 $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ); 245 246 // Ignore the $fields argument as the queried result will be the same regardless. 247 unset( $_args['fields'] ); 248 249 $key = md5( serialize( $_args ) ); 250 $last_changed = wp_cache_get_last_changed( 'sites' ); 251 252 $cache_key = "get_sites:$key:$last_changed"; 243 $cache_key = $this->get_cache_key( $this->query_vars ); 253 244 $cache_value = wp_cache_get( $cache_key, 'sites' ); 254 245 255 246 if ( false === $cache_value ) { … … 698 689 return 'DESC'; 699 690 } 700 691 } 692 693 /** 694 * Generates the cache key to lookup query results for a specific set of arguments. 695 * 696 * @since 5.0.0 697 * 698 * @param array $query_vars Array of WP_Site_Query arguments. See WP_Site_Query::__construct(). 699 * @return string Cache key to use for the lookup. 700 */ 701 protected function get_cache_key( $query_vars ) { 702 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. 703 $_args = wp_array_slice_assoc( $query_vars, array_keys( $this->query_var_defaults ) ); 704 705 // Ignore the $fields argument as the queried result will be the same regardless. 706 unset( $_args['fields'] ); 707 708 // Ignore the $update_site_cache as it does not affect the query. 709 unset( $_args['update_site_cache'] ); 710 711 // Use the same cache key for array lookups with one element and single value lookups. 712 $single_multi_mappings = array( 713 'ID' => 'site__in', 714 'network_id' => 'network__in', 715 'domain' => 'domain__in', 716 'path' => 'path__in', 717 'lang_id' => 'lang__in', 718 ); 719 foreach ( $single_multi_mappings as $single_var => $multi_var ) { 720 if ( empty( $_args[ $single_var ] ) && isset( $_args[ $multi_var ] ) && is_array( $_args[ $multi_var ] ) && count( $_args[ $multi_var ] ) === 1 ) { 721 $_args[ $single_var ] = array_pop( $_args[ $multi_var ] ); 722 $_args[ $multi_var ] = ''; 723 } 724 } 725 726 $key = md5( serialize( $_args ) ); 727 728 /* The following part of the code checks some common combinations of query vars. 729 * If all non-empty values that actually affect the last_changed date for the query 730 * belong to one of the special argument combinations, a more specific last_changed 731 * cache key is used instead of the global one. */ 732 733 // Only consider arguments that are not empty and have thus been passed to the query. 734 $used_args = array_filter( $_args ); 735 736 // The following arguments affect the query result, but not its last_changed value. 737 $ignore_args = array( 'number', 'offset', 'no_found_rows', 'orderby', 'order', 'count' ); 738 $used_args = array_diff_key( $used_args, array_flip( $ignore_args ) ); 739 740 // The following arguments are relevant for a special 'last_changed' prefix. 741 $last_changed_keys = array( 'domain', 'path', 'network_id' ); 742 743 $last_changed_args = array(); 744 foreach ( $last_changed_keys as $last_changed_key ) { 745 if ( isset( $used_args[ $last_changed_key ] ) ) { 746 $last_changed_args[ $last_changed_key ] = (string) $used_args[ $last_changed_key ]; 747 unset( $used_args[ $last_changed_key ] ); 748 } 749 } 750 751 // Only use a special 'last_changed' prefix if no other arguments are present. 752 if ( ! empty( $last_changed_args ) && empty( $used_args ) ) { 753 $last_changed_prefix = md5( serialize( $last_changed_args ) ) . '_'; 754 } else { 755 $last_changed_prefix = ''; 756 } 757 758 $last_changed = wp_cache_get_last_changed( 'sites', $last_changed_prefix ); 759 760 return "get_sites:$key:$last_changed"; 761 } 701 762 } -
src/wp-includes/functions.php
5952 5952 * Get last changed date for the specified cache group. 5953 5953 * 5954 5954 * @since 4.7.0 5955 * @since 5.0.0 Now supports the $prefix parameter. 5955 5956 * 5956 * @param string $group Where the cache contents are grouped. 5957 * @param string $group Where the cache contents are grouped. 5958 * @param string $prefix Optional. Prefix to look for a specific last changed key. Default empty string. 5957 5959 * 5958 5960 * @return string $last_changed UNIX timestamp with microseconds representing when the group was last changed. 5959 5961 */ 5960 function wp_cache_get_last_changed( $group ) { 5961 $last_changed = wp_cache_get( 'last_changed', $group ); 5962 function wp_cache_get_last_changed( $group, $prefix = '' ) { 5963 $key = $prefix . 'last_changed'; 5964 5965 $last_changed = wp_cache_get( $key, $group ); 5962 5966 5963 5967 if ( ! $last_changed ) { 5964 5968 $last_changed = microtime(); 5965 wp_cache_set( 'last_changed', $last_changed, $group );5969 wp_cache_set( $key, $last_changed, $group ); 5966 5970 } 5967 5971 5968 5972 return $last_changed; -
src/wp-includes/ms-blogs.php
459 459 'blog_id' => $blog_id, 460 460 'domain' => null, 461 461 'path' => null, 462 'site_id' => get_current_network_id(), 462 463 ) 463 464 ); 464 465 } … … 486 487 */ 487 488 do_action( 'clean_site_cache', $blog_id, $blog, $domain_path_key ); 488 489 489 wp_cache_set( 'last_changed', microtime(), 'sites' ); 490 $current_time = microtime(); 491 492 // The following arguments are relevant for a special 'last_changed' prefix. 493 $last_changed_args = array( 494 'domain' => $blog->domain, 495 'path' => $blog->path, 496 'network_id' => $blog->site_id, 497 ); 498 499 $last_changed_prefixes = array( '' ); 500 501 // Generate all possible variations. 502 $combinations = array( array() ); 503 foreach ( $last_changed_args as $key => $value ) { 504 $value = (string) $value; 505 506 foreach ( $combinations as $combination ) { 507 $current_args = array_merge( $combination, array( $key => $value ) ); 508 $last_changed_prefixes[] = md5( serialize( $current_args ) ) . '_'; 509 510 $combinations[] = $current_args; 511 } 512 } 513 514 foreach ( $last_changed_prefixes as $last_changed_prefix ) { 515 wp_cache_set( $last_changed_prefix . 'last_changed', $current_time, 'sites' ); 516 } 490 517 491 518 /** 492 519 * Fires after the blog details cache is cleared. -
tests/phpunit/tests/multisite/siteQuery.php
63 63 'path' => '/foo/bar/', 64 64 'site_id' => self::$network_ids['wordpress.org/'], 65 65 ), 66 'wordpress.org/differentnetwork/' => array( 67 'domain' => 'wordpress.org', 68 'path' => '/differentnetwork/', 69 'site_id' => self::$network_ids['make.wordpress.org/'], 70 ), 71 'test.wordpress.org/' => array( 72 'domain' => 'test.wordpress.org', 73 'path' => '/', 74 'site_id' => self::$network_ids['wordpress.org/'], 75 ), 76 'test.wordpress.org/foo/' => array( 77 'domain' => 'test.wordpress.org', 78 'path' => '/foo/', 79 'site_id' => self::$network_ids['wordpress.org/'], 80 ), 66 81 'make.wordpress.org/' => array( 67 82 'domain' => 'make.wordpress.org', 68 83 'path' => '/', … … 228 243 array( 229 244 'fields' => 'ids', 230 245 'network_id' => self::$network_ids['wordpress.org/'], 231 'number' => 3,246 'number' => 5, 232 247 'order' => 'ASC', 233 248 ) 234 249 ); … … 237 252 self::$site_ids['wordpress.org/'], 238 253 self::$site_ids['wordpress.org/foo/'], 239 254 self::$site_ids['wordpress.org/foo/bar/'], 255 self::$site_ids['test.wordpress.org/'], 256 self::$site_ids['test.wordpress.org/foo/'], 240 257 ); 241 258 242 259 $this->assertEquals( $expected, $found ); … … 245 262 array( 246 263 'fields' => 'ids', 247 264 'network_id' => self::$network_ids['wordpress.org/'], 248 'number' => 3,265 'number' => 5, 249 266 'order' => 'DESC', 250 267 ) 251 268 ); … … 265 282 $expected = array( 266 283 self::$site_ids['make.wordpress.org/'], 267 284 self::$site_ids['make.wordpress.org/foo/'], 285 self::$site_ids['wordpress.org/differentnetwork/'], 268 286 ); 269 287 270 288 $this->assertEqualSets( $expected, $found ); … … 369 387 self::$site_ids['wordpress.org/'], 370 388 self::$site_ids['wordpress.org/foo/'], 371 389 self::$site_ids['wordpress.org/foo/bar/'], 390 self::$site_ids['wordpress.org/differentnetwork/'], 372 391 self::$site_ids['make.wordpress.org/'], 373 392 self::$site_ids['make.wordpress.org/foo/'], 374 393 ); … … 390 409 self::$site_ids['wordpress.org/'], 391 410 self::$site_ids['wordpress.org/foo/'], 392 411 self::$site_ids['wordpress.org/foo/bar/'], 412 self::$site_ids['wordpress.org/differentnetwork/'], 413 self::$site_ids['test.wordpress.org/'], 414 self::$site_ids['test.wordpress.org/foo/'], 393 415 self::$site_ids['make.wordpress.org/'], 394 416 self::$site_ids['make.wordpress.org/foo/'], 395 417 ); … … 408 430 409 431 $expected = array( 410 432 get_current_blog_id(), // Account for the initial site added by the test suite. 433 self::$site_ids['test.wordpress.org/'], 434 self::$site_ids['test.wordpress.org/foo/'], 411 435 self::$site_ids['make.wordpress.org/'], 412 436 self::$site_ids['make.wordpress.org/foo/'], 413 437 ); … … 657 681 $expected = array( 658 682 self::$site_ids['wordpress.org/foo/'], 659 683 self::$site_ids['wordpress.org/foo/bar/'], 684 self::$site_ids['test.wordpress.org/foo/'], 660 685 self::$site_ids['make.wordpress.org/foo/'], 661 686 self::$site_ids['www.w.org/foo/'], 662 687 self::$site_ids['www.w.org/foo/bar/'], … … 878 903 ); 879 904 $this->assertEquals( $number_of_queries + 1, $wpdb->num_queries ); 880 905 } 906 907 /** 908 * @ticket 42252 909 * @dataProvider data_wp_site_query_granular_cache 910 */ 911 public function test_wp_site_query_granular_cache( $query_vars, $site_id, $update_data, $add ) { 912 global $wpdb; 913 914 if ( is_string( $site_id ) ) { 915 $site_id = self::$site_ids[ $site_id ]; 916 } 917 918 if ( isset( $query_vars['network_id'] ) && is_string( $query_vars['network_id'] ) ) { 919 $query_vars['network_id'] = self::$network_ids[ $query_vars['network_id'] ]; 920 } 921 922 $this->set_last_changed( get_site( $site_id ), current_time( 'timestamp' ) - HOUR_IN_SECONDS ); 923 924 $q = new WP_Site_Query(); 925 926 $query_1 = $q->query( $query_vars ); 927 928 update_blog_details( $site_id, $update_data ); 929 930 $number_of_queries = $wpdb->num_queries; 931 932 $query_2 = $q->query( $query_vars ); 933 934 $expected = $add ? $number_of_queries + 1 : $number_of_queries; 935 936 $this->assertEquals( $expected, $wpdb->num_queries ); 937 } 938 939 public function data_wp_site_query_granular_cache() { 940 $base_domain = 'wordpress.org'; 941 $base_path = '/'; 942 $base_network_id = $base_domain . $base_path; 943 944 $all_different = 'make.wordpress.org/foo/'; 945 946 $same_domain = 'wordpress.org/differentnetwork/'; 947 $same_path = 'make.wordpress.org/'; 948 $same_network_id = 'test.wordpress.org/foo/'; 949 950 // A combination of $same_domain_path (with different network ID) does not exist. 951 $same_domain_network_id = 'wordpress.org/foo/'; 952 $same_path_network_id = 'test.wordpress.org/'; 953 954 $same_domain_path_network_id = 'wordpress.org/'; 955 956 $base_data_sets = array( 957 958 // Update for a random site field. 959 array( 960 'query_vars' => array( 961 'fields' => 'ids', 962 ), 963 'update_data' => array( 964 'mature' => 1, 965 ), 966 ), 967 968 // Update for a site field that is sorted by and may change the order. 969 array( 970 'query_vars' => array( 971 'fields' => 'ids', 972 'orderby' => 'registered', 973 'order' => 'DESC', 974 ), 975 'update_data' => array( 976 'registered' => '0000-00-00 00:00:00', 977 ), 978 ), 979 ); 980 981 $test_data = array(); 982 foreach ( $base_data_sets as $base_data_set ) { 983 $comparison_sets = array( 984 985 // General query without any special field. 986 array( 987 'query_vars' => array(), 988 'comparisons' => array( 989 array( 990 'site_id' => $all_different, 991 'add' => true, 992 ), 993 array( 994 'site_id' => $same_domain, 995 'add' => true, 996 ), 997 array( 998 'site_id' => $same_path, 999 'add' => true, 1000 ), 1001 array( 1002 'site_id' => $same_network_id, 1003 'add' => true, 1004 ), 1005 array( 1006 'site_id' => $same_domain_network_id, 1007 'add' => true, 1008 ), 1009 array( 1010 'site_id' => $same_path_network_id, 1011 'add' => true, 1012 ), 1013 array( 1014 'site_id' => $same_domain_path_network_id, 1015 'add' => true, 1016 ), 1017 ), 1018 ), 1019 1020 // Query by domain. 1021 array( 1022 'query_vars' => array( 1023 'domain' => $base_domain, 1024 ), 1025 'comparisons' => array( 1026 array( 1027 'site_id' => $all_different, 1028 'add' => false, 1029 ), 1030 array( 1031 'site_id' => $same_domain, 1032 'add' => true, 1033 ), 1034 array( 1035 'site_id' => $same_path, 1036 'add' => false, 1037 ), 1038 array( 1039 'site_id' => $same_network_id, 1040 'add' => false, 1041 ), 1042 array( 1043 'site_id' => $same_domain_network_id, 1044 'add' => true, 1045 ), 1046 array( 1047 'site_id' => $same_path_network_id, 1048 'add' => false, 1049 ), 1050 array( 1051 'site_id' => $same_domain_path_network_id, 1052 'add' => true, 1053 ), 1054 ), 1055 ), 1056 1057 // Query by path. 1058 array( 1059 'query_vars' => array( 1060 'path' => $base_path, 1061 ), 1062 'comparisons' => array( 1063 array( 1064 'site_id' => $all_different, 1065 'add' => false, 1066 ), 1067 array( 1068 'site_id' => $same_domain, 1069 'add' => false, 1070 ), 1071 array( 1072 'site_id' => $same_path, 1073 'add' => true, 1074 ), 1075 array( 1076 'site_id' => $same_network_id, 1077 'add' => false, 1078 ), 1079 array( 1080 'site_id' => $same_domain_network_id, 1081 'add' => false, 1082 ), 1083 array( 1084 'site_id' => $same_path_network_id, 1085 'add' => true, 1086 ), 1087 array( 1088 'site_id' => $same_domain_path_network_id, 1089 'add' => true, 1090 ), 1091 ), 1092 ), 1093 1094 // Query by network ID. 1095 array( 1096 'query_vars' => array( 1097 'network_id' => $base_network_id, 1098 ), 1099 'comparisons' => array( 1100 array( 1101 'site_id' => $all_different, 1102 'add' => false, 1103 ), 1104 array( 1105 'site_id' => $same_domain, 1106 'add' => false, 1107 ), 1108 array( 1109 'site_id' => $same_path, 1110 'add' => false, 1111 ), 1112 array( 1113 'site_id' => $same_network_id, 1114 'add' => true, 1115 ), 1116 array( 1117 'site_id' => $same_domain_network_id, 1118 'add' => true, 1119 ), 1120 array( 1121 'site_id' => $same_path_network_id, 1122 'add' => true, 1123 ), 1124 array( 1125 'site_id' => $same_domain_path_network_id, 1126 'add' => true, 1127 ), 1128 ), 1129 ), 1130 1131 // Query by domain and path. 1132 array( 1133 'query_vars' => array( 1134 'domain' => $base_domain, 1135 'path' => $base_path, 1136 ), 1137 'comparisons' => array( 1138 array( 1139 'site_id' => $all_different, 1140 'add' => false, 1141 ), 1142 array( 1143 'site_id' => $same_domain, 1144 'add' => false, 1145 ), 1146 array( 1147 'site_id' => $same_path, 1148 'add' => false, 1149 ), 1150 array( 1151 'site_id' => $same_network_id, 1152 'add' => false, 1153 ), 1154 array( 1155 'site_id' => $same_domain_network_id, 1156 'add' => false, 1157 ), 1158 array( 1159 'site_id' => $same_path_network_id, 1160 'add' => false, 1161 ), 1162 array( 1163 'site_id' => $same_domain_path_network_id, 1164 'add' => true, 1165 ), 1166 ), 1167 ), 1168 1169 // Query by domain and network ID. 1170 array( 1171 'query_vars' => array( 1172 'domain' => $base_domain, 1173 'network_id' => $base_network_id, 1174 ), 1175 'comparisons' => array( 1176 array( 1177 'site_id' => $all_different, 1178 'add' => false, 1179 ), 1180 array( 1181 'site_id' => $same_domain, 1182 'add' => false, 1183 ), 1184 array( 1185 'site_id' => $same_path, 1186 'add' => false, 1187 ), 1188 array( 1189 'site_id' => $same_network_id, 1190 'add' => false, 1191 ), 1192 array( 1193 'site_id' => $same_domain_network_id, 1194 'add' => true, 1195 ), 1196 array( 1197 'site_id' => $same_path_network_id, 1198 'add' => false, 1199 ), 1200 array( 1201 'site_id' => $same_domain_path_network_id, 1202 'add' => true, 1203 ), 1204 ), 1205 ), 1206 1207 // Query by path and network ID. 1208 array( 1209 'query_vars' => array( 1210 'path' => $base_path, 1211 'network_id' => $base_network_id, 1212 ), 1213 'comparisons' => array( 1214 array( 1215 'site_id' => $all_different, 1216 'add' => false, 1217 ), 1218 array( 1219 'site_id' => $same_domain, 1220 'add' => false, 1221 ), 1222 array( 1223 'site_id' => $same_path, 1224 'add' => false, 1225 ), 1226 array( 1227 'site_id' => $same_network_id, 1228 'add' => false, 1229 ), 1230 array( 1231 'site_id' => $same_domain_network_id, 1232 'add' => false, 1233 ), 1234 array( 1235 'site_id' => $same_path_network_id, 1236 'add' => true, 1237 ), 1238 array( 1239 'site_id' => $same_domain_path_network_id, 1240 'add' => true, 1241 ), 1242 ), 1243 ), 1244 1245 // Query by domain, path and network ID. 1246 array( 1247 'query_vars' => array( 1248 'domain' => $base_domain, 1249 'path' => $base_path, 1250 'network_id' => $base_network_id, 1251 ), 1252 'comparisons' => array( 1253 array( 1254 'site_id' => $all_different, 1255 'add' => false, 1256 ), 1257 array( 1258 'site_id' => $same_domain, 1259 'add' => false, 1260 ), 1261 array( 1262 'site_id' => $same_path, 1263 'add' => false, 1264 ), 1265 array( 1266 'site_id' => $same_network_id, 1267 'add' => false, 1268 ), 1269 array( 1270 'site_id' => $same_domain_network_id, 1271 'add' => false, 1272 ), 1273 array( 1274 'site_id' => $same_path_network_id, 1275 'add' => false, 1276 ), 1277 array( 1278 'site_id' => $same_domain_path_network_id, 1279 'add' => true, 1280 ), 1281 ), 1282 ), 1283 ); 1284 1285 foreach ( $comparison_sets as $comparison_set ) { 1286 $query_vars = array_merge( $base_data_set['query_vars'], $comparison_set['query_vars'] ); 1287 1288 foreach ( $comparison_set['comparisons'] as $comparison ) { 1289 $test_data[] = array( 1290 $query_vars, 1291 $comparison['site_id'], 1292 $base_data_set['update_data'], 1293 $comparison['add'], 1294 ); 1295 } 1296 } 1297 } 1298 1299 return $test_data; 1300 } 1301 1302 private function set_last_changed( $blog, $current_time ) { 1303 /* 1304 This function is essentially a copy of the respective code part in `clean_blog_cache()`. 1305 It allows to set the last_changed values for a site to a specific time. 1306 */ 1307 1308 // The following arguments are relevant for a special 'last_changed' prefix. 1309 $last_changed_args = array( 1310 'domain' => $blog->domain, 1311 'path' => $blog->path, 1312 'network_id' => $blog->site_id, 1313 ); 1314 1315 $last_changed_prefixes = array( '' ); 1316 1317 // Generate all possible variations. 1318 $combinations = array( array() ); 1319 foreach ( $last_changed_args as $key => $value ) { 1320 $value = (string) $value; 1321 1322 foreach ( $combinations as $combination ) { 1323 $current_args = array_merge( $combination, array( $key => $value ) ); 1324 $last_changed_prefixes[] = md5( serialize( $current_args ) ) . '_'; 1325 1326 $combinations[] = $current_args; 1327 } 1328 } 1329 1330 foreach ( $last_changed_prefixes as $last_changed_prefix ) { 1331 wp_cache_set( $last_changed_prefix . 'last_changed', $current_time, 'sites' ); 1332 } 1333 } 881 1334 } 882 1335 883 1336 endif;