Merge "Introduce ApiMaxLagInfo hook"
[lhc/web/wiklou.git] / includes / libs / rdbms / lbfactory / LBFactory.php
index 097775a..52c2df7 100644 (file)
@@ -110,43 +110,34 @@ abstract class LBFactory implements ILBFactory {
                        $this->readOnlyReason = $conf['readOnlyReason'];
                }
 
-               $this->srvCache = isset( $conf['srvCache'] ) ? $conf['srvCache'] : new EmptyBagOStuff();
-               $this->memStash = isset( $conf['memStash'] ) ? $conf['memStash'] : new EmptyBagOStuff();
-               $this->wanCache = isset( $conf['wanCache'] )
-                       ? $conf['wanCache']
-                       : WANObjectCache::newEmpty();
+               $this->srvCache = $conf['srvCache'] ?? new EmptyBagOStuff();
+               $this->memStash = $conf['memStash'] ?? new EmptyBagOStuff();
+               $this->wanCache = $conf['wanCache'] ?? WANObjectCache::newEmpty();
 
                foreach ( self::$loggerFields as $key ) {
-                       $this->$key = isset( $conf[$key] ) ? $conf[$key] : new \Psr\Log\NullLogger();
+                       $this->$key = $conf[$key] ?? new \Psr\Log\NullLogger();
                }
-               $this->errorLogger = isset( $conf['errorLogger'] )
-                       ? $conf['errorLogger']
-                       : function ( Exception $e ) {
-                               trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
-                       };
-               $this->deprecationLogger = isset( $conf['deprecationLogger'] )
-                       ? $conf['deprecationLogger']
-                       : function ( $msg ) {
-                               trigger_error( $msg, E_USER_DEPRECATED );
-                       };
-
-               $this->profiler = isset( $conf['profiler'] ) ? $conf['profiler'] : null;
-               $this->trxProfiler = isset( $conf['trxProfiler'] )
-                       ? $conf['trxProfiler']
-                       : new TransactionProfiler();
+               $this->errorLogger = $conf['errorLogger'] ?? function ( Exception $e ) {
+                       trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
+               };
+               $this->deprecationLogger = $conf['deprecationLogger'] ?? function ( $msg ) {
+                       trigger_error( $msg, E_USER_DEPRECATED );
+               };
+
+               $this->profiler = $conf['profiler'] ?? null;
+               $this->trxProfiler = $conf['trxProfiler'] ?? new TransactionProfiler();
 
                $this->requestInfo = [
-                       'IPAddress' => isset( $_SERVER[ 'REMOTE_ADDR' ] ) ? $_SERVER[ 'REMOTE_ADDR' ] : '',
-                       'UserAgent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '',
-                       'ChronologyProtection' => 'true',
-                       'ChronologyPositionIndex' => isset( $_GET['cpPosIndex'] ) ? $_GET['cpPosIndex'] : null
+                       'IPAddress' => $_SERVER[ 'REMOTE_ADDR' ] ?? '',
+                       'UserAgent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
+                       // Headers application can inject via LBFactory::setRequestInfo()
+                       'ChronologyClientId' => null, // prior $cpClientId value from LBFactory::shutdown()
+                       'ChronologyPositionIndex' => null // prior $cpIndex value from LBFactory::shutdown()
                ];
 
-               $this->cliMode = isset( $conf['cliMode'] )
-                       ? $conf['cliMode']
-                       : ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
-               $this->hostname = isset( $conf['hostname'] ) ? $conf['hostname'] : gethostname();
-               $this->agent = isset( $conf['agent'] ) ? $conf['agent'] : '';
+               $this->cliMode = $conf['cliMode'] ?? ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
+               $this->hostname = $conf['hostname'] ?? gethostname();
+               $this->agent = $conf['agent'] ?? '';
 
                $this->ticket = mt_rand();
        }
