namespace Wikimedia\Rdbms;
use Exception;
+use LogicException;
use InvalidArgumentException;
/**
/** @var string Domain specifier when no specific database needs to be selected */
const DOMAIN_ANY = '';
+ /** @var string The generic query group */
+ const GROUP_GENERIC = '';
/** @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';
* 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
* Subsequent calls with the same $group will not need to make new connection attempts
* since the acquired connection for each group is preserved.
*
- * @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 );
* 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
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) in preference order; [] for 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 If any error occurs that prevents the yielding of a (live) IDatabase
* @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. 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.
*
- * This mechanism is reference-counted, and must be called the same number of times
- * as getConnection() to work.
+ * @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) in preference order; [] for 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) in preference order; [] for 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) in preference order; [] for 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 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
public function getServerAttributes( $i );
/**
- * Get the current master position for chronology control purposes
+ * Get the current master replication position
+ *
* @return DBMasterPos|bool Returns false if not applicable
+ * @throws DBError
*/
public function getMasterPos();
+ /**
+ * Get the highest DB replication position for chronology control purposes
+ *
+ * If there is only a master server then this returns false. If replication is present
+ * and correctly configured, then this returns the highest replication position of any
+ * server with an open connection. That position can later be passed to waitFor() on a
+ * new load balancer instance to make sure that queries on the new connections see data
+ * at least as up-to-date as queries (prior to this method call) on the old connections.
+ *
+ * This can be useful for implementing session consistency, where the session
+ * will be resumed accross multiple HTTP requests or CLI script instances.
+ *
+ * @return DBMasterPos|bool Replication position or false if not applicable
+ * @since 1.34
+ */
+ public function getReplicaResumePos();
+
/**
* Disable this load balancer. All connections are closed, and any attempt to
* open a new connection will result in a DBAccessError.
/**
* @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 );
/**
* @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
*/
* 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 );
/**
* 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