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