@@ -157,7 +148,10 @@ abstract class LBFactory implements ILBFactory {
        }
 
        public function shutdown(
-               $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback = null, &$cpIndex = null
+               $mode = self::SHUTDOWN_CHRONPROT_SYNC,
+               callable $workCallback = null,
+               &$cpIndex = null,
+               &$cpClientId = null
        ) {
                $chronProt = $this->getChronologyProtector();
                if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) {
@@ -166,34 +160,36 @@ abstract class LBFactory implements ILBFactory {
                        $this->shutdownChronologyProtector( $chronProt, null, 'async', $cpIndex );
                }
 
+               $cpClientId = $chronProt->getClientId();
+
                $this->commitMasterChanges( __METHOD__ ); // sanity
        }
 
        /**
         * @see ILBFactory::newMainLB()
         * @param bool $domain
-        * @return LoadBalancer
+        * @return ILoadBalancer
         */
        abstract public function newMainLB( $domain = false );
 
        /**
         * @see ILBFactory::getMainLB()
         * @param bool $domain
-        * @return LoadBalancer
+        * @return ILoadBalancer
         */
        abstract public function getMainLB( $domain = false );
 
        /**
         * @see ILBFactory::newExternalLB()
         * @param string $cluster
-        * @return LoadBalancer
+        * @return ILoadBalancer
         */
        abstract public function newExternalLB( $cluster );
 
        /**
         * @see ILBFactory::getExternalLB()
         * @param string $cluster
-        * @return LoadBalancer
+        * @return ILoadBalancer
         */
        abstract public function getExternalLB( $cluster );
 
@@ -497,6 +493,7 @@ abstract class LBFactory implements ILBFactory {
                        [
                                'ip' => $this->requestInfo['IPAddress'],
                                'agent' => $this->requestInfo['UserAgent'],
+                               'clientId' => $this->requestInfo['ChronologyClientId']
                        ],
                        $this->requestInfo['ChronologyPositionIndex']
                );
@@ -551,7 +548,7 @@ abstract class LBFactory implements ILBFactory {
        }
 
        /**
-        * Base parameters to LoadBalancer::__construct()
+        * Base parameters to ILoadBalancer::__construct()
         * @return array
         */
        final protected function baseLoadBalancerParams() {
@@ -640,6 +637,42 @@ abstract class LBFactory implements ILBFactory {
                return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index";
        }
 
+       /**
+        * @param int $index Write index
+        * @param int $time UNIX timestamp; can be used to detect stale cookies (T190082)
+        * @param string $clientId Agent ID hash from ILBFactory::shutdown()
+        * @return string Timestamp-qualified write index of the form "<index>@<timestamp>#<hash>"
+        * @since 1.32
+        */
+       public static function makeCookieValueFromCPIndex( $index, $time, $clientId ) {
+               return "$index@$time#$clientId";
+       }
+
+       /**
+        * @param string $value Possible result of LBFactory::makeCookieValueFromCPIndex()
+        * @param int $minTimestamp Lowest UNIX timestamp of non-expired values (if present)
+        * @return array (index: int or null, clientId: string or null)
+        * @since 1.32
+        */
+       public static function getCPInfoFromCookieValue( $value, $minTimestamp ) {
+               static $placeholder = [ 'index' => null, 'clientId' => null ];
+
+               if ( !preg_match( '/^(\d+)(?:@(\d+))?(?:#([0-9a-f]{32}))?$/', $value, $m ) ) {
+                       return $placeholder; // invalid
+               }
+
+               $index = (int)$m[1];
+               if ( $index <= 0 ) {
+                       return $placeholder; // invalid
+               } elseif ( isset( $m[2] ) && $m[2] !== '' && (int)$m[2] < $minTimestamp ) {
+                       return $placeholder; // expired
+               }
+
+               $clientId = ( isset( $m[3] ) && $m[3] !== '' ) ? $m[3] : null;
+
+               return [ 'index' => $index, 'clientId' => $clientId ];
+       }
+
        public function setRequestInfo( array $info ) {
                if ( $this->chronProt ) {
                        throw new LogicException( 'ChronologyProtector already initialized.' );
@@ -682,4 +715,7 @@ abstract class LBFactory implements ILBFactory {
        }
 }
 
+/**
+ * @deprecated since 1.29
+ */
 class_alias( LBFactory::class, 'LBFactory' );