Merge "maintenance: Script to rename titles for Unicode uppercasing changes"
[lhc/web/wiklou.git] / includes / libs / rdbms / loadbalancer / ILoadBalancer.php
index 0258878..ba0b4a0 100644 (file)
@@ -23,6 +23,7 @@
 namespace Wikimedia\Rdbms;
 
 use Exception;
+use LogicException;
 use InvalidArgumentException;
 
 /**
@@ -62,6 +63,8 @@ use InvalidArgumentException;
  *      Note that lag is still possible depending on how wsrep-sync-wait is set server-side.
  *   - Read-only archive clones: set 'is static' in the server configuration maps. This will
  *      treat all such DBs as having 0 lag.
+ *   - Externally updated dataset clones: set 'is static' in the server configuration maps.
+ *      This will treat all such DBs as having 0 lag.
  *   - SQL load balancing proxy: any proxy should handle lag checks on its own, so the 'max lag'
  *      parameter should probably be set to INF in the server configuration maps. This will make
  *      the load balancer ignore whatever it detects as the lag of the logical replica is (which
@@ -83,9 +86,15 @@ interface ILoadBalancer {
 
        /** @var string Domain specifier when no specific database needs to be selected */
        const DOMAIN_ANY = '';
+       /** @var bool The generic query group (bool gives b/c with 1.33 method signatures) */
+       const GROUP_GENERIC = false;
 
        /** @var int DB handle should have DBO_TRX disabled and the caller will leave it as such */
        const CONN_TRX_AUTOCOMMIT = 1;
+       /** @var int Return null on connection failure instead of throwing an exception */
+       const CONN_SILENCE_ERRORS = 2;
+       /** @var int Caller is requesting the master DB server for possibly writes */
+       const CONN_INTENT_WRITABLE = 4;
 
        /** @var string Manager of ILoadBalancer instances is running post-commit callbacks */
        const STAGE_POSTCOMMIT_CALLBACKS = 'stage-postcommit-callbacks';
