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 | */ |
20 | namespace Wikimedia\Rdbms; |
21 | |
22 | use Generator; |
23 | use 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 "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. |
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 | */ |
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; |
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(): string; |
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 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. |
145 | * |
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. |
150 | * |
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. |
153 | * |
154 | * @param string|false $domain Domain ID, or false for the current domain |
155 | * @return ILoadBalancerForOwner |
156 | */ |
157 | public function newMainLB( $domain = false ): ILoadBalancerForOwner; |
158 | |
159 | /** |
160 | * Get the tracked load balancer instance for the main cluster that handles the given domain |
161 | * |
162 | * If no tracked instances exists, then one will be instantiated |
163 | * |
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. |
166 | * |
167 | * @param string|false $domain Domain ID, or false for the current domain |
168 | * @return ILoadBalancer |
169 | */ |
170 | public function getMainLB( $domain = false ): ILoadBalancer; |
171 | |
172 | /** |
173 | * Create a new load balancer instance for an external cluster |
174 | * |
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. |
177 | * |
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. |
182 | * |
183 | * @param string $cluster External cluster name |
184 | * @throws InvalidArgumentException If $cluster is not recognized |
185 | * @return ILoadBalancerForOwner |
186 | */ |
187 | public function newExternalLB( $cluster ): ILoadBalancerForOwner; |
188 | |
189 | /** |
190 | * Get the tracked load balancer instance for an external cluster |
191 | * |
192 | * If no tracked instances exists, then one will be instantiated |
193 | * |
194 | * @param string $cluster External cluster name |
195 | * @throws InvalidArgumentException If $cluster is not recognized |
196 | * @return ILoadBalancer |
197 | */ |
198 | public function getExternalLB( $cluster ): ILoadBalancer; |
199 | |
200 | /** |
201 | * Get the tracked load balancer instances for all main clusters |
202 | * |
203 | * If no tracked instance exists for a cluster, then one will be instantiated |
204 | * |
205 | * Note that default main cluster name is ILoadBalancer::CLUSTER_MAIN_DEFAULT |
206 | * |
207 | * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer) |
208 | * @since 1.29 |
209 | */ |
210 | public function getAllMainLBs(): array; |
211 | |
212 | /** |
213 | * Get the tracked load balancer instances for all external clusters |
214 | * |
215 | * If no tracked instance exists for a cluster, then one will be instantiated |
216 | * |
217 | * @return ILoadBalancer[] Map of (cluster name => ILoadBalancer) |
218 | * @since 1.29 |
219 | */ |
220 | public function getAllExternalLBs(): array; |
221 | |
222 | /** |
223 | * Get all tracked load balancer instances (generator) |
224 | * |
225 | * @return Generator|ILoadBalancer[] |
226 | * @since 1.39 |
227 | */ |
228 | public function getAllLBs(); |
229 | |
230 | /** |
231 | * Prepare all instantiated tracked load balancer instances for shutdown |
232 | * |
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] |
237 | */ |
238 | public function shutdown( |
239 | $flags = self::SHUTDOWN_NORMAL, |
240 | ?callable $workCallback = null, |
241 | &$cpIndex = null, |
242 | &$cpClientId = null |
243 | ); |
244 | |
245 | /** |
246 | * Commit all replica database server transactions, clearing any point-in-time view snapshots |
247 | * |
248 | * This only applies to the instantiated tracked load balancer instances. |
249 | * |
250 | * This is useful for getting rid of stale data from an implicit transaction round |
251 | * |
252 | * @param string $fname Caller name @phan-mandatory-param |
253 | * @deprecated Since 1.43 |
254 | */ |
255 | public function flushReplicaSnapshots( $fname = __METHOD__ ); |
256 | |
257 | /** |
258 | * Wrap subsequent queries for all transaction round aware primary connections in a transaction |
259 | * |
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. |
268 | * |
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. |
273 | * |
274 | * This only applies to the tracked load balancer instances. |
275 | * |
276 | * This allows for custom transaction rounds from any outer transaction scope. |
277 | * |
278 | * @param string $fname @phan-mandatory-param |
279 | * @throws DBTransactionError |
280 | * @since 1.37 |
281 | */ |
282 | public function beginPrimaryChanges( $fname = __METHOD__ ); |
283 | |
284 | /** |
285 | * Commit all primary connection transactions and flush all replica connection transactions |
286 | * |
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. |
291 | * |
292 | * This only applies to the instantiated tracked load balancer instances. |
293 | * |
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 |
298 | */ |
299 | public function commitPrimaryChanges( $fname = __METHOD__, int $maxWriteDuration = 0 ); |
300 | |
301 | /** |
302 | * Rollback all primary connection transactions and flush all replica connection transactions |
303 | * |
304 | * This only applies to the instantiated tracked load balancer instances. |
305 | * |
306 | * @param string $fname Caller name @phan-mandatory-param |
307 | * @since 1.37 |
308 | */ |
309 | public function rollbackPrimaryChanges( $fname = __METHOD__ ); |
310 | |
311 | /** |
312 | * Release important session-level state (named lock, table locks) as post-rollback cleanup |
313 | * |
314 | * This only applies to the instantiated tracked load balancer instances. |
315 | * |
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. |
318 | * |
319 | * @param string $fname Caller name @phan-mandatory-param |
320 | * @since 1.38 |
321 | */ |
322 | public function flushPrimarySessions( $fname = __METHOD__ ); |
323 | |
324 | /** |
325 | * Check if an explicit transaction round is active |
326 | * |
327 | * @return bool |
328 | * @since 1.29 |
329 | */ |
330 | public function hasTransactionRound(); |
331 | |
332 | /** |
333 | * Check if transaction rounds can be started, committed, or rolled back right now |
334 | * |
335 | * This can be used as a recursion guard to avoid exceptions in transaction callbacks. |
336 | * |
337 | * @return bool |
338 | * @since 1.32 |
339 | */ |
340 | public function isReadyForRoundOperations(); |
341 | |
342 | /** |
343 | * Determine if any primary connection has pending changes |
344 | * |
345 | * This only applies to the instantiated tracked load balancer instances. |
346 | * |
347 | * @return bool |
348 | * @since 1.37 |
349 | */ |
350 | public function hasPrimaryChanges(); |
351 | |
352 | /** |
353 | * Determine if any lagged replica database server connection was used. |
354 | * |
355 | * This only applies to the instantiated tracked load balancer instances. |
356 | * |
357 | * @return bool |
358 | */ |
359 | public function laggedReplicaUsed(); |
360 | |
361 | /** |
362 | * Determine if any primary connection has pending/written changes from this request |
363 | * |
364 | * This only applies to the instantiated tracked load balancer instances. |
365 | * |
366 | * @param float|null $age How many seconds ago is "recent" [defaults to LB lag wait timeout] |
367 | * @return bool |
368 | */ |
369 | public function hasOrMadeRecentPrimaryChanges( $age = null ); |
370 | |
371 | /** |
372 | * Waits for the replica database server to catch up to the current primary position |
373 | * |
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. |
376 | * |
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. |
381 | * |
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. |
384 | * |
385 | * This only applies to the instantiated tracked load balancer instances. |
386 | * |
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 |
391 | */ |
392 | public function waitForReplication( array $opts = [] ); |
393 | |
394 | /** |
395 | * Add a callback to be run in every call to waitForReplication() prior to any waiting |
396 | * |
397 | * Callbacks must clear any transactions that they start. |
398 | * |
399 | * @param string $name Callback name |
400 | * @param callable|null $callback Use null to unset a callback |
401 | */ |
402 | public function setWaitForReplicationListener( $name, ?callable $callback = null ); |
403 | |
404 | /** |
405 | * Disable the ChronologyProtector on all instantiated tracked load balancer instances |
406 | * |
407 | * This can be called at the start of special API entry points. |
408 | */ |
409 | public function disableChronologyProtection(); |
410 | |
411 | /** |
412 | * Set a new table prefix for the existing local domain ID for testing |
413 | * |
414 | * @param string $prefix |
415 | * @since 1.33 |
416 | */ |
417 | public function setLocalDomainPrefix( $prefix ); |
418 | |
419 | /** |
420 | * Close all connections on instantiated tracked load balancer instances |
421 | * |
422 | * @param string $fname Caller name (e.g. __METHOD__) @phan-mandatory-param |
423 | */ |
424 | public function closeAll( $fname = __METHOD__ ); |
425 | |
426 | /** |
427 | * @param string $agent Agent name for query profiling |
428 | */ |
429 | public function setAgentName( $agent ); |
430 | |
431 | /** |
432 | * Whether it has streaming replica servers. |
433 | * |
434 | * @since 1.41 |
435 | * @return bool |
436 | */ |
437 | public function hasStreamingReplicaServers(); |
438 | |
439 | /** |
440 | * Set the default timeout for replication wait checks |
441 | * |
442 | * @param int $seconds Timeout, in seconds |
443 | * @return int The previous default timeout |
444 | * @since 1.35 |
445 | */ |
446 | public function setDefaultReplicationWaitTimeout( $seconds ); |
447 | |
448 | /** |
449 | * Make certain table names use their own database, schema, and table prefix |
450 | * when passed into SQL queries pre-escaped and without a qualified database name |
451 | * |
452 | * For example, "user" can be converted to "myschema.mydbname.user" for convenience. |
453 | * Appearances like `user`, somedb.user, somedb.someschema.user will used literally. |
454 | * |
455 | * Calling this twice will completely clear any old table aliases. Also, note that |
456 | * callers are responsible for making sure the schemas and databases actually exist. |
457 | * |
458 | * @param array[] $aliases Map of (table => (dbname, schema, prefix) map) |
459 | * @since 1.31 |
460 | */ |
461 | public function setTableAliases( array $aliases ); |
462 | |
463 | /** |
464 | * Convert certain index names to alternative names before querying the DB |
465 | * |
466 | * Note that this applies to indexes regardless of the table they belong to. |
467 | * |
468 | * This can be employed when an index was renamed X => Y in code, but the new Y-named |
469 | * indexes were not yet built on all DBs. After all the Y-named ones are added by the DBA, |
470 | * the aliases can be removed, and then the old X-named indexes dropped. |
471 | * |
472 | * @param string[] $aliases Map of (index alias => index name) |
473 | * @since 1.31 |
474 | */ |
475 | public function setIndexAliases( array $aliases ); |
476 | |
477 | /** |
478 | * Convert certain database domains to alternative ones |
479 | * |
480 | * This can be used for backwards compatibility logic. |
481 | * |
482 | * @param DatabaseDomain[]|string[] $aliases Map of (domain alias => domain) |
483 | * @since 1.35 |
484 | */ |
485 | public function setDomainAliases( array $aliases ); |
486 | |
487 | /** |
488 | * Get the TransactionProfiler used by this instance |
489 | * |
490 | * @return TransactionProfiler |
491 | * @since 1.35 |
492 | */ |
493 | public function getTransactionProfiler(): TransactionProfiler; |
494 | } |