Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
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.
7 *
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.
12 *
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
17 *
18 * @file
19 */
20namespace Wikimedia\Rdbms;
21
22use Generator;
23use InvalidArgumentException;
24
25/**
26 * Manager of ILoadBalancer objects and, indirectly, IDatabase connections
27 *
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.
30 *
31 * The "core" 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.
36 *
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.
40 *
41 * @see ILoadBalancer
42 *
43 * @ingroup Database
44 * @since 1.28
45 */
46interface 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;
51
52    /** @var string Default main cluster name (do not change this) */
53    public const CLUSTER_MAIN_DEFAULT = 'DEFAULT';
54
55    /**
56     * Sub-classes may extend the required keys in $conf with additional parameters
57     *
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]
86     */
87    public function __construct( array $conf );
88
89    /**
90     * Close all connections and make further attempts to open connections result in DBAccessError
91     *
92     * This only applies to the tracked load balancer instances.
93     *
94     * @see ILoadBalancer::disable()
95     */
96    public function destroy();
97
98    /**
99     * Reload the configuration if necessary.
100     * This may or may not have any effect.
101     */
102    public function autoReconfigure(): void;
103
104    /**
105     * Get the local (and default) database domain ID of connection handles
106     *
107     * @see DatabaseDomain
108     * @return string Database domain ID; this specifies DB name, schema, and table prefix
109     * @since 1.32
110     */
111    public function getLocalDomainID();
112
113    /**
114     * Close all connections and redefine the local database domain
115     *
116     * This only applies to the tracked load balancer instances.
117     *
118     * This method is only intended for use with schema creation or integration testing
119     *
120     * @param DatabaseDomain|string $domain
121     * @since 1.33
122     */
123    public function redefineLocalDomain( $domain );
124
125    /**
126     * Get the tracked load balancer instance for a given domain.
127     *
128     * If no tracked instances exists, then one will be instantiated.
129     *
130     * This method accepts virtual domains
131     * ({@see \MediaWiki\MainConfigSchema::VirtualDomainsMapping}).
132     *
133     * @since 1.43
134     * @param string|false $domain Domain ID, or false for the current domain
135     * @return ILoadBalancer
136     */
137    public function getLoadBalancer( $domain = false ): ILoadBalancer;
138
139    /**
140     * Create a new load balancer instance for the main cluster that handles the given domain
141     *
142     * The resulting object will be untracked and the caller is responsible for cleaning it up.
143     * Database replication positions will not be saved by ChronologyProtector.
144     *
145     * This method is for only advanced usage and callers should almost always use
146     * getMainLB() instead. This method can be useful when a table is used as a key/value
147     * store. In that cases, one might want to query it in autocommit mode (DBO_TRX off)
148     * but still use DBO_TRX transaction rounds on other tables.
149     *
150     * @note The local/default database domain used by the load balancer instance will
151     * still inherit from this ILBFactory instance, regardless of the $domain parameter.
152     *
153     * @param string|false $domain Domain ID, or false for the current domain
154     * @return ILoadBalancerForOwner
155     */
156    public function newMainLB( $domain = false ): ILoadBalancerForOwner;
157
158    /**
159     * Get the tracked load balancer instance for the main cluster that handles the given domain
160     *
161     * If no tracked instances exists, then one will be instantiated
162     *
163     * @note The local/default database domain used by the load balancer instance will
164     * still inherit from this ILBFactory instance, regardless of the $domain parameter.
165     *
166     * @param string|false $domain Domain ID, or false for the current domain
167     * @return ILoadBalancer
168     */
169    public function getMainLB( $domain = false ): ILoadBalancer;
170
171    /**
172     * Create a new load balancer instance for an external cluster
173     *
174     * The resulting object will be untracked and the caller is responsible for cleaning it up.
175     * Database replication positions will not be saved by ChronologyProtector.
176     *
177     * This method is for only advanced usage and callers should almost always use
178     * getExternalLB() instead. This method can be useful when a table is used as a
179     * key/value store. In that cases, one might want to query it in autocommit mode
180     * (DBO_TRX off) but still use DBO_TRX transaction rounds on other tables.
181     *
182     * @param string $cluster External cluster name
183     * @throws InvalidArgumentException If $cluster is not recognized
184     * @return ILoadBalancerForOwner
185     */
186    public function newExternalLB( $cluster ): ILoadBalancerForOwner;
187
188    /**
189     * Get the tracked load balancer instance for an external cluster
190     *
191     * If no tracked instances exists, then one will be instantiated
192     *
193     * @param string $cluster External cluster name
194     * @throws InvalidArgumentException If $cluster is not recognized
195     * @return ILoadBalancer
196     */
197    public function getExternalLB( $cluster ): ILoadBalancer;
198
199    /**
200     * Get the tracked load balancer instances for all main clusters
201     *
202     * If no tracked instance exists for a cluster, then one will be instantiated
203     *
204     * Note that default main cluster name is ILoadBalancer::CLUSTER_MAIN_DEFAULT
205     *
206     * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer)
207     * @since 1.29
208     */
209    public function getAllMainLBs(): array;
210
211    /**
212     * Get the tracked load balancer instances for all external clusters
213     *
214     * If no tracked instance exists for a cluster, then one will be instantiated
215     *
216     * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer)
217     * @since 1.29
218     */
219    public function getAllExternalLBs(): array;
220
221    /**
222     * Get all tracked load balancer instances (generator)
223     *
224     * @return Generator|ILoadBalancer[]
225     * @since 1.39
226     */
227    public function getAllLBs();
228
229    /**
230     * Prepare all instantiated tracked load balancer instances for shutdown
231     *
232     * @param int $flags Bit field of ILBFactory::SHUTDOWN_* constants
233     * @param callable|null $workCallback Work to mask ChronologyProtector writes
234     * @param int|null &$cpIndex Position key write counter for ChronologyProtector [returned]
235     * @param string|null &$cpClientId Client ID hash for ChronologyProtector [returned]
236     */
237    public function shutdown(
238        $flags = self::SHUTDOWN_NORMAL,
239        callable $workCallback = null,
240        &$cpIndex = null,
241        &$cpClientId = null
242    );
243
244    /**
245     * Commit all replica database server transactions, clearing any REPEATABLE-READ/SSI snapshots
246     *
247     * This only applies to the instantiated tracked load balancer instances.
248     *
249     * This is useful for getting rid of stale data from an implicit transaction round
250     *
251     * @param string $fname Caller name
252     */
253    public function flushReplicaSnapshots( $fname = __METHOD__ );
254
255    /**
256     * Flush any primary transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
257     *
258     * The DBO_TRX setting will be reverted to the default in each of these methods:
259     *   - commitPrimaryChanges()
260     *   - rollbackPrimaryChanges()
261     *
262     * This only applies to the tracked load balancer instances.
263     *
264     * This allows for custom transaction rounds from any outer transaction scope.
265     *
266     * @param string $fname
267     * @throws DBTransactionError
268     * @since 1.37
269     */
270    public function beginPrimaryChanges( $fname = __METHOD__ );
271
272    /**
273     * Commit changes and clear view snapshots on all primary connections
274     *
275     * This only applies to the instantiated tracked load balancer instances.
276     *
277     * @param string $fname Caller name
278     * @param int $maxWriteDuration abort if more than this much time was spent in write queries
279     * @throws DBTransactionError
280     * @since 1.37
281     */
282    public function commitPrimaryChanges( $fname = __METHOD__, int $maxWriteDuration = 0 );
283
284    /**
285     * Rollback changes on all primary connections
286     *
287     * This only applies to the instantiated tracked load balancer instances.
288     *
289     * @param string $fname Caller name
290     * @since 1.37
291     */
292    public function rollbackPrimaryChanges( $fname = __METHOD__ );
293
294    /**
295     * Release important session-level state (named lock, table locks) as post-rollback cleanup
296     *
297     * This only applies to the instantiated tracked load balancer instances.
298     *
299     * This should only be called by application entry point functions, since there must be
300     * no chance that a future caller will still be expecting some of the lost session state.
301     *
302     * @param string $fname Caller name
303     * @since 1.38
304     */
305    public function flushPrimarySessions( $fname = __METHOD__ );
306
307    /**
308     * Check if an explicit transaction round is active
309     *
310     * @return bool
311     * @since 1.29
312     */
313    public function hasTransactionRound();
314
315    /**
316     * Check if transaction rounds can be started, committed, or rolled back right now
317     *
318     * This can be used as a recursion guard to avoid exceptions in transaction callbacks.
319     *
320     * @return bool
321     * @since 1.32
322     */
323    public function isReadyForRoundOperations();
324
325    /**
326     * Determine if any primary connection has pending changes
327     *
328     * This only applies to the instantiated tracked load balancer instances.
329     *
330     * @return bool
331     * @since 1.37
332     */
333    public function hasPrimaryChanges();
334
335    /**
336     * Determine if any lagged replica database server connection was used.
337     *
338     * This only applies to the instantiated tracked load balancer instances.
339     *
340     * @return bool
341     */
342    public function laggedReplicaUsed();
343
344    /**
345     * Determine if any primary connection has pending/written changes from this request
346     *
347     * This only applies to the instantiated tracked load balancer instances.
348     *
349     * @param float|null $age How many seconds ago is "recent" [defaults to LB lag wait timeout]
350     * @return bool
351     */
352    public function hasOrMadeRecentPrimaryChanges( $age = null );
353
354    /**
355     * Waits for the replica database server to catch up to the current primary position
356     *
357     * Use this when updating very large numbers of rows, as in maintenance scripts, to
358     * avoid causing too much lag. This is a no-op if there are no replica database servers.
359     *
360     * By default this waits on all DB clusters actually used in this request.
361     * This makes sense when lag being waiting on is caused by the code that does this check.
362     * In that case, setting "ifWritesSince" can avoid the overhead of waiting for clusters
363     * that were not changed since the last wait check.
364     *
365     * Never call this function after a large DB write that is *still* in a transaction.
366     * It only makes sense to call this after the possible lag inducing changes were committed.
367     *
368     * This only applies to the instantiated tracked load balancer instances.
369     *
370     * @param array $opts Optional fields that include:
371     *   - timeout: Max wait time. Default: 60 seconds for CLI, 1 second for web.
372     *   - ifWritesSince: Only wait if writes were done since this UNIX timestamp.
373     * @return bool True on success, false if a timeout or error occurred while waiting
374     */
375    public function waitForReplication( array $opts = [] );
376
377    /**
378     * Add a callback to be run in every call to waitForReplication() before waiting
379     *
380     * Callbacks must clear any transactions that they start.
381     *
382     * @param string $name Callback name
383     * @param callable|null $callback Use null to unset a callback
384     */
385    public function setWaitForReplicationListener( $name, callable $callback = null );
386
387    /**
388     * Disable the ChronologyProtector on all instantiated tracked load balancer instances
389     *
390     * This can be called at the start of special API entry points.
391     */
392    public function disableChronologyProtection();
393
394    /**
395     * Set a new table prefix for the existing local domain ID for testing
396     *
397     * @param string $prefix
398     * @since 1.33
399     */
400    public function setLocalDomainPrefix( $prefix );
401
402    /**
403     * Close all connections on instantiated tracked load balancer instances
404     *
405     * @param string $fname Caller name (e.g. __METHOD__)
406     */
407    public function closeAll( $fname = __METHOD__ );
408
409    /**
410     * @param string $agent Agent name for query profiling
411     */
412    public function setAgentName( $agent );
413
414    /**
415     * Whether it has streaming replica servers.
416     *
417     * @since 1.41
418     * @return bool
419     */
420    public function hasStreamingReplicaServers();
421
422    /**
423     * Set the default timeout for replication wait checks
424     *
425     * @param int $seconds Timeout, in seconds
426     * @return int The previous default timeout
427     * @since 1.35
428     */
429    public function setDefaultReplicationWaitTimeout( $seconds );
430
431    /**
432     * Make certain table names use their own database, schema, and table prefix
433     * when passed into SQL queries pre-escaped and without a qualified database name
434     *
435     * For example, "user" can be converted to "myschema.mydbname.user" for convenience.
436     * Appearances like `user`, somedb.user, somedb.someschema.user will used literally.
437     *
438     * Calling this twice will completely clear any old table aliases. Also, note that
439     * callers are responsible for making sure the schemas and databases actually exist.
440     *
441     * @param array[] $aliases Map of (table => (dbname, schema, prefix) map)
442     * @since 1.31
443     */
444    public function setTableAliases( array $aliases );
445
446    /**
447     * Convert certain index names to alternative names before querying the DB
448     *
449     * Note that this applies to indexes regardless of the table they belong to.
450     *
451     * This can be employed when an index was renamed X => Y in code, but the new Y-named
452     * indexes were not yet built on all DBs. After all the Y-named ones are added by the DBA,
453     * the aliases can be removed, and then the old X-named indexes dropped.
454     *
455     * @param string[] $aliases Map of (index alias => index name)
456     * @since 1.31
457     */
458    public function setIndexAliases( array $aliases );
459
460    /**
461     * Convert certain database domains to alternative ones
462     *
463     * This can be used for backwards compatibility logic.
464     *
465     * @param DatabaseDomain[]|string[] $aliases Map of (domain alias => domain)
466     * @since 1.35
467     */
468    public function setDomainAliases( array $aliases );
469
470    /**
471     * Get the TransactionProfiler used by this instance
472     *
473     * @return TransactionProfiler
474     * @since 1.35
475     */
476    public function getTransactionProfiler(): TransactionProfiler;
477}