Skip to content

Commit c70a033

Browse files
committed
Merge pull request #104 from nacin/speed
Performance improvements and various fixes
2 parents 2ac65c9 + f0ab2b0 commit c70a033

File tree

2 files changed

+108
-47
lines changed

2 files changed

+108
-47
lines changed

lib/class-command.php

+21-1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ protected function _get_phpdoc_data( $path, $format = 'json' ) {
139139
* @param bool $import_internal_functions Optional; defaults to false. If true, functions marked @internal will be imported.
140140
*/
141141
protected function _do_import( array $data, $skip_sleep = false, $import_internal_functions = false ) {
142+
global $wpdb;
143+
144+
$time_start = microtime(true);
145+
$num_queries = $wpdb->num_queries;
142146

143147
// Make sure a current user is set
144148
if ( ! wp_get_current_user()->exists() ) {
@@ -151,10 +155,17 @@ protected function _do_import( array $data, $skip_sleep = false, $import_interna
151155
$file_number = 1;
152156
$num_of_files = count( $data );
153157

158+
do_action( 'wp_parser_starting_import' );
159+
154160
// Defer term counting for performance
161+
wp_suspend_cache_invalidation( true );
155162
wp_defer_term_counting( true );
156163
wp_defer_comment_counting( true );
157164

165+
// Remove actions for performance
166+
remove_action( 'transition_post_status', '_update_blog_date_on_post_publish', 10 );
167+
remove_action( 'transition_post_status', '__clear_multi_author_cache', 10 );
168+
158169
// Run the importer
159170
$importer = new Importer;
160171

@@ -171,7 +182,7 @@ protected function _do_import( array $data, $skip_sleep = false, $import_interna
171182
}
172183

173184
foreach ( $data as $file ) {
174-
WP_CLI::line( sprintf( 'Processing file %1$s of %2$s.', number_format_i18n( $file_number ), number_format_i18n( $num_of_files ) ) );
185+
WP_CLI::line( sprintf( 'Processing file %1$s of %2$s "%3$s".', number_format_i18n( $file_number ), number_format_i18n( $num_of_files ), $file['path'] ) );
175186
$file_number ++;
176187

177188
$importer->import_file( $file, $skip_sleep, $import_internal_functions );
@@ -188,8 +199,17 @@ protected function _do_import( array $data, $skip_sleep = false, $import_interna
188199

189200
// Start counting again
190201
wp_defer_term_counting( false );
202+
wp_suspend_cache_invalidation( false );
203+
wp_cache_flush();
191204
wp_defer_comment_counting( false );
192205

206+
do_action( 'wp_parser_ending_import' );
207+
208+
$time_end = microtime(true);
209+
$time = $time_end - $time_start;
210+
211+
WP_CLI::line( 'Time: '.$time );
212+
WP_CLI::line( 'Queries: ' . ( $wpdb->num_queries - $num_queries ) );
193213
if ( empty( $importer->errors ) ) {
194214
WP_CLI::success( 'Import complete!' );
195215

lib/class-importer.php

+87-46
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class Importer {
7070
*/
7171
public $errors = array();
7272

73+
/**
74+
* @var array Cached items of inserted terms
75+
*/
76+
protected $inserted_terms = array();
7377

7478
/**
7579
* Constructor. Sets up post type/taxonomy names.
@@ -96,6 +100,23 @@ public function __construct( array $args = array() ) {
96100
}
97101
}
98102

103+
protected function insert_term( $term, $taxonomy, $args = array() ) {
104+
if ( isset( $this->inserted_terms[ $taxonomy ][ $term ] ) ) {
105+
return $this->inserted_terms[ $taxonomy ][ $term ];
106+
}
107+
108+
$parent = isset( $args['parent'] ) ? $args['parent'] : 0;
109+
if ( ! $inserted_term = term_exists( $term, $taxonomy, $parent ) ) {
110+
$inserted_term = wp_insert_term( $term, $taxonomy, $args );
111+
}
112+
113+
if ( ! is_wp_error( $inserted_term ) ) {
114+
$this->inserted_terms[ $taxonomy ][ $term ] = $inserted_term;
115+
}
116+
117+
return $inserted_term;
118+
}
119+
99120
/**
100121
* For a specific file, go through and import the file, functions, and classes.
101122
*
@@ -107,26 +128,18 @@ public function import_file( array $file, $skip_sleep = false, $import_internal
107128

108129
// Maybe add this file to the file taxonomy
109130
$slug = sanitize_title( str_replace( '/', '_', $file['path'] ) );
110-
$term = get_term_by( 'slug', $slug, $this->taxonomy_file, ARRAY_A );
111-
112-
if ( ! $term ) {
113-
114-
$term = wp_insert_term( $file['path'], $this->taxonomy_file, array( 'slug' => $slug ) );
115131

116-
if ( is_wp_error( $term ) ) {
117-
$this->errors[] = sprintf( 'Problem creating file tax item "%1$s" for %2$s: %3$s', $slug, $file['path'], $term->get_error_message() );
118-
119-
return;
120-
}
132+
$term = $this->insert_term( $file['path'], $this->taxonomy_file, array( 'slug' => $slug ) );
121133

122-
// Grab the full term object
123-
$term = get_term_by( 'slug', $slug, $this->taxonomy_file, ARRAY_A );
134+
if ( is_wp_error( $term ) ) {
135+
$this->errors[] = sprintf( 'Problem creating file tax item "%1$s" for %2$s: %3$s', $slug, $file['path'], $term->get_error_message() );
136+
return;
124137
}
125138

126139
// Store file meta for later use
127140
$this->file_meta = array(
128141
'docblock' => $file['file'], // File docblock
129-
'term_id' => $term['name'], // File's term item in the file taxonomy
142+
'term_id' => $file['path'], // Term name in the file taxonomy is the file name
130143
);
131144

132145
// Functions
@@ -201,6 +214,14 @@ public function import_function( array $data, $parent_post_id = 0, $import_inter
201214
* @return bool|int Post ID of this hook, false if any failure.
202215
*/
203216
public function import_hook( array $data, $parent_post_id = 0, $import_internal = false ) {
217+
if ( 0 === strpos( $data['doc']['description'], 'This action is documented in' ) ) {
218+
return false;
219+
} elseif ( 0 === strpos( $data['doc']['description'], 'This filter is documented in' ) ) {
220+
return false;
221+
} elseif ( '' === $data['doc']['description'] && '' === $data['doc']['long_description'] ) {
222+
return false;
223+
}
224+
204225
$hook_id = $this->import_item( $data, $parent_post_id, $import_internal, array( 'post_type' => $this->post_type_hook ) );
205226

206227
if ( ! $hook_id ) {
@@ -230,16 +251,16 @@ protected function import_class( array $data, $import_internal = false ) {
230251
}
231252

232253
// Set class-specific meta
233-
update_post_meta( $class_id, '_wp-parser_final', (bool) $data['final'] );
234-
update_post_meta( $class_id, '_wp-parser_abstract', (bool) $data['abstract'] );
254+
update_post_meta( $class_id, '_wp-parser_final', (string) $data['final'] );
255+
update_post_meta( $class_id, '_wp-parser_abstract', (string) $data['abstract'] );
235256
update_post_meta( $class_id, '_wp-parser_extends', $data['extends'] );
236257
update_post_meta( $class_id, '_wp-parser_implements', $data['implements'] );
237258
update_post_meta( $class_id, '_wp-parser_properties', $data['properties'] );
238259

239260
// Now add the methods
240261
foreach ( $data['methods'] as $method ) {
241262
// Namespace method names with the class name
242-
$method['name'] = $data['name'] . '-' . $method['name'];
263+
$method['name'] = $data['name'] . '::' . $method['name'];
243264
$this->import_method( $method, $class_id, $import_internal );
244265
}
245266

@@ -266,9 +287,9 @@ protected function import_method( array $data, $parent_post_id = 0, $import_inte
266287
}
267288

268289
// Set method-specific meta.
269-
update_post_meta( $method_id, '_wp-parser_final', (bool) $data['final'] );
270-
update_post_meta( $method_id, '_wp-parser_abstract', (bool) $data['abstract'] );
271-
update_post_meta( $method_id, '_wp-parser_static', (bool) $data['static'] );
290+
update_post_meta( $method_id, '_wp-parser_final', (string) $data['final'] );
291+
update_post_meta( $method_id, '_wp-parser_abstract', (string) $data['abstract'] );
292+
update_post_meta( $method_id, '_wp-parser_static', (string) $data['static'] );
272293
update_post_meta( $method_id, '_wp-parser_visibility', $data['visibility'] );
273294

274295
// Now add the hooks.
@@ -323,6 +344,10 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
323344
return false;
324345
}
325346

347+
if ( wp_list_filter( $data['doc']['tags'], array( 'name' => 'ignore' ) ) ) {
348+
return false;
349+
}
350+
326351
$is_new_post = true;
327352
$slug = sanitize_title( $data['name'] );
328353
$post_data = wp_parse_args(
@@ -340,9 +365,9 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
340365

341366
// Look for an existing post for this item
342367
$existing_post_id = $wpdb->get_var(
343-
$wpdb->prepare(
344-
"SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = %s AND post_parent = %d LIMIT 1",
345-
$data['name'],
368+
$q = $wpdb->prepare(
369+
"SELECT ID FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND post_parent = %d LIMIT 1",
370+
$slug,
346371
$post_data['post_type'],
347372
(int) $parent_post_id
348373
)
@@ -351,12 +376,15 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
351376
// Insert/update the item post
352377
if ( ! empty( $existing_post_id ) ) {
353378
$is_new_post = false;
354-
$post_data['ID'] = (int) $existing_post_id;
355-
$ID = wp_update_post( $post_data, true );
356-
379+
$ID = $post_data['ID'] = (int) $existing_post_id;
380+
$post_needed_update = array_diff_assoc( sanitize_post( $post_data, 'db' ), get_post( $existing_post_id, ARRAY_A, 'db' ) );
381+
if ( $post_needed_update ) {
382+
$ID = wp_update_post( wp_slash( $post_data ), true );
383+
}
357384
} else {
358-
$ID = wp_insert_post( $post_data, true );
385+
$ID = wp_insert_post( wp_slash( $post_data ), true );
359386
}
387+
$anything_updated = array();
360388

361389
if ( ! $ID || is_wp_error( $ID ) ) {
362390

@@ -387,15 +415,16 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
387415

388416
$since_version = array_shift( $since_version );
389417
$since_version = $since_version['content'];
390-
$since_term = term_exists( $since_version, $this->taxonomy_since_version );
391418

392-
if ( ! $since_term ) {
393-
$since_term = wp_insert_term( $since_version, $this->taxonomy_since_version );
394-
}
419+
$since_term = $this->insert_term( $since_version, $this->taxonomy_since_version );
395420

396421
// Assign the tax item to the post
397422
if ( ! is_wp_error( $since_term ) ) {
423+
$added_term_relationship = did_action( 'added_term_relationship' );
398424
wp_set_object_terms( $ID, (int) $since_term['term_id'], $this->taxonomy_since_version );
425+
if ( did_action( 'added_term_relationship' ) > $added_term_relationship ) {
426+
$anything_updated[] = true;
427+
}
399428
} else {
400429
WP_CLI::warning( "\tCannot set @since term: " . $since_term->get_error_message() );
401430
}
@@ -416,7 +445,7 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
416445
}
417446

418447
$main_package_id = false;
419-
$package_term_args = array();
448+
$package_term_ids = array();
420449

421450
// If the item has any @package/@subpackage markup (or has inherited it from file scope), assign the taxonomy.
422451
foreach ( $packages as $pack_name => $pack_value ) {
@@ -436,33 +465,45 @@ public function import_item( array $data, $parent_post_id = 0, $import_internal
436465
}
437466

438467
// If the package doesn't already exist in the taxonomy, add it
439-
$package_term = term_exists( $pack_value, $this->taxonomy_package, $package_term_args['parent'] );
440-
if ( ! $package_term ) {
441-
$package_term = wp_insert_term( $pack_value, $this->taxonomy_package, $package_term_args );
442-
}
468+
$package_term = $this->insert_term( $pack_value, $this->taxonomy_package, $package_term_args );
469+
$package_term_ids[] = (int) $package_term['term_id'];
443470

444471
if ( $pack_name === 'main' && $main_package_id === false && ! is_wp_error( $package_term ) ) {
445472
$main_package_id = (int) $package_term['term_id'];
446473
}
447474

448-
// Assign the tax item to the post
449-
if ( ! is_wp_error( $package_term ) ) {
450-
wp_set_object_terms( $ID, (int) $package_term['term_id'], $this->taxonomy_package );
451-
} elseif ( is_int( $main_package_id ) ) {
452-
WP_CLI::warning( "\tCannot set @subpackage term: " . $package_term->get_error_message() );
453-
} else {
454-
WP_CLI::warning( "\tCannot set @package term: " . $package_term->get_error_message() );
475+
if ( is_wp_error( $package_term ) ) {
476+
if ( is_int( $main_package_id ) ) {
477+
WP_CLI::warning( "\tCannot create @subpackage term: " . $package_term->get_error_message() );
478+
} else {
479+
WP_CLI::warning( "\tCannot create @package term: " . $package_term->get_error_message() );
480+
}
455481
}
456482
}
483+
$added_term_relationship = did_action( 'added_term_relationship' );
484+
wp_set_object_terms( $ID, $package_term_ids, $this->taxonomy_package );
485+
if ( did_action( 'added_term_relationship' ) > $added_term_relationship ) {
486+
$anything_updated[] = true;
487+
}
457488

458489
// Set other taxonomy and post meta to use in the theme templates
490+
$added_item = did_action( 'added_term_relationship' );
459491
wp_set_object_terms( $ID, $this->file_meta['term_id'], $this->taxonomy_file );
492+
if ( did_action( 'added_term_relationship' ) > $added_item ) {
493+
$anything_updated[] = true;
494+
}
495+
460496
if ( $post_data['post_type'] !== $this->post_type_class ) {
461-
update_post_meta( $ID, '_wp-parser_args', $data['arguments'] );
497+
$anything_updated[] = update_post_meta( $ID, '_wp-parser_args', $data['arguments'] );
498+
}
499+
$anything_updated[] = update_post_meta( $ID, '_wp-parser_line_num', (string) $data['line'] );
500+
$anything_updated[] = update_post_meta( $ID, '_wp-parser_end_line_num', (string) $data['end_line'] );
501+
$anything_updated[] = update_post_meta( $ID, '_wp-parser_tags', $data['doc']['tags'] );
502+
503+
// If the post didn't need to be updated, but meta or tax changed, update it to bump last modified.
504+
if ( ! $is_new_post && ! $post_needed_update && array_filter( $anything_updated ) ) {
505+
wp_update_post( wp_slash( $post_data ), true );
462506
}
463-
update_post_meta( $ID, '_wp-parser_line_num', $data['line'] );
464-
update_post_meta( $ID, '_wp-parser_end_line_num', $data['end_line'] );
465-
update_post_meta( $ID, '_wp-parser_tags', $data['doc']['tags'] );
466507

467508
// Everything worked! Woo hoo!
468509
if ( $is_new_post ) {

0 commit comments

Comments
 (0)