Make WordPress Core

Changeset 44129


Ignore:
Timestamp:
12/14/2018 01:03:51 AM (7 years ago)
Author:
pento
Message:

Revisions: Improve performance of WP_Text_Diff_Renderer_Table.

WP_Text_Diff_Renderer_Table is used to generate the diff view in revisions, but there were some cases that could cause it to take excessive amounts of time to run.

Some noteable cases include:

  • When a large number of new lines were inserted in the middle of the post from one revision to the next.
  • When both revisions contain >100 lines.
  • When either revision contains a lot of long lines.

In one extreme test case, the diff view took over a minute to generate. With this change, it now takes less than a second.

Merges [43775] from the 5.0 branch to trunk.

Fixes #35667.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/wp-includes/class-wp-text-diff-renderer-table.php

    r42343 r44129  
    5555
    5656    protected $compat_fields = array( '_show_split_view', 'inline_diff_renderer', '_diff_threshold' );
     57
     58    /**
     59     * Caches the output of count_chars() in compute_string_distance()
     60     *
     61     * @var array
     62     * @since 5.0.0
     63     */
     64    protected $count_cache = array();
     65
     66    /**
     67     * Caches the difference calculation in compute_string_distance()
     68     *
     69     * @var array
     70     * @since 5.0.0
     71     */
     72    protected $difference_cache = array();
    5773
    5874    /**
     
    397413                array_splice( $final_rows, $orig_pos, 0, -1 );
    398414            } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows.
    399                 $diff_pos = $final_pos - $orig_pos;
    400                 while ( $diff_pos < 0 ) {
    401                     array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
    402                 }
     415                $diff_array = range( -1, $final_pos - $orig_pos );
     416                array_splice( $final_rows, $orig_pos, 0, $diff_array );
    403417            } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows.
    404                 $diff_pos = $orig_pos - $final_pos;
    405                 while ( $diff_pos < 0 ) {
    406                     array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
    407                 }
     418                $diff_array = range( -1, $orig_pos - $final_pos );
     419                array_splice( $orig_rows, $orig_pos, 0, $diff_array );
    408420            }
    409421        }
     
    435447     */
    436448    public function compute_string_distance( $string1, $string2 ) {
    437         // Vectors containing character frequency for all chars in each string
    438         $chars1 = count_chars( $string1 );
    439         $chars2 = count_chars( $string2 );
    440 
    441         // L1-norm of difference vector.
    442         $difference = array_sum( array_map( array( $this, 'difference' ), $chars1, $chars2 ) );
     449        // Use an md5 hash of the strings for a count cache, as it's fast to generate, and collisions aren't a concern.
     450        $count_key1 = md5( $string1 );
     451        $count_key2 = md5( $string2 );
     452
     453        // Cache vectors containing character frequency for all chars in each string.
     454        if ( ! isset( $this->count_cache[ $count_key1 ] ) ) {
     455            $this->count_cache[ $count_key1 ] = count_chars( $string1 );
     456        }
     457        if ( ! isset( $this->count_cache[ $count_key2 ] ) ) {
     458            $this->count_cache[ $count_key2 ] = count_chars( $string2 );
     459        }
     460
     461        $chars1 = $this->count_cache[ $count_key1 ];
     462        $chars2 = $this->count_cache[ $count_key2 ];
     463
     464        $difference_key = md5( implode( ',', $chars1 ) . ':' . implode( ',', $chars2 ) );
     465        if ( ! isset( $this->difference_cache[ $difference_key ] ) ) {
     466            // L1-norm of difference vector.
     467            $this->difference_cache[ $difference_key ] = array_sum( array_map( array( $this, 'difference' ), $chars1, $chars2 ) );
     468        }
     469
     470        $difference = $this->difference_cache[ $difference_key ];
    443471
    444472        // $string1 has zero length? Odd. Give huge penalty by not dividing.
Note: See TracChangeset for help on using the changeset viewer.