Merge "Avoid unnecessary WaitConditionLoop delays in ChronologyProtector"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 19 May 2018 10:38:23 +0000 (10:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 19 May 2018 10:38:23 +0000 (10:38 +0000)
1  2 
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/lbfactory/LBFactory.php

@@@ -63,6 -63,8 +63,8 @@@ class ChronologyProtector implements Lo
  
        /** @var int Seconds to store positions */
        const POSITION_TTL = 60;
+       /** @var int Seconds to store position write index cookies (safely less than POSITION_TTL) */
+       const POSITION_COOKIE_TTL = 60;
        /** @var int Max time to wait for positions to appear */
        const POS_STORE_WAIT_TIMEOUT = 5;
  
                        implode( ', ', array_keys( $this->shutdownPositions ) ) . "\n"
                );
  
 -              // CP-protected writes should overwhemingly go to the master datacenter, so get DC-local
 -              // lock to merge the values. Use a DC-local get() and a synchronous all-DC set(). This
 -              // makes it possible for the BagOStuff class to write in parallel to all DCs with one RTT.
 +              // CP-protected writes should overwhelmingly go to the master datacenter, so use a
 +              // DC-local lock to merge the values. Use a DC-local get() and a synchronous all-DC
 +              // set(). This makes it possible for the BagOStuff class to write in parallel to all
 +              // DCs with one RTT. The use of WRITE_SYNC avoids needing READ_LATEST for the get().
                if ( $store->lock( $this->key, 3 ) ) {
                        if ( $workCallback ) {
 -                              // Let the store run the work before blocking on a replication sync barrier. By the
 -                              // time it's done with the work, the barrier should be fast if replication caught up.
 +                              // Let the store run the work before blocking on a replication sync barrier.
 +                              // If replication caught up while the work finished, the barrier will be fast.
                                $store->addBusyCallback( $workCallback );
                        }
                        $ok = $store->set(
@@@ -172,28 -172,28 +172,28 @@@ abstract class LBFactory implements ILB
        /**
         * @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 );
  
        }
  
        /**
 -       * Base parameters to LoadBalancer::__construct()
 +       * Base parameters to ILoadBalancer::__construct()
         * @return array
         */
        final protected function baseLoadBalancerParams() {
                return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index";
        }
  
+       /**
+        * @param int $index Write index
+        * @param int $time UNIX timestamp
+        * @return string Timestamp-qualified write index of the form "<index>.<timestamp>"
+        * @since 1.32
+        */
+       public static function makeCookieValueFromCPIndex( $index, $time ) {
+               return $index . '@' . $time;
+       }
+       /**
+        * @param string $value String possibly of the form "<index>" or "<index>@<timestamp>"
+        * @param int $minTimestamp Lowest UNIX timestamp of non-expired values (if present)
+        * @return int|null Write index or null if $value is empty or expired
+        * @since 1.32
+        */
+       public static function getCPIndexFromCookieValue( $value, $minTimestamp ) {
+               if ( !preg_match( '/^(\d+)(?:@(\d+))?$/', $value, $m ) ) {
+                       return null;
+               }
+               $index = (int)$m[1];
+               if ( isset( $m[2] ) && $m[2] !== '' && (int)$m[2] < $minTimestamp ) {
+                       return null; // expired
+               }
+               return ( $index > 0 ) ? $index : null;
+       }
        public function setRequestInfo( array $info ) {
                if ( $this->chronProt ) {
                        throw new LogicException( 'ChronologyProtector already initialized.' );