*/
private $mExtensionData = [];
- /** @var array $mLimitReportData Parser limit report data. */
+ /**
+ * @var array $mLimitReportData Parser limit report data.
+ */
private $mLimitReportData = [];
/**
/** @var integer|null Assumed rev ID for {{REVISIONID}} if no revision is set */
private $mSpeculativeRevId;
+ /** @var integer Upper bound of expiry based on parse duration */
+ private $mMaxAdaptiveExpiry = INF;
+
const EDITSECTION_REGEX =
'#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#';
+ // finalizeAdaptiveCacheExpiry() uses TTL = MAX( m * PARSE_TIME + b, MIN_AR_TTL)
+ // Current values imply that m=3933.333333 and b=-333.333333
+ // See https://www.nngroup.com/articles/website-response-times/
+ const PARSE_FAST_SEC = .100; // perceived "fast" page parse
+ const PARSE_SLOW_SEC = 1.0; // perceived "slow" page parse
+ const FAST_AR_TTL = 60; // adaptive TTL for "fast" pages
+ const SLOW_AR_TTL = 3600; // adaptive TTL for "slow" pages
+ const MIN_AR_TTL = 15; // min adaptive TTL (for sanity, pool counter, and edit stashing)
+
public function __construct( $text = '', $languageLinks = [], $categoryLinks = [],
$unused = false, $titletext = ''
) {
/**
* Sets parser limit report data for a key
*
- * If $value consist of a list of two floats, it will be interpreted as
- * (actual value, maximum allowed value). The presence of a "-" in $key will cause
- * the first part of the key to be interpreted as a namespace.
+ * The key is used as the prefix for various messages used for formatting:
+ * - $key: The label for the field in the limit report
+ * - $key-value-text: Message used to format the value in the "NewPP limit
+ * report" HTML comment. If missing, uses $key-format.
+ * - $key-value-html: Message used to format the value in the preview
+ * limit report table. If missing, uses $key-format.
+ * - $key-value: Message used to format the value. If missing, uses "$1".
+ *
+ * Note that all values are interpreted as wikitext, and so should be
+ * encoded with htmlspecialchars() as necessary, but should avoid complex
+ * HTML for sanity of display in the "NewPP limit report" comment.
*
* @since 1.22
- * @param string $key Data key
- * @param mixed $value Data value One of (float, string, bool, JSON serializable array)
+ * @param string $key Message key
+ * @param mixed $value Appropriate for Message::params()
*/
public function setLimitReportData( $key, $value ) {
- if ( is_array( $value ) ) {
- if ( array_keys( $value ) === [ 0, 1 ]
- && is_numeric( $value[0] )
- && is_numeric( $value[1] )
- ) {
- $data = [ 'value' => $value[0], 'limit' => $value[1] ];
- } else {
- $data = $value;
- }
- } else {
- $data = $value;
- }
-
- if ( strpos( $key, '-' ) ) {
- list( $ns, $name ) = explode( '-', $key, 2 );
- $this->mLimitReportData[$ns][$name] = $data;
- } else {
- $this->mLimitReportData[$key] = $data;
- }
+ $this->mLimitReportData[$key] = $value;
}
/**
}
/**
- * Save space for serialization by removing useless values
- * @return array
+ * Lower the runtime adaptive TTL to at most this value
+ *
+ * @param integer $ttl
+ * @since 1.28
*/
+ public function updateRuntimeAdaptiveExpiry( $ttl ) {
+ $this->mMaxAdaptiveExpiry = min( $ttl, $this->mMaxAdaptiveExpiry );
+ $this->updateCacheExpiry( $ttl );
+ }
+
+ /**
+ * Call this when parsing is done to lower the TTL based on low parse times
+ *
+ * @since 1.28
+ */
+ public function finalizeAdaptiveCacheExpiry() {
+ if ( is_infinite( $this->mMaxAdaptiveExpiry ) ) {
+ return; // not set
+ }
+
+ $runtime = $this->getTimeSinceStart( 'wall' );
+ if ( is_float( $runtime ) ) {
+ $slope = ( self::SLOW_AR_TTL - self::FAST_AR_TTL )
+ / ( self::PARSE_SLOW_SEC - self::PARSE_FAST_SEC );
+ // SLOW_AR_TTL = PARSE_SLOW_SEC * $slope + $point
+ $point = self::SLOW_AR_TTL - self::PARSE_SLOW_SEC * $slope;
+
+ $adaptiveTTL = min(
+ max( $slope * $runtime + $point, self::MIN_AR_TTL ),
+ $this->mMaxAdaptiveExpiry
+ );
+ $this->updateCacheExpiry( $adaptiveTTL );
+ }
+ }
+
public function __sleep() {
return array_diff(
array_keys( get_object_vars( $this ) ),