mediawiki.api: Adopt async-await and assert.rejects() in various tests
[mediawiki.git] / includes / libs / rdbms / lbfactory / ILBFactory.php
blob6af072f7578869512d64649b9080d5f7ddc5d089
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
18 * @file
20 namespace Wikimedia\Rdbms;
22 use Generator;
23 use InvalidArgumentException;
25 /**
26 * Manager of ILoadBalancer objects and, indirectly, IDatabase connections
28 * Each Load balancer instances corresponds to a specific database cluster.
29 * A "cluster" is the set of database servers that manage a given dataset.
31 * The "main" clusters are meant to colocate the most basic and highly relational application
32 * data for one or more "sister projects" managed by this site. This allows for highly flexible
33 * queries. Each project is identified by a database domain. Note that if there are several
34 * projects stored on a cluster, then the cluster dataset is a superset of the dataset for each
35 * of those projects.
37 * The "external" clusters are meant to provide places for bulk text storage, to colocate bulky
38 * relational data from specific modules, and to colocate data from cross-project modules such
39 * as authentication systems. An external cluster can have a database/schema for each project.
41 * @see ILoadBalancer
43 * @ingroup Database
44 * @since 1.28
46 interface ILBFactory extends IConnectionProvider {
47 /** Idiom for "no special shutdown flags" */
48 public const SHUTDOWN_NORMAL = 0;
49 /** Do not save "session consistency" DB replication positions */
50 public const SHUTDOWN_NO_CHRONPROT = 1;
52 /** @var string Default main cluster name (do not change this) */
53 public const CLUSTER_MAIN_DEFAULT = 'DEFAULT';
55 /**
56 * Sub-classes may extend the required keys in $conf with additional parameters
58 * @param array $conf Array with keys:
59 * - localDomain: A DatabaseDomain or database domain ID string
60 * - virtualDomains: List of virtual database domain ID strings [optional].
61 * These can be passed to {@see ILBFactory::getPrimaryDatabase()} and
62 * {@see ILBFactory::getReplicaDatabase()}, with the actual cluster and database
63 * domain being automatically resolved via "virtualDomainsMapping". Virtual database
64 * domains not defined there will resolve to the local database domain.
65 * - virtualDomainsMapping: Map of (virtual database domain ID => config map) [optional].
66 * Each config map has a "db" key and an optional "cluster" key. The "db" key specifies
67 * the actual database domain configured for use, with false indicating that the local
68 * database domain is configured for use. The "cluster" key, if provided, specifies the
69 * name of the external cluster configured for use, otherwise, the main cluster for the
70 * actual database domain will be used.
71 * - chronologyProtector: ChronologyProtector instance [optional]
72 * - readOnlyReason: Reason the primary server is read-only (false if not)
73 * - srvCache: BagOStuff instance for server cache [optional]
74 * - cpStash: BagOStuff instance for ChronologyProtector store [optional].
75 * See [ChronologyProtector requirements](@ref ChronologyProtector-storage-requirements).
76 * - wanCache: WANObjectCache instance [optional]
77 * - cliMode: Whether the execution context is a CLI script [optional]
78 * - profiler: Callback that takes a profile section name and returns a ScopedCallback
79 * that ends the profile section in its destructor [optional]
80 * - trxProfiler: TransactionProfiler instance [optional]
81 * - logger: PSR-3 logger instance [optional]
82 * - errorLogger: Callback that takes an Exception and logs it [optional]
83 * - deprecationLogger: Callback to log a deprecation warning [optional]
84 * - secret: Secret string to use for HMAC hashing [optional]
85 * - criticalSectionProvider: CriticalSectionProvider instance [optional]
87 public function __construct( array $conf );
89 /**
90 * Close all connections and make further attempts to open connections result in DBAccessError
92 * This only applies to the tracked load balancer instances.
94 * @see ILoadBalancer::disable()
96 public function destroy();
98 /**
99 * Reload the configuration if necessary.
100 * This may or may not have any effect.
102 public function autoReconfigure(): void;
105 * Get the local (and default) database domain ID of connection handles
107 * @see DatabaseDomain
108 * @return string Database domain ID; this specifies DB name, schema, and table prefix
109 * @since 1.32
111 public function getLocalDomainID(): string;
114 * Close all connections and redefine the local database domain
116 * This only applies to the tracked load balancer instances.
118 * This method is only intended for use with schema creation or integration testing
120 * @param DatabaseDomain|string $domain
121 * @since 1.33
123 public function redefineLocalDomain( $domain );
126 * Get the tracked load balancer instance for a given domain.
128 * If no tracked instances exists, then one will be instantiated.
130 * This method accepts virtual domains
131 * ({@see \MediaWiki\MainConfigSchema::VirtualDomainsMapping}).
133 * @since 1.43
134 * @param string|false $domain Domain ID, or false for the current domain
135 * @return ILoadBalancer
137 public function getLoadBalancer( $domain = false ): ILoadBalancer;
140 * Create a new load balancer instance for the main cluster that handles the given domain
142 * The resulting object is considered to be owned by the caller. Namely, it will be
143 * untracked, the caller is responsible for cleaning it up, and replication positions
144 * from it will not be saved by ChronologyProtector.
146 * This method is for only advanced usage and callers should almost always use
147 * getMainLB() instead. This method can be useful when a table is used as a key/value
148 * store. In that cases, one might want to query it in autocommit mode (DBO_TRX off)
149 * but still use DBO_TRX transaction rounds on other tables.
151 * @note The local/default database domain used by the load balancer instance will
152 * still inherit from this ILBFactory instance, regardless of the $domain parameter.
154 * @param string|false $domain Domain ID, or false for the current domain
155 * @return ILoadBalancerForOwner
157 public function newMainLB( $domain = false ): ILoadBalancerForOwner;
160 * Get the tracked load balancer instance for the main cluster that handles the given domain
162 * If no tracked instances exists, then one will be instantiated
164 * @note The local/default database domain used by the load balancer instance will
165 * still inherit from this ILBFactory instance, regardless of the $domain parameter.
167 * @param string|false $domain Domain ID, or false for the current domain
168 * @return ILoadBalancer
170 public function getMainLB( $domain = false ): ILoadBalancer;
173 * Create a new load balancer instance for an external cluster
175 * The resulting object will be untracked and the caller is responsible for cleaning it up.
176 * Database replication positions will not be saved by ChronologyProtector.
178 * This method is for only advanced usage and callers should almost always use
179 * getExternalLB() instead. This method can be useful when a table is used as a
180 * key/value store. In that cases, one might want to query it in autocommit mode
181 * (DBO_TRX off) but still use DBO_TRX transaction rounds on other tables.
183 * @param string $cluster External cluster name
184 * @throws InvalidArgumentException If $cluster is not recognized
185 * @return ILoadBalancerForOwner
187 public function newExternalLB( $cluster ): ILoadBalancerForOwner;
190 * Get the tracked load balancer instance for an external cluster
192 * If no tracked instances exists, then one will be instantiated
194 * @param string $cluster External cluster name
195 * @throws InvalidArgumentException If $cluster is not recognized
196 * @return ILoadBalancer
198 public function getExternalLB( $cluster ): ILoadBalancer;
201 * Get the tracked load balancer instances for all main clusters
203 * If no tracked instance exists for a cluster, then one will be instantiated
205 * Note that default main cluster name is ILoadBalancer::CLUSTER_MAIN_DEFAULT
207 * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer)
208 * @since 1.29
210 public function getAllMainLBs(): array;
213 * Get the tracked load balancer instances for all external clusters
215 * If no tracked instance exists for a cluster, then one will be instantiated
217 * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer)
218 * @since 1.29
220 public function getAllExternalLBs(): array;
223 * Get all tracked load balancer instances (generator)
225 * @return Generator|ILoadBalancer[]
226 * @since 1.39
228 public function getAllLBs();
231 * Prepare all instantiated tracked load balancer instances for shutdown
233 * @param int $flags Bit field of ILBFactory::SHUTDOWN_* constants
234 * @param callable|null $workCallback Work to mask ChronologyProtector writes
235 * @param int|null &$cpIndex Position key write counter for ChronologyProtector [returned]
236 * @param string|null &$cpClientId Client ID hash for ChronologyProtector [returned]
238 public function shutdown(
239 $flags = self::SHUTDOWN_NORMAL,
240 ?callable $workCallback = null,
241 &$cpIndex = null,
242 &$cpClientId = null
246 * Commit all replica database server transactions, clearing any point-in-time view snapshots
248 * This only applies to the instantiated tracked load balancer instances.
250 * This is useful for getting rid of stale data from an implicit transaction round
252 * @param string $fname Caller name @phan-mandatory-param
253 * @deprecated Since 1.43
255 public function flushReplicaSnapshots( $fname = __METHOD__ );
258 * Wrap subsequent queries for all transaction round aware primary connections in a transaction
260 * Each of these transactions will be owned by this ILBFactory instance such that direct
261 * calls to {@link IDatabase::commit()} or {@link IDatabase::rollback()} will be disabled.
262 * These transactions get resolved by a single call to either {@link commitPrimaryChanges()}
263 * or {@link rollbackPrimaryChanges()}, after which, the transaction wrapping and ownership
264 * behavior revert back to the default. When there are multiple connections involved, these
265 * methods perform best-effort distributed transactions. When using distributed transactions,
266 * the RDBMS should be configured to used pessimistic concurrency control such that the commit
267 * step of each transaction is unlikely to fail.
269 * Transactions on replication connections are flushed so that future reads will not keep
270 * using the same point-in-time view snapshots (e.g. from MySQL REPEATABLE-READ). However,
271 * this does not wait for replication to catch up, so subsequent reads from replicas might
272 * not reflect recently committed changes.
274 * This only applies to the tracked load balancer instances.
276 * This allows for custom transaction rounds from any outer transaction scope.
278 * @param string $fname @phan-mandatory-param
279 * @throws DBTransactionError
280 * @since 1.37
282 public function beginPrimaryChanges( $fname = __METHOD__ );
285 * Commit all primary connection transactions and flush all replica connection transactions
287 * Transactions on replication connections are flushed so that future reads will not keep
288 * using the same point-in-time view snapshots (e.g. from MySQL REPEATABLE-READ). However,
289 * this does not wait for replication to catch up, so subsequent reads from replicas might
290 * not reflect the committed changes.
292 * This only applies to the instantiated tracked load balancer instances.
294 * @param string $fname Caller name @phan-mandatory-param
295 * @param int $maxWriteDuration abort if more than this much time was spent in write queries
296 * @throws DBTransactionError
297 * @since 1.37
299 public function commitPrimaryChanges( $fname = __METHOD__, int $maxWriteDuration = 0 );
302 * Rollback all primary connection transactions and flush all replica connection transactions
304 * This only applies to the instantiated tracked load balancer instances.
306 * @param string $fname Caller name @phan-mandatory-param
307 * @since 1.37
309 public function rollbackPrimaryChanges( $fname = __METHOD__ );
312 * Release important session-level state (named lock, table locks) as post-rollback cleanup
314 * This only applies to the instantiated tracked load balancer instances.
316 * This should only be called by application entry point functions, since there must be
317 * no chance that a future caller will still be expecting some of the lost session state.
319 * @param string $fname Caller name @phan-mandatory-param
320 * @since 1.38
322 public function flushPrimarySessions( $fname = __METHOD__ );
325 * Check if an explicit transaction round is active
327 * @return bool
328 * @since 1.29
330 public function hasTransactionRound();
333 * Check if transaction rounds can be started, committed, or rolled back right now
335 * This can be used as a recursion guard to avoid exceptions in transaction callbacks.
337 * @return bool
338 * @since 1.32
340 public function isReadyForRoundOperations();
343 * Determine if any primary connection has pending changes
345 * This only applies to the instantiated tracked load balancer instances.
347 * @return bool
348 * @since 1.37
350 public function hasPrimaryChanges();
353 * Determine if any lagged replica database server connection was used.
355 * This only applies to the instantiated tracked load balancer instances.
357 * @return bool
359 public function laggedReplicaUsed();
362 * Determine if any primary connection has pending/written changes from this request
364 * This only applies to the instantiated tracked load balancer instances.
366 * @param float|null $age How many seconds ago is "recent" [defaults to LB lag wait timeout]
367 * @return bool
369 public function hasOrMadeRecentPrimaryChanges( $age = null );
372 * Waits for the replica database server to catch up to the current primary position
374 * Use this when updating very large numbers of rows, as in maintenance scripts, to
375 * avoid causing too much lag. This is a no-op if there are no replica database servers.
377 * By default this waits on all DB clusters actually used in this request.
378 * This makes sense when lag being waiting on is caused by the code that does this check.
379 * In that case, setting "ifWritesSince" can avoid the overhead of waiting for clusters
380 * that were not changed since the last wait check.
382 * Never call this function after a large DB write that is *still* in a transaction.
383 * It only makes sense to call this after the possible lag inducing changes were committed.
385 * This only applies to the instantiated tracked load balancer instances.
387 * @param array $opts Optional fields that include:
388 * - timeout: Max wait time. Default: 60 seconds for CLI, 1 second for web.
389 * - ifWritesSince: Only wait if writes were done since this UNIX timestamp.
390 * @return bool True on success, false if a timeout or error occurred while waiting
392 public function waitForReplication( array $opts = [] );
395 * Add a callback to be run in every call to waitForReplication() prior to any waiting
397 * Callbacks must clear any transactions that they start.
399 * @param string $name Callback name
400 * @param callable|null $callback Use null to unset a callback
401 * @deprecated Since 1.44
403 public function setWaitForReplicationListener( $name, ?callable $callback = null );
406 * Disable the ChronologyProtector on all instantiated tracked load balancer instances
408 * This can be called at the start of special API entry points.
410 public function disableChronologyProtection();
413 * Set a new table prefix for the existing local domain ID for testing
415 * @param string $prefix
416 * @since 1.33
418 public function setLocalDomainPrefix( $prefix );
421 * Close all connections on instantiated tracked load balancer instances
423 * @param string $fname Caller name (e.g. __METHOD__) @phan-mandatory-param
425 public function closeAll( $fname = __METHOD__ );
428 * @param string $agent Agent name for query profiling
430 public function setAgentName( $agent );
433 * Whether it has streaming replica servers.
435 * @since 1.41
436 * @return bool
438 public function hasStreamingReplicaServers();
441 * Set the default timeout for replication wait checks
443 * @param int $seconds Timeout, in seconds
444 * @return int The previous default timeout
445 * @since 1.35
447 public function setDefaultReplicationWaitTimeout( $seconds );
450 * Make certain table names use their own database, schema, and table prefix
451 * when passed into SQL queries pre-escaped and without a qualified database name
453 * For example, "user" can be converted to "myschema.mydbname.user" for convenience.
454 * Appearances like `user`, somedb.user, somedb.someschema.user will used literally.
456 * Calling this twice will completely clear any old table aliases. Also, note that
457 * callers are responsible for making sure the schemas and databases actually exist.
459 * @param array[] $aliases Map of (table => (dbname, schema, prefix) map)
460 * @since 1.31
462 public function setTableAliases( array $aliases );
465 * Convert certain index names to alternative names before querying the DB
467 * Note that this applies to indexes regardless of the table they belong to.
469 * This can be employed when an index was renamed X => Y in code, but the new Y-named
470 * indexes were not yet built on all DBs. After all the Y-named ones are added by the DBA,
471 * the aliases can be removed, and then the old X-named indexes dropped.
473 * @param string[] $aliases Map of (index alias => index name)
474 * @since 1.31
476 public function setIndexAliases( array $aliases );
479 * Convert certain database domains to alternative ones
481 * This can be used for backwards compatibility logic.
483 * @param DatabaseDomain[]|string[] $aliases Map of (domain alias => domain)
484 * @since 1.35
486 public function setDomainAliases( array $aliases );
489 * Get the TransactionProfiler used by this instance
491 * @return TransactionProfiler
492 * @since 1.35
494 public function getTransactionProfiler(): TransactionProfiler;