Merge "Parse wikitext in gallery caption"
[lhc/web/wiklou.git] / includes / deferred / WANCacheReapUpdate.php
1 <?php
2
3 use MediaWiki\Linker\LinkTarget;
4 use Psr\Log\LoggerInterface;
5 use Wikimedia\Rdbms\IDatabase;
6
7 /**
8 * Class for fixing stale WANObjectCache keys using a purge event source
9 *
10 * This is useful for expiring keys that missed fire-and-forget purges. This uses the
11 * recentchanges table as a reliable stream to make certain keys reach consistency
12 * as soon as the underlying replica database catches up. These means that critical
13 * keys will not escape getting purged simply due to brief hiccups in the network,
14 * which are more prone to happen across datacenters.
15 *
16 * ----
17 * "I was trying to cheat death. I was only trying to surmount for a little while the
18 * darkness that all my life I surely knew was going to come rolling in on me some day
19 * and obliterate me. I was only to stay alive a little brief while longer, after I was
20 * already gone. To stay in the light, to be with the living, a little while past my time."
21 * -- Notes for "Blues of a Lifetime", by [[Cornell Woolrich]]
22 *
23 * @since 1.28
24 */
25 class WANCacheReapUpdate implements DeferrableUpdate {
26 /** @var IDatabase */
27 private $db;
28 /** @var LoggerInterface */
29 private $logger;
30
31 /**
32 * @param IDatabase $db
33 * @param LoggerInterface $logger
34 */
35 public function __construct( IDatabase $db, LoggerInterface $logger ) {
36 $this->db = $db;
37 $this->logger = $logger;
38 }
39
40 function doUpdate() {
41 $reaper = new WANObjectCacheReaper(
42 ObjectCache::getMainWANInstance(),
43 ObjectCache::getLocalClusterInstance(),
44 [ $this, 'getTitleChangeEvents' ],
45 [ $this, 'getEventAffectedKeys' ],
46 [
47 'channel' => 'table:recentchanges:' . $this->db->getDomainID(),
48 'logger' => $this->logger
49 ]
50 );
51
52 $reaper->invoke( 100 );
53 }
54
55 /**
56 * @see WANObjectCacheRepear
57 *
58 * @param int $start
59 * @param int $id
60 * @param int $end
61 * @param int $limit
62 * @return TitleValue[]
63 */
64 public function getTitleChangeEvents( $start, $id, $end, $limit ) {
65 $db = $this->db;
66 $encStart = $db->addQuotes( $db->timestamp( $start ) );
67 $encEnd = $db->addQuotes( $db->timestamp( $end ) );
68 $id = (int)$id; // cast NULL => 0 since rc_id is an integer
69
70 $res = $db->select(
71 'recentchanges',
72 [ 'rc_namespace', 'rc_title', 'rc_timestamp', 'rc_id' ],
73 [
74 $db->makeList( [
75 "rc_timestamp > $encStart",
76 "rc_timestamp = $encStart AND rc_id > " . $db->addQuotes( $id )
77 ], LIST_OR ),
78 "rc_timestamp < $encEnd"
79 ],
80 __METHOD__,
81 [ 'ORDER BY' => 'rc_timestamp ASC, rc_id ASC', 'LIMIT' => $limit ]
82 );
83
84 $events = [];
85 foreach ( $res as $row ) {
86 $events[] = [
87 'id' => (int)$row->rc_id,
88 'pos' => (int)wfTimestamp( TS_UNIX, $row->rc_timestamp ),
89 'item' => new TitleValue( (int)$row->rc_namespace, $row->rc_title )
90 ];
91 }
92
93 return $events;
94 }
95
96 /**
97 * Gets a list of important cache keys associated with a title
98 *
99 * @see WANObjectCacheRepear
100 * @param WANObjectCache $cache
101 * @param LinkTarget $t
102 * @return string[]
103 */
104 public function getEventAffectedKeys( WANObjectCache $cache, LinkTarget $t ) {
105 /** @var WikiPage[]|LocalFile[]|User[] $entities */
106 $entities = [];
107
108 // You can't create a WikiPage for special pages (-1) or other virtual
109 // namespaces, but special pages do appear in RC sometimes, e.g. for logs
110 // of AbuseFilter filter changes.
111 if ( $t->getNamespace() >= 0 ) {
112 $entities[] = WikiPage::factory( Title::newFromLinkTarget( $t ) );
113 }
114
115 if ( $t->inNamespace( NS_FILE ) ) {
116 $entities[] = wfLocalFile( $t->getText() );
117 }
118 if ( $t->inNamespace( NS_USER ) ) {
119 $entities[] = User::newFromName( $t->getText(), false );
120 }
121
122 $keys = [];
123 foreach ( $entities as $entity ) {
124 if ( $entity ) {
125 $keys = array_merge( $keys, $entity->getMutableCacheKeys( $cache ) );
126 }
127 }
128 if ( $keys ) {
129 $this->logger->debug( __CLASS__ . ': got key(s) ' . implode( ', ', $keys ) );
130 }
131
132 return $keys;
133 }
134 }