@@ -96,25 +105,26 @@ interface ILoadBalancer {
         * Construct a manager of IDatabase connection objects
         *
         * @param array $params Parameter map with keys:
-        *  - servers : Required. Array of server info structures.
-        *  - localDomain: A DatabaseDomain or domain ID string.
-        *  - loadMonitor : Name of a class used to fetch server lag and load.
+        *  - servers : List of server info structures
+        *  - localDomain: A DatabaseDomain or domain ID string
+        *  - loadMonitor : Name of a class used to fetch server lag and load
         *  - readOnlyReason : Reason the master DB is read-only if so [optional]
         *  - waitTimeout : Maximum time to wait for replicas for consistency [optional]
         *  - maxLag: Try to avoid DB replicas with lag above this many seconds [optional]
         *  - srvCache : BagOStuff object for server cache [optional]
         *  - wanCache : WANObjectCache object [optional]
         *  - chronologyCallback: Callback to run before the first connection attempt [optional]
+        *  - defaultGroup: Default query group; the generic group if not specified [optional]
         *  - hostname : The name of the current server [optional]
-        *  - cliMode: Whether the execution context is a CLI script. [optional]
-        *  - profiler : Class name or instance with profileIn()/profileOut() methods. [optional]
-        *  - trxProfiler: TransactionProfiler instance. [optional]
-        *  - replLogger: PSR-3 logger instance. [optional]
-        *  - connLogger: PSR-3 logger instance. [optional]
-        *  - queryLogger: PSR-3 logger instance. [optional]
-        *  - perfLogger: PSR-3 logger instance. [optional]
-        *  - errorLogger : Callback that takes an Exception and logs it. [optional]
-        *  - deprecationLogger: Callback to log a deprecation warning. [optional]
+        *  - cliMode: Whether the execution context is a CLI script [optional]
+        *  - profiler : Class name or instance with profileIn()/profileOut() methods [optional]
+        *  - trxProfiler: TransactionProfiler instance [optional]
+        *  - replLogger: PSR-3 logger instance [optional]
+        *  - connLogger: PSR-3 logger instance [optional]
+        *  - queryLogger: PSR-3 logger instance [optional]
+        *  - perfLogger: PSR-3 logger instance [optional]
+        *  - errorLogger : Callback that takes an Exception and logs it [optional]
+        *  - deprecationLogger: Callback to log a deprecation warning [optional]
         *  - roundStage: STAGE_POSTCOMMIT_* class constant; for internal use [optional]
         *  - ownerId: integer ID of an LBFactory instance that manages this instance [optional]
         * @throws InvalidArgumentException
@@ -146,15 +156,18 @@ interface ILoadBalancer {
        public function redefineLocalDomain( $domain );
 
        /**
-        * Get the index of the reader connection, which may be a replica DB
+        * Get the server index of the reader connection for a given group
         *
-        * This takes into account load ratios and lag times. It should
-        * always return a consistent index during a given invocation.
+        * This takes into account load ratios and lag times. It should return a consistent
+        * index during the life time of the load balancer. This initially checks replica DBs
+        * for connectivity to avoid returning an unusable server. This means that connections
+        * might be attempted by calling this method (usally one at the most but possibly more).
+        * Subsequent calls with the same $group will not need to make new connection attempts
+        * since the acquired connection for each group is preserved.
         *
-        * Side effect: opens connections to databases
-        * @param string|bool $group Query group, or false for the generic group
-        * @param string|bool $domain Domain ID, or false for the current domain
-        * @throws DBError
+        * @param string|bool $group Query group or false for the generic group
+        * @param string|bool $domain DB domain ID or false for the local domain
+        * @throws DBError If no live handle can be obtained
         * @return bool|int|string
         */
        public function getReaderIndex( $group = false, $domain = false );
@@ -197,7 +210,8 @@ interface ILoadBalancer {
         * Get any open connection to a given server index, local or foreign
         *
         * Use CONN_TRX_AUTOCOMMIT to only look for connections opened with that flag.
-        * Avoid the use of begin() or startAtomic() on any such connections.
+        * Avoid the use of transaction methods like IDatabase::begin() or IDatabase::startAtomic()
+        * on any such connections.
         *
         * @param int $i Server index or DB_MASTER/DB_REPLICA
         * @param int $flags Bitfield of CONN_* class constants
@@ -206,152 +220,207 @@ interface ILoadBalancer {
        public function getAnyOpenConnection( $i, $flags = 0 );
 
        /**
-        * Get a connection handle by server index
-        *
-        * The CONN_TRX_AUTOCOMMIT flag is ignored for databases with ATTR_DB_LEVEL_LOCKING
-        * (e.g. sqlite) in order to avoid deadlocks. ILoadBalancer::getServerAttributes()
-        * can be used to check such flags beforehand.
-        *
-        * If the caller uses $domain or sets CONN_TRX_AUTOCOMMIT in $flags, then it must
-        * also call ILoadBalancer::reuseConnection() on the handle when finished using it.
-        * In all other cases, this is not necessary, though not harmful either.
-        * Avoid the use of begin() or startAtomic() on any such connections.
+        * Get a live handle for a real or virtual (DB_MASTER/DB_REPLICA) server index
+        *
+        * The server index, $i, can be one of the following:
+        *   - DB_REPLICA: a server index will be selected by the load balancer based on read
+        *      weight, connectivity, and replication lag. Note that the master server might be
+        *      configured with read weight. If $groups is empty then it means "the generic group",
+        *      in which case all servers defined with read weight will be considered. Additional
+        *      query groups can be configured, having their own list of server indexes and read
+        *      weights. If a query group list is provided in $groups, then each recognized group
+        *      will be tried, left-to-right, until server index selection succeeds or all groups
+        *      have been tried, in which case the generic group will be tried.
+        *   - DB_MASTER: the master server index will be used; the same as getWriterIndex().
+        *      The value of $groups should be [] when using this server index.
+        *   - Specific server index: a positive integer can be provided to use the server with
+        *      that index. An error will be thrown in no such server index is recognized. This
+        *      server selection method is usually only useful for internal load balancing logic.
+        *      The value of $groups should be [] when using a specific server index.
+        *
+        * Handles acquired by this method, getConnectionRef(), getLazyConnectionRef(), and
+        * getMaintenanceConnectionRef() use the same set of shared connection pools. Callers that
+        * get a *local* DB domain handle for the same server will share one handle for all of those
+        * callers using CONN_TRX_AUTOCOMMIT (via $flags) and one handle for all of those callers not
+        * using CONN_TRX_AUTOCOMMIT. Callers that get a *foreign* DB domain handle (via $domain) will
+        * share any handle that has the right CONN_TRX_AUTOCOMMIT mode and is already on the right
+        * DB domain. Otherwise, one of the "free for reuse" handles will be claimed or a new handle
+        * will be made if there are none.
+        *
+        * Handle sharing is particularly useful when callers get local DB domain (the default),
+        * transaction round aware (the default), DB_MASTER handles. All such callers will operate
+        * within a single database transaction as a consequence. Handle sharing is also useful when
+        * callers get local DB domain (the default), transaction round aware (the default), samely
+        * query grouped (the default), DB_REPLICA handles. All such callers will operate within a
+        * single database transaction as a consequence.
+        *
+        * Calling functions that use $domain must call reuseConnection() once the last query of the
+        * function is executed. This lets the load balancer share this handle with other callers
+        * requesting connections on different database domains.
+        *
+        * Use CONN_TRX_AUTOCOMMIT to use a separate pool of only auto-commit handles. This flag
+        * is ignored for databases with ATTR_DB_LEVEL_LOCKING (e.g. sqlite) in order to avoid
+        * deadlocks. getServerAttributes() can be used to check such attributes beforehand. Avoid
+        * using IDatabase::begin() and IDatabase::commit() on such handles. If it is not possible
+        * to avoid using methods like IDatabase::startAtomic() and IDatabase::endAtomic(), callers
+        * should at least make sure that the atomic sections are closed on failure via try/catch
+        * and IDatabase::cancelAtomic().
+        *
+        * @see ILoadBalancer::reuseConnection()
+        * @see ILoadBalancer::getServerAttributes()
         *
         * @param int $i Server index (overrides $groups) or DB_MASTER/DB_REPLICA
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string[]|string $groups Query group(s) or [] to use the default group
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @param int $flags Bitfield of CONN_* class constants
         *
         * @note This method throws DBAccessError if ILoadBalancer::disable() was called
         *
-        * @throws DBError
-        * @return Database
+        * @return IDatabase|bool This returns false on failure if CONN_SILENCE_ERRORS is set
+        * @throws DBError If no live handle can be obtained and CONN_SILENCE_ERRORS is not set
+        * @throws DBAccessError If disable() was previously called
+        * @throws InvalidArgumentException
         */
        public function getConnection( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
-        * Mark a foreign connection as being available for reuse under a different DB domain
+        * Get a live handle for a server index
+        *
+        * This is a simpler version of getConnection() that does not accept virtual server
+        * indexes (e.g. DB_MASTER/DB_REPLICA), does not assure that master DB handles have
+        * read-only mode when there is high replication lag, and can only trigger attempts
+        * to connect to a single server (the one with the specified server index).
+        *
+        * @see ILoadBalancer::getConnection()
+        *
+        * @param int $i Specific server index
+        * @param string $domain Resolved DB domain
+        * @param int $flags Bitfield of class CONN_* constants
+        * @return IDatabase|bool
+        */
+       public function getServerConnection( $i, $domain, $flags = 0 );
+
+       /**
+        * Mark a live handle as being available for reuse under a different database domain
         *
-        * This mechanism is reference-counted, and must be called the same number of times
-        * as getConnection() to work.
+        * This mechanism is reference-counted, and must be called the same number of times as
+        * getConnection() to work. Never call this on handles acquired via getConnectionRef(),
+        * getLazyConnectionRef(), and getMaintenanceConnectionRef(), as they already manage
+        * the logic of calling this method when they fall out of scope in PHP.
+        *
+        * @see ILoadBalancer::getConnection()
         *
         * @param IDatabase $conn
-        * @throws InvalidArgumentException
+        * @throws LogicException
         */
        public function reuseConnection( IDatabase $conn );
 
        /**
-        * Get a database connection handle reference
-        *
-        * The handle's methods simply wrap those of a Database handle
+        * Get a live database handle reference for a real or virtual (DB_MASTER/DB_REPLICA) server index
         *
         * The CONN_TRX_AUTOCOMMIT flag is ignored for databases with ATTR_DB_LEVEL_LOCKING
-        * (e.g. sqlite) in order to avoid deadlocks. ILoadBalancer::getServerAttributes()
+        * (e.g. sqlite) in order to avoid deadlocks. getServerAttributes()
         * can be used to check such flags beforehand. Avoid the use of begin() or startAtomic()
         * on any CONN_TRX_AUTOCOMMIT connections.
         *
         * @see ILoadBalancer::getConnection() for parameter information
         *
         * @param int $i Server index or DB_MASTER/DB_REPLICA
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string[]|string $groups Query group(s) or [] to use the default group
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
         * @return DBConnRef
         */
        public function getConnectionRef( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
-        * Get a database connection handle reference without connecting yet
+        * Get a database handle reference for a real or virtual (DB_MASTER/DB_REPLICA) server index
         *
-        * The handle's methods simply wrap those of a Database handle
+        * The handle's methods simply proxy to those of an underlying IDatabase handle which
+        * takes care of the actual connection and query logic.
         *
         * The CONN_TRX_AUTOCOMMIT flag is ignored for databases with ATTR_DB_LEVEL_LOCKING
-        * (e.g. sqlite) in order to avoid deadlocks. ILoadBalancer::getServerAttributes()
+        * (e.g. sqlite) in order to avoid deadlocks. getServerAttributes()
         * can be used to check such flags beforehand. Avoid the use of begin() or startAtomic()
         * on any CONN_TRX_AUTOCOMMIT connections.
         *
         * @see ILoadBalancer::getConnection() for parameter information
         *
         * @param int $i Server index or DB_MASTER/DB_REPLICA
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string[]|string $groups Query group(s) or [] to use the default group
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
         * @return DBConnRef
         */
        public function getLazyConnectionRef( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
-        * Get a maintenance database connection handle reference for migrations and schema changes
+        * Get a live database handle for a real or virtual (DB_MASTER/DB_REPLICA) server index
+        * that can be used for data migrations and schema changes
         *
-        * The handle's methods simply wrap those of a Database handle
+        * The handle's methods simply proxy to those of an underlying IDatabase handle which
+        * takes care of the actual connection and query logic.
         *
         * The CONN_TRX_AUTOCOMMIT flag is ignored for databases with ATTR_DB_LEVEL_LOCKING
-        * (e.g. sqlite) in order to avoid deadlocks. ILoadBalancer::getServerAttributes()
+        * (e.g. sqlite) in order to avoid deadlocks. getServerAttributes()
         * can be used to check such flags beforehand. Avoid the use of begin() or startAtomic()
         * on any CONN_TRX_AUTOCOMMIT connections.
         *
         * @see ILoadBalancer::getConnection() for parameter information
         *
         * @param int $i Server index or DB_MASTER/DB_REPLICA
-        * @param array|string|bool $groups Query group(s), or false for the generic reader
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string[]|string $groups Query group(s) or [] to use the default group
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
         * @return MaintainableDBConnRef
         */
        public function getMaintenanceConnectionRef( $i, $groups = [], $domain = false, $flags = 0 );
 
        /**
-        * Open a connection to the server given by the specified index
-        *
-        * The index must be an actual index into the array. If a connection to the server is
-        * already open and not considered an "in use" foreign connection, this simply returns it.
-        *
-        * Avoid using CONN_TRX_AUTOCOMMIT for databases with ATTR_DB_LEVEL_LOCKING (e.g. sqlite)
-        * in order to avoid deadlocks. ILoadBalancer::getServerAttributes() can be used to check
-        * such flags beforehand.
+        * Get the server index of the master server
         *
-        * If the caller uses $domain or sets CONN_TRX_AUTOCOMMIT in $flags, then it must
-        * also call ILoadBalancer::reuseConnection() on the handle when finished using it.
-        * In all other cases, this is not necessary, though not harmful either.
-        * Avoid the use of begin() or startAtomic() on any such connections.
-        *
-        * @note This method throws DBAccessError if ILoadBalancer::disable() was called
-        *
-        * @param int $i Server index (does not support DB_MASTER/DB_REPLICA)
-        * @param string|bool $domain Domain ID, or false for the current domain
-        * @param int $flags Bitfield of CONN_* class constants (e.g. CONN_TRX_AUTOCOMMIT)
-        * @return Database|bool Returns false on errors
-        * @throws DBAccessError
-        */
-       public function openConnection( $i, $domain = false, $flags = 0 );
-
-       /**
         * @return int
         */
        public function getWriterIndex();
 
        /**
-        * Returns true if the specified index is a valid server index
+        * Get the number of servers defined in configuration
         *
-        * @param int $i
-        * @return bool
+        * @return int
         */
-       public function haveIndex( $i );
+       public function getServerCount();
 
        /**
-        * Returns true if the specified index is valid and has non-zero load
+        * Whether there are any replica servers configured
         *
-        * @param int $i
-        * @return bool
+        * This counts both servers using streaming replication from the master server and
+        * servers that just have a clone of the static dataset found on the master server
+        *
+        * @return int
+        * @since 1.34
         */
-       public function isNonZeroLoad( $i );
+       public function hasReplicaServers();
 
        /**
-        * Get the number of defined servers (not the number of open connections)
+        * Whether any replica servers use streaming replication from the master server
+        *
+        * Generally this is one less than getServerCount(), though it might otherwise
+        * return a lower number if some of the servers are configured with "is static".
+        * That flag is used when both the server has no active replication setup and the
+        * dataset is either read-only or occasionally updated out-of-band. For example,
+        * a script might import a new geographic information dataset each week by writing
+        * it to each server and later directing the application to use the new version.
+        *
+        * It is possible for some replicas to be configured with "is static" but not
+        * others, though it generally should either be set for all or none of the replicas.
+        *
+        * If this returns zero, this means that there is generally no reason to execute
+        * replication wait logic for session consistency and lag reduction.
         *
         * @return int
+        * @since 1.34
         */
-       public function getServerCount();
+       public function hasStreamingReplicaServers();
 
        /**
         * Get the host name or IP address of the server with the specified index
@@ -362,7 +431,7 @@ interface ILoadBalancer {
        public function getServerName( $i );
 
        /**
-        * Return the server info structure for a given index, or false if the index is invalid.
+        * Return the server info structure for a given index or false if the index is invalid.
         * @param int $i
         * @return array|bool
         * @since 1.31
@@ -544,7 +613,7 @@ interface ILoadBalancer {
 
        /**
         * @note This method will trigger a DB connection if not yet done
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @return bool Whether the database for generic connections this request is highly "lagged"
         */
        public function getLaggedReplicaMode( $domain = false );
@@ -561,7 +630,7 @@ interface ILoadBalancer {
 
        /**
         * @note This method may trigger a DB connection if not yet done
-        * @param string|bool $domain Domain ID, or false for the current domain
+        * @param string|bool $domain DB domain ID or false for the local domain
         * @param IDatabase|null $conn DB master connection; used to avoid loops [optional]
         * @return string|bool Reason the master is read-only or false if it is not
         */
@@ -601,13 +670,13 @@ interface ILoadBalancer {
        public function forEachOpenReplicaConnection( $callback, array $params = [] );
 
        /**
-        * Get the hostname and lag time of the most-lagged replica DB
+        * Get the hostname and lag time of the most-lagged replica server
         *
         * This is useful for maintenance scripts that need to throttle their updates.
         * May attempt to open connections to replica DBs on the default DB. If there is
         * no lag, the maximum lag will be reported as -1.
         *
-        * @param bool|string $domain Domain ID, or false for the default database
+        * @param bool|string $domain Domain ID or false for the default database
         * @return array ( host, max lag, index of max lagged host )
         */
        public function getMaxLag( $domain = false );
@@ -624,33 +693,20 @@ interface ILoadBalancer {
         */
        public function getLagTimes( $domain = false );
 
-       /**
-        * Get the lag in seconds for a given connection, or zero if this load
-        * balancer does not have replication enabled.
-        *
-        * This should be used in preference to Database::getLag() in cases where
-        * replication may not be in use, since there is no way to determine if
-        * replication is in use at the connection level without running
-        * potentially restricted queries such as SHOW SLAVE STATUS. Using this
-        * function instead of Database::getLag() avoids a fatal error in this
-        * case on many installations.
-        *
-        * @param IDatabase $conn
-        * @return int|bool Returns false on error
-        */
-       public function safeGetLag( IDatabase $conn );
-
        /**
         * Wait for a replica DB to reach a specified master position
         *
-        * This will connect to the master to get an accurate position if $pos is not given
+        * If $conn is not a replica server connection, then this will return true.
+        * Otherwise, if $pos is not provided, this will connect to the master server
+        * to get an accurate position.
         *
         * @param IDatabase $conn Replica DB
         * @param DBMasterPos|bool $pos Master position; default: current position
         * @param int $timeout Timeout in seconds [optional]
         * @return bool Success
+        * @since 1.34
         */
-       public function safeWaitForMasterPos( IDatabase $conn, $pos = false, $timeout = 10 );
+       public function waitForMasterPos( IDatabase $conn, $pos = false, $timeout = 10 );
 
        /**
         * Set a callback via IDatabase::setTransactionListener() on