]> git.mxchange.org Git - friendica.git/blob - src/Worker/DBClean.php
Use short form array syntax everywhere
[friendica.git] / src / Worker / DBClean.php
1 <?php
2 /**
3  * @file src/Worker/DBClean.php
4  * @brief The script is called from time to time to clean the database entries and remove orphaned data.
5  */
6
7 namespace Friendica\Worker;
8
9 use Friendica\Core\Config;
10 use Friendica\Core\Worker;
11 use dba;
12
13 require_once 'include/dba.php';
14
15 class DBClean {
16         public static function execute($stage = 0) {
17
18                 if (!Config::get('system', 'dbclean', false)) {
19                         return;
20                 }
21
22                 if ($stage == 0) {
23                         self::forkCleanProcess();
24                 } else {
25                         self::removeOrphans($stage);
26                 }
27         }
28
29         /**
30          * @brief Fork the different DBClean processes
31          */
32         private static function forkCleanProcess() {
33                 // Get the expire days for step 8 and 9
34                 $days = Config::get('system', 'dbclean-expire-days', 0);
35
36                 for ($i = 1; $i <= 10; $i++) {
37                         // Execute the background script for a step when it isn't finished.
38                         // Execute step 8 and 9 only when $days is defined.
39                         if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($i > 9) || ($days > 0))) {
40                                 Worker::add(PRIORITY_LOW, 'DBClean', $i);
41                         }
42                 }
43         }
44
45         /**
46          * @brief Remove orphaned database entries
47          * @param integer $stage What should be deleted?
48          *
49          * Values for $stage:
50          * ------------------
51          *  1:  Old global item entries from item table without user copy.
52          *  2:  Items without parents.
53          *  3:  Orphaned data from thread table.
54          *  4:  Orphaned data from notify table.
55          *  5:  Orphaned data from notify-threads table.
56          *  6:  Orphaned data from sign table.
57          *  7:  Orphaned data from term table.
58          *  8:  Expired threads.
59          *  9:  Old global item entries from expired threads.
60          * 10:  Old conversations.
61          */
62         private static function removeOrphans($stage) {
63                 global $db;
64
65                 $count = 0;
66
67                 // We split the deletion in many small tasks
68                 $limit = 1000;
69
70                 // Get the expire days for step 8 and 9
71                 $days = Config::get('system', 'dbclean-expire-days', 0);
72
73                 if ($stage == 1) {
74                         $last_id = Config::get('system', 'dbclean-last-id-1', 0);
75
76                         logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id);
77                         $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
78                                                 NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
79                                                 `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ?
80                                         ORDER BY `id` LIMIT ".intval($limit), $last_id);
81                         $count = dba::num_rows($r);
82                         if ($count > 0) {
83                                 logger("found global item orphans: ".$count);
84                                 while ($orphan = dba::fetch($r)) {
85                                         $last_id = $orphan["id"];
86                                         dba::delete('item', ['id' => $orphan["id"]]);
87                                 }
88                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 1, $last_id);
89                         } else {
90                                 logger("No global item orphans found");
91                         }
92                         dba::close($r);
93                         logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id);
94
95                         Config::set('system', 'dbclean-last-id-1', $last_id);
96                 } elseif ($stage == 2) {
97                         $last_id = Config::get('system', 'dbclean-last-id-2', 0);
98
99                         logger("Deleting items without parents. Last ID: ".$last_id);
100                         $r = dba::p("SELECT `id` FROM `item`
101                                         WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`)
102                                         AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id);
103                         $count = dba::num_rows($r);
104                         if ($count > 0) {
105                                 logger("found item orphans without parents: ".$count);
106                                 while ($orphan = dba::fetch($r)) {
107                                         $last_id = $orphan["id"];
108                                         dba::delete('item', ['id' => $orphan["id"]]);
109                                 }
110                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 2, $last_id);
111                         } else {
112                                 logger("No item orphans without parents found");
113                         }
114                         dba::close($r);
115                         logger("Done deleting ".$count." items without parents. Last ID: ".$last_id);
116
117                         Config::set('system', 'dbclean-last-id-2', $last_id);
118
119                         if ($count < $limit) {
120                                 Config::set('system', 'finished-dbclean-2', true);
121                         }
122                 } elseif ($stage == 3) {
123                         $last_id = Config::get('system', 'dbclean-last-id-3', 0);
124
125                         logger("Deleting orphaned data from thread table. Last ID: ".$last_id);
126                         $r = dba::p("SELECT `iid` FROM `thread`
127                                         WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ?
128                                         ORDER BY `iid` LIMIT ".intval($limit), $last_id);
129                         $count = dba::num_rows($r);
130                         if ($count > 0) {
131                                 logger("found thread orphans: ".$count);
132                                 while ($orphan = dba::fetch($r)) {
133                                         $last_id = $orphan["iid"];
134                                         dba::delete('thread', ['iid' => $orphan["iid"]]);
135                                 }
136                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 3, $last_id);
137                         } else {
138                                 logger("No thread orphans found");
139                         }
140                         dba::close($r);
141                         logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id);
142
143                         Config::set('system', 'dbclean-last-id-3', $last_id);
144
145                         if ($count < $limit) {
146                                 Config::set('system', 'finished-dbclean-3', true);
147                         }
148                 } elseif ($stage == 4) {
149                         $last_id = Config::get('system', 'dbclean-last-id-4', 0);
150
151                         logger("Deleting orphaned data from notify table. Last ID: ".$last_id);
152                         $r = dba::p("SELECT `iid`, `id` FROM `notify`
153                                         WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ?
154                                         ORDER BY `id` LIMIT ".intval($limit), $last_id);
155                         $count = dba::num_rows($r);
156                         if ($count > 0) {
157                                 logger("found notify orphans: ".$count);
158                                 while ($orphan = dba::fetch($r)) {
159                                         $last_id = $orphan["id"];
160                                         dba::delete('notify', ['iid' => $orphan["iid"]]);
161                                 }
162                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 4, $last_id);
163                         } else {
164                                 logger("No notify orphans found");
165                         }
166                         dba::close($r);
167                         logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id);
168
169                         Config::set('system', 'dbclean-last-id-4', $last_id);
170
171                         if ($count < $limit) {
172                                 Config::set('system', 'finished-dbclean-4', true);
173                         }
174                 } elseif ($stage == 5) {
175                         $last_id = Config::get('system', 'dbclean-last-id-5', 0);
176
177                         logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id);
178                         $r = dba::p("SELECT `id` FROM `notify-threads`
179                                         WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ?
180                                         ORDER BY `id` LIMIT ".intval($limit), $last_id);
181                         $count = dba::num_rows($r);
182                         if ($count > 0) {
183                                 logger("found notify-threads orphans: ".$count);
184                                 while ($orphan = dba::fetch($r)) {
185                                         $last_id = $orphan["id"];
186                                         dba::delete('notify-threads', ['id' => $orphan["id"]]);
187                                 }
188                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 5, $last_id);
189                         } else {
190                                 logger("No notify-threads orphans found");
191                         }
192                         dba::close($r);
193                         logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id);
194
195                         Config::set('system', 'dbclean-last-id-5', $last_id);
196
197                         if ($count < $limit) {
198                                 Config::set('system', 'finished-dbclean-5', true);
199                         }
200                 } elseif ($stage == 6) {
201                         $last_id = Config::get('system', 'dbclean-last-id-6', 0);
202
203                         logger("Deleting orphaned data from sign table. Last ID: ".$last_id);
204                         $r = dba::p("SELECT `iid`, `id` FROM `sign`
205                                         WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ?
206                                         ORDER BY `id` LIMIT ".intval($limit), $last_id);
207                         $count = dba::num_rows($r);
208                         if ($count > 0) {
209                                 logger("found sign orphans: ".$count);
210                                 while ($orphan = dba::fetch($r)) {
211                                         $last_id = $orphan["id"];
212                                         dba::delete('sign', ['iid' => $orphan["iid"]]);
213                                 }
214                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 6, $last_id);
215                         } else {
216                                 logger("No sign orphans found");
217                         }
218                         dba::close($r);
219                         logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id);
220
221                         Config::set('system', 'dbclean-last-id-6', $last_id);
222
223                         if ($count < $limit) {
224                                 Config::set('system', 'finished-dbclean-6', true);
225                         }
226                 } elseif ($stage == 7) {
227                         $last_id = Config::get('system', 'dbclean-last-id-7', 0);
228
229                         logger("Deleting orphaned data from term table. Last ID: ".$last_id);
230                         $r = dba::p("SELECT `oid`, `tid` FROM `term`
231                                         WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ?
232                                         ORDER BY `tid` LIMIT ".intval($limit), $last_id);
233                         $count = dba::num_rows($r);
234                         if ($count > 0) {
235                                 logger("found term orphans: ".$count);
236                                 while ($orphan = dba::fetch($r)) {
237                                         $last_id = $orphan["tid"];
238                                         dba::delete('term', ['oid' => $orphan["oid"]]);
239                                 }
240                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 7, $last_id);
241                         } else {
242                                 logger("No term orphans found");
243                         }
244                         dba::close($r);
245                         logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id);
246
247                         Config::set('system', 'dbclean-last-id-7', $last_id);
248
249                         if ($count < $limit) {
250                                 Config::set('system', 'finished-dbclean-7', true);
251                         }
252                 } elseif ($stage == 8) {
253                         if ($days <= 0) {
254                                 return;
255                         }
256
257                         $last_id = Config::get('system', 'dbclean-last-id-8', 0);
258
259                         logger("Deleting expired threads. Last ID: ".$last_id);
260                         $r = dba::p("SELECT `thread`.`iid` FROM `thread`
261                                         INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts`
262                                         WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY
263                                                 AND NOT `thread`.`mention` AND NOT `thread`.`starred`
264                                                 AND NOT `thread`.`wall` AND NOT `thread`.`origin`
265                                                 AND `thread`.`uid` != 0 AND `thread`.`iid` >= ?
266                                                 AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item`
267                                                                 WHERE (`item`.`starred` OR (`item`.`resource-id` != '')
268                                                                         OR (`item`.`file` != '') OR (`item`.`event-id` != '')
269                                                                         OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`)
270                                                                         AND `item`.`parent` = `thread`.`iid`)
271                                         ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id);
272                         $count = dba::num_rows($r);
273                         if ($count > 0) {
274                                 logger("found expired threads: ".$count);
275                                 while ($thread = dba::fetch($r)) {
276                                         $last_id = $thread["iid"];
277                                         dba::delete('thread', ['iid' => $thread["iid"]]);
278                                 }
279                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 8, $last_id);
280                         } else {
281                                 logger("No expired threads found");
282                         }
283                         dba::close($r);
284                         logger("Done deleting ".$count." expired threads. Last ID: ".$last_id);
285
286                         Config::set('system', 'dbclean-last-id-8', $last_id);
287                 } elseif ($stage == 9) {
288                         if ($days <= 0) {
289                                 return;
290                         }
291
292                         $last_id = Config::get('system', 'dbclean-last-id-9', 0);
293                         $till_id = Config::get('system', 'dbclean-last-id-8', 0);
294
295                         logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id);
296                         $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
297                                                 NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
298                                                 `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ?
299                                         ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id);
300                         $count = dba::num_rows($r);
301                         if ($count > 0) {
302                                 logger("found global item entries from expired threads: ".$count);
303                                 while ($orphan = dba::fetch($r)) {
304                                         $last_id = $orphan["id"];
305                                         dba::delete('item', ['id' => $orphan["id"]]);
306                                 }
307                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 9, $last_id);
308                         } else {
309                                 logger("No global item entries from expired threads");
310                         }
311                         dba::close($r);
312                         logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id);
313
314                         Config::set('system', 'dbclean-last-id-9', $last_id);
315                 } elseif ($stage == 10) {
316                         $last_id = Config::get('system', 'dbclean-last-id-10', 0);
317
318                         logger("Deleting old conversations. Last created: ".$last_id);
319                         $r = dba::p("SELECT `received`, `item-uri` FROM `conversation`
320                                         WHERE `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY
321                                         ORDER BY `received` LIMIT ".intval($limit));
322                         $count = dba::num_rows($r);
323                         if ($count > 0) {
324                                 logger("found old conversations: ".$count);
325                                 while ($orphan = dba::fetch($r)) {
326                                         $last_id = $orphan["received"];
327                                         dba::delete('conversation', ['item-uri' => $orphan["item-uri"]]);
328                                 }
329                                 Worker::add(PRIORITY_MEDIUM, 'DBClean', 10, $last_id);
330                         } else {
331                                 logger("No old conversations found");
332                         }
333                         dba::close($r);
334                         logger("Done deleting ".$count." conversations. Last created: ".$last_id);
335
336                         Config::set('system', 'dbclean-last-id-10', $last_id);
337                 }
338         }
339 }