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