Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
61.29% |
19 / 31 |
|
50.00% |
5 / 10 |
CRAP | |
0.00% |
0 / 1 |
CentralAuthDatabaseManager | |
61.29% |
19 / 31 |
|
50.00% |
5 / 10 |
39.94 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
resolveDatabaseDomain | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
assertNotReadOnly | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
isReadOnly | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
getCentralReadOnlyReason | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
getCentralPrimaryDB | |
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
1.12 | |||
getCentralReplicaDB | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCentralDBFromRecency | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getLocalDB | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
centralLBHasRecentPrimaryChanges | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\CentralAuth; |
4 | |
5 | use InvalidArgumentException; |
6 | use MediaWiki\Config\ServiceOptions; |
7 | use MediaWiki\Extension\CentralAuth\Config\CAMainConfigNames; |
8 | use MediaWiki\WikiMap\WikiMap; |
9 | use ReadOnlyError; |
10 | use Wikimedia\Rdbms\DBAccessObjectUtils; |
11 | use Wikimedia\Rdbms\IDatabase; |
12 | use Wikimedia\Rdbms\IDBAccessObject; |
13 | use Wikimedia\Rdbms\IReadableDatabase; |
14 | use Wikimedia\Rdbms\LBFactory; |
15 | use Wikimedia\Rdbms\ReadOnlyMode; |
16 | |
17 | /** |
18 | * Service providing access to the CentralAuth internal database. |
19 | * |
20 | * @since 1.37 |
21 | * @author Taavi "Majavah" Väänänen <hi@taavi.wtf> |
22 | */ |
23 | class CentralAuthDatabaseManager { |
24 | |
25 | /** @internal Only public for service wiring use */ |
26 | public const CONSTRUCTOR_OPTIONS = [ |
27 | 'CentralAuthReadOnly', |
28 | ]; |
29 | |
30 | private ServiceOptions $options; |
31 | private LBFactory $lbFactory; |
32 | private ReadOnlyMode $readOnlyMode; |
33 | |
34 | public function __construct( ServiceOptions $options, LBFactory $lbFactory, ReadOnlyMode $readOnlyMode ) { |
35 | $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); |
36 | $this->options = $options; |
37 | $this->lbFactory = $lbFactory; |
38 | $this->readOnlyMode = $readOnlyMode; |
39 | } |
40 | |
41 | /** |
42 | * Determine the database domain for this CentralAuth instance. |
43 | * |
44 | * @return false|string |
45 | */ |
46 | private function resolveDatabaseDomain() { |
47 | return $this->lbFactory->getPrimaryDatabase( 'virtual-centralauth' )->getDomainID(); |
48 | } |
49 | |
50 | /** |
51 | * Throw an exception if the database is read-only. |
52 | * |
53 | * @throws CentralAuthReadOnlyError |
54 | */ |
55 | public function assertNotReadOnly() { |
56 | if ( $this->readOnlyMode->isReadOnly() ) { |
57 | throw new ReadOnlyError; |
58 | } |
59 | $reason = $this->getCentralReadOnlyReason(); |
60 | if ( $reason ) { |
61 | throw new CentralAuthReadOnlyError( $reason ); |
62 | } |
63 | } |
64 | |
65 | /** |
66 | * Determine if either the local or the shared CentralAuth database is |
67 | * read only. This should determine whether assertNotReadOnly() would |
68 | * throw. |
69 | * |
70 | * @return bool |
71 | */ |
72 | public function isReadOnly(): bool { |
73 | return $this->readOnlyMode->isReadOnly() |
74 | || ( $this->getCentralReadOnlyReason() !== false ); |
75 | } |
76 | |
77 | /** |
78 | * Return the reason why either the shared CentralAuth database is read |
79 | * only, false otherwise. |
80 | * |
81 | * @return bool|string |
82 | */ |
83 | private function getCentralReadOnlyReason() { |
84 | $configReason = $this->options->get( CAMainConfigNames::CentralAuthReadOnly ); |
85 | if ( $configReason === true ) { |
86 | return '(no reason given)'; |
87 | } elseif ( $configReason ) { |
88 | return $configReason; |
89 | } |
90 | |
91 | return $this->readOnlyMode->getReason( $this->resolveDatabaseDomain() ); |
92 | } |
93 | |
94 | /** |
95 | * @return IDatabase a connection to the CentralAuth database primary. |
96 | */ |
97 | public function getCentralPrimaryDB(): IDatabase { |
98 | $this->assertNotReadOnly(); |
99 | return $this->lbFactory->getPrimaryDatabase( 'virtual-centralauth' ); |
100 | } |
101 | |
102 | /** |
103 | * @return IReadableDatabase a connection to a CentralAuth database replica |
104 | */ |
105 | public function getCentralReplicaDB(): IReadableDatabase { |
106 | return $this->lbFactory->getReplicaDatabase( 'virtual-centralauth' ); |
107 | } |
108 | |
109 | /** |
110 | * @param int $recency IDBAccessObject::READ_* constant |
111 | * @return IReadableDatabase |
112 | */ |
113 | public function getCentralDBFromRecency( int $recency ): IReadableDatabase { |
114 | if ( DBAccessObjectUtils::hasFlags( $recency, IDBAccessObject::READ_LATEST ) ) { |
115 | return $this->getCentralPrimaryDB(); |
116 | } else { |
117 | return $this->getCentralReplicaDB(); |
118 | } |
119 | } |
120 | |
121 | /** |
122 | * Gets a database connection to the local database based on a wikiId |
123 | * |
124 | * @param int $index DB_PRIMARY or DB_REPLICA |
125 | * @param string $wikiId |
126 | * |
127 | * @todo Split to two for IReadableDatabase support or drop entirely |
128 | * |
129 | * @return IDatabase |
130 | * @throws CentralAuthReadOnlyError |
131 | * @throws InvalidArgumentException |
132 | */ |
133 | public function getLocalDB( int $index, string $wikiId ): IDatabase { |
134 | if ( $index !== DB_PRIMARY && $index !== DB_REPLICA ) { |
135 | throw new InvalidArgumentException( "Unknown index $index, expected DB_PRIMARY or DB_REPLICA" ); |
136 | } |
137 | |
138 | if ( WikiMap::isCurrentWikiId( $wikiId ) ) { |
139 | $wikiId = false; |
140 | } |
141 | |
142 | return $this->lbFactory->getMainLB( $wikiId ) |
143 | ->getConnection( $index, [], $wikiId ); |
144 | } |
145 | |
146 | /** |
147 | * Check hasOrMadeRecentPrimaryChanges() on the CentralAuth load balancer |
148 | * |
149 | * @return bool |
150 | */ |
151 | public function centralLBHasRecentPrimaryChanges() { |
152 | return $this->lbFactory->getLoadBalancer( 'virtual-centralauth' )->hasOrMadeRecentPrimaryChanges(); |
153 | } |
154 | |
155 | } |