MediaWiki master
LCStoreDB.php
Go to the documentation of this file.
1<?php
10use Wikimedia\ScopedCallback;
11
17class LCStoreDB implements LCStore {
19 private $code;
21 private $server;
22
24 private $batch = [];
25
27 private $dbw;
29 private $writesDone = false;
31 private $readOnly = false;
32
33 public function __construct( array $params ) {
34 $this->server = $params['server'] ?? [];
35 }
36
38 public function get( $code, $key ) {
39 if ( $this->server || $this->writesDone ) {
40 // If a server configuration map is specified, always used that connection
41 // for reads and writes. Otherwise, if writes occurred in finishWrite(), make
42 // sure those changes are always visible.
43 $db = $this->getWriteConnection();
44 } else {
45 $db = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
46 }
47
48 $value = $db->newSelectQueryBuilder()
49 ->select( 'lc_value' )
50 ->from( 'l10n_cache' )
51 ->where( [ 'lc_lang' => $code, 'lc_key' => $key ] )
52 ->caller( __METHOD__ )->fetchField();
53
54 return ( $value !== false ) ? unserialize( $db->decodeBlob( $value ) ) : null;
55 }
56
58 public function startWrite( $code ) {
59 if ( $this->readOnly ) {
60 return;
61 } elseif ( !$code ) {
62 throw new InvalidArgumentException( __METHOD__ . ": Invalid language \"$code\"" );
63 }
64
65 $dbw = $this->getWriteConnection();
66 $this->readOnly = $dbw->isReadOnly();
67
68 $this->code = $code;
69 $this->batch = [];
70 }
71
72 public function finishWrite() {
73 if ( $this->readOnly ) {
74 return;
75 } elseif ( $this->code === null ) {
76 throw new LogicException( __CLASS__ . ': must call startWrite() before finishWrite()' );
77 }
78
79 $scope = Profiler::instance()->getTransactionProfiler()->silenceForScope();
80 $dbw = $this->getWriteConnection();
81 $dbw->startAtomic( __METHOD__ );
82 try {
84 ->deleteFrom( 'l10n_cache' )
85 ->where( [ 'lc_lang' => $this->code ] )
86 ->caller( __METHOD__ )->execute();
87 foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
89 ->insertInto( 'l10n_cache' )
90 ->rows( $rows )
91 ->caller( __METHOD__ )->execute();
92 }
93 $this->writesDone = true;
94 } catch ( DBQueryError $e ) {
95 if ( $dbw->isReadOnly() ) {
96 $this->readOnly = true; // just avoid site downtime
97 } else {
98 throw $e;
99 }
100 }
101 $dbw->endAtomic( __METHOD__ );
102 ScopedCallback::consume( $scope );
103
104 $this->code = null;
105 $this->batch = [];
106 }
107
109 public function set( $key, $value ) {
110 if ( $this->readOnly ) {
111 return;
112 } elseif ( $this->code === null ) {
113 throw new LogicException( __CLASS__ . ': must call startWrite() before set()' );
114 }
115
116 $dbw = $this->getWriteConnection();
117
118 $this->batch[] = [
119 'lc_lang' => $this->code,
120 'lc_key' => $key,
121 'lc_value' => $dbw->encodeBlob( serialize( $value ) )
122 ];
123 }
124
128 private function getWriteConnection() {
129 if ( !$this->dbw ) {
130 if ( $this->server ) {
131 $dbFactory = MediaWikiServices::getInstance()->getDatabaseFactory();
132 $this->dbw = $dbFactory->create( $this->server['type'], $this->server );
133 if ( !$this->dbw ) {
134 throw new RuntimeException( __CLASS__ . ': failed to obtain a DB connection' );
135 }
136 } else {
137 $this->dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
138 }
139 }
140
141 return $this->dbw;
142 }
143}
LCStore implementation which uses the standard DB functions to store data.
Definition LCStoreDB.php:17
finishWrite()
Finish a cache write transaction.
Definition LCStoreDB.php:72
startWrite( $code)
Start a cache write transaction.
Definition LCStoreDB.php:58
__construct(array $params)
Definition LCStoreDB.php:33
Service locator for MediaWiki core services.
static instance()
Definition Profiler.php:90
Interface for the persistence layer of LocalisationCache.
Definition LCStore.php:26
Interface to a relational database.
Definition IDatabase.php:31
endAtomic( $fname=__METHOD__)
Ends an atomic section of SQL statements.
newDeleteQueryBuilder()
Get an DeleteQueryBuilder bound to this connection.
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.
newInsertQueryBuilder()
Get an InsertQueryBuilder bound to this connection.
isReadOnly()
Check if this DB server is marked as read-only according to load balancer info.
encodeBlob( $b)
Some DBMSs have a special format for inserting into blob fields, they don't allow simple quoted strin...