WordPress.org

Make WordPress Core

Changeset 49212


Ignore:
Timestamp:
10/19/2020 09:49:58 PM (13 months ago)
Author:
helen
Message:

Multisite: More specific caching for get_dirsize.

Instead of one cache entry for all upload folders for a site on multisite, this now caches for each folder and invalidates that cache based on context. In multisite, this should speed up get_dirsize calls since older directories that are much less likely to change will no longer have the size recalculated.

Props janthiel, A5hleyRich, batmoo.
Fixes #19879.

Location:
trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r49193 r49212  
    929929
    930930    if ( is_multisite() ) {
    931         delete_transient( 'dirsize_cache' );
     931        invalidate_dirsize_cache( $new_file );
    932932    }
    933933
  • trunk/src/wp-includes/functions.php

    r49193 r49212  
    27402740    // Compute the URL.
    27412741    $url = $upload['url'] . "/$filename";
     2742
     2743    if ( is_multisite() ) {
     2744        invalidate_dirsize_cache( $new_file );
     2745    }
    27422746
    27432747    /** This filter is documented in wp-admin/includes/file.php */
     
    75617565 */
    75627566function get_dirsize( $directory, $max_execution_time = null ) {
    7563     $dirsize = get_transient( 'dirsize_cache' );
    7564 
    7565     if ( is_array( $dirsize ) && isset( $dirsize[ $directory ]['size'] ) ) {
    7566         return $dirsize[ $directory ]['size'];
    7567     }
    7568 
    7569     if ( ! is_array( $dirsize ) ) {
    7570         $dirsize = array();
    7571     }
    75727567
    75737568    // Exclude individual site directories from the total when checking the main site of a network,
    75747569    // as they are subdirectories and should not be counted.
    75757570    if ( is_multisite() && is_main_site() ) {
    7576         $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
     7571        $size = recurse_dirsize( $directory, $directory . '/sites', $max_execution_time );
    75777572    } else {
    7578         $dirsize[ $directory ]['size'] = recurse_dirsize( $directory, null, $max_execution_time );
    7579     }
    7580 
    7581     set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
    7582     return $dirsize[ $directory ]['size'];
     7573        $size = recurse_dirsize( $directory, null, $max_execution_time );
     7574    }
     7575
     7576    return $size;
    75837577}
    75847578
     
    75927586 * @since 4.3.0 $exclude parameter added.
    75937587 * @since 5.2.0 $max_execution_time parameter added.
     7588 * @since 5.6.0 $directory_cache parameter added.
    75947589 *
    75957590 * @param string       $directory          Full path of a directory.
     
    75987593 * @param int          $max_execution_time Maximum time to run before giving up. In seconds. The timeout is global
    75997594 *                                         and is measured from the moment WordPress started to load.
     7595 * @param array        $directory_cache    Optional. Array of cached directory paths.
     7596 *
    76007597 * @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
    76017598 */
    7602 function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null ) {
     7599function recurse_dirsize( $directory, $exclude = null, $max_execution_time = null, &$directory_cache = null ) {
    76037600    $size = 0;
    76047601
    76057602    $directory = untrailingslashit( $directory );
     7603    $cache_path = normalize_dirsize_cache_path( $directory );
     7604    $save_cache = false;
     7605
     7606    if ( ! isset( $directory_cache ) ) {
     7607        $directory_cache = get_transient( 'dirsize_cache' );
     7608        $save_cache      = true;
     7609    }
     7610
     7611    if ( isset( $directory_cache[ $cache_path ] ) ) {
     7612        return $directory_cache[ $cache_path ];
     7613    }
    76067614
    76077615    if ( ! file_exists( $directory ) || ! is_dir( $directory ) || ! is_readable( $directory ) ) {
     
    76317639    }
    76327640
    7633     $handle = opendir( $directory );
    7634     if ( $handle ) {
    7635         while ( ( $file = readdir( $handle ) ) !== false ) {
    7636             $path = $directory . '/' . $file;
    7637             if ( '.' !== $file && '..' !== $file ) {
    7638                 if ( is_file( $path ) ) {
    7639                     $size += filesize( $path );
    7640                 } elseif ( is_dir( $path ) ) {
    7641                     $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time );
    7642                     if ( $handlesize > 0 ) {
    7643                         $size += $handlesize;
     7641    /**
     7642    * Filters the amount of storage space used by one directory and all it's children, in megabytes.
     7643    * Return the actual used space to shortcircuit the recursive PHP file size calculation and use something else
     7644    * like a CDN API or native operating system tools for better performance
     7645    *
     7646    * @since 5.6.0
     7647    *
     7648    * @param int|false $space_used The amount of used space, in bytes. Default 0.
     7649    */
     7650    $size = apply_filters( 'calculate_current_dirsize', $size, $directory, $exclude, $max_execution_time, $directory_cache );
     7651
     7652    if ( 0 === $size ) {
     7653        $handle = opendir( $directory );
     7654        if ( $handle ) {
     7655            while ( ( $file = readdir( $handle ) ) !== false ) {
     7656                $path = $directory . '/' . $file;
     7657                if ( '.' !== $file && '..' !== $file ) {
     7658                    if ( is_file( $path ) ) {
     7659                        $size += filesize( $path );
     7660                    } elseif ( is_dir( $path ) ) {
     7661                        $handlesize = recurse_dirsize( $path, $exclude, $max_execution_time, $directory_cache );
     7662                        if ( $handlesize > 0 ) {
     7663                            $size += $handlesize;
     7664                        }
     7665                    }
     7666
     7667                    if ( $max_execution_time > 0 && microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) {
     7668                        // Time exceeded. Give up instead of risking a fatal timeout.
     7669                        $size = null;
     7670                        break;
    76447671                    }
    76457672                }
    7646 
    7647                 if ( $max_execution_time > 0 && microtime( true ) - WP_START_TIMESTAMP > $max_execution_time ) {
    7648                     // Time exceeded. Give up instead of risking a fatal timeout.
    7649                     $size = null;
    7650                     break;
    7651                 }
    76527673            }
    7653         }
    7654         closedir( $handle );
    7655     }
     7674            closedir( $handle );
     7675        }
     7676    }
     7677    $directory_cache[ $cache_path ] = $size;
     7678
     7679    // Only write the transient on the top level call and not on recursive calls
     7680    if ( $save_cache ) {
     7681        set_transient( 'dirsize_cache', $directory_cache );
     7682    }
     7683
    76567684    return $size;
     7685}
     7686
     7687/**
     7688 * Invalidates entries within the dirsize_cache
     7689 *
     7690 * Remove the current directory and all parent directories
     7691 * from the dirsize_cache transient.
     7692 *
     7693 * @since 5.6.0
     7694 *
     7695 * @param string $path Full path of a directory or file.
     7696 */
     7697function invalidate_dirsize_cache( $path ) {
     7698    $directory_cache = get_transient( 'dirsize_cache' );
     7699
     7700    if ( empty( $directory_cache ) ) {
     7701        return;
     7702    }
     7703
     7704    $cache_path = normalize_dirsize_cache_path( $path );
     7705    unset( $directory_cache[ $cache_path ] );
     7706
     7707    while ( DIRECTORY_SEPARATOR !== $cache_path && '.' !== $cache_path && '..' !== $cache_path ) {
     7708        $cache_path = dirname( $cache_path );
     7709        unset( $directory_cache[ $cache_path ] );
     7710    }
     7711
     7712    set_transient( 'dirsize_cache', $directory_cache );
     7713}
     7714
     7715/**
     7716 * Normalize dirsize cache path.
     7717 *
     7718 * Ensures array keys within the dirsize_cache transient follow the same format.
     7719 *
     7720 * @since 5.6.0
     7721 *
     7722 * @param string $path
     7723 * @return string
     7724 */
     7725function normalize_dirsize_cache_path( $path ) {
     7726    $path = str_replace( ABSPATH, '', $path );
     7727
     7728    return untrailingslashit( $path );
    76577729}
    76587730
  • trunk/src/wp-includes/post.php

    r49193 r49212  
    59155915
    59165916    if ( is_multisite() ) {
    5917         delete_transient( 'dirsize_cache' );
     5917        invalidate_dirsize_cache( $file );
    59185918    }
    59195919
Note: See TracChangeset for help on using the changeset viewer.