Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 246 lines (214 sloc) 11.516 kB
0dee125 base for sss3
tommyrot authored
1 <?php
2
3 /**
4187828 @tommyrot badger badger badger badger badger badger badger badger badger badger…
authored
4 * Copyright (c) 2007-2012, Jos de Ruijter <jos@dutnie.nl>
0dee125 base for sss3
tommyrot authored
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /**
20 * Class for performing database maintenance. Crucial to keep data up2date and usable.
21 */
22 final class maintenance extends base
23 {
24 /**
25 * Variables that shouldn't be tampered with.
26 */
27 private $mysqli;
28 private $settings_list = array('outputbits' => 'int');
29
30 public function __construct($settings)
31 {
c71d463 @tommyrot 5.0
authored
32 /**
33 * The variables that are listed in $settings_list will have their values overridden by those found in the config file.
34 */
0dee125 base for sss3
tommyrot authored
35 foreach ($this->settings_list as $key => $type) {
36 if (!array_key_exists($key, $settings)) {
37 continue;
38 }
39
40 if ($type == 'string') {
41 $this->$key = $settings[$key];
42 } elseif ($type == 'int') {
43 $this->$key = (int) $settings[$key];
44 } elseif ($type == 'bool') {
55fda21 test on strtolower instead of strtoupper coz of change in case style
tommyrot authored
45 if (strtolower($settings[$key]) == 'true') {
0dee125 base for sss3
tommyrot authored
46 $this->$key = true;
55fda21 test on strtolower instead of strtoupper coz of change in case style
tommyrot authored
47 } elseif (strtolower($settings[$key]) == 'false') {
0dee125 base for sss3
tommyrot authored
48 $this->$key = false;
49 }
50 }
51 }
52 }
53
ebb34a3 @tommyrot calculate milestones
authored
54 private function calculate_milestones()
1bf9e43 @tommyrot milestones part 2
authored
55 {
56 $query = @mysqli_query($this->mysqli, 'select `q_activity_by_day`.`ruid`, `date`, `l_total` from `q_activity_by_day` join `user_status` on `q_activity_by_day`.`ruid` = `user_status`.`uid` where `status` != 3 order by `ruid` asc, `date` asc') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
57 $rows = mysqli_num_rows($query);
58
59 /**
60 * If there is no user activity we can stop here.
61 */
62 if (empty($rows)) {
63 return null;
64 }
65
66 $values = '';
67
68 while ($result = mysqli_fetch_object($query)) {
69 if (!isset($l_total[(int) $result->ruid])) {
70 $l_total[(int) $result->ruid] = (int) $result->l_total;
71 $milestones = array(1000, 2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000);
72 $nextmilestone = array_shift($milestones);
73 } else {
74 $l_total[(int) $result->ruid] += (int) $result->l_total;
75 }
76
77 while (!is_null($nextmilestone) && $l_total[(int) $result->ruid] >= $nextmilestone) {
78 $values .= ', ('.$result->ruid.', '.$nextmilestone.', \''.$result->date.'\')';
79 $nextmilestone = array_shift($milestones);
80 }
81 }
82
83 if (!empty($values)) {
5362fb5 @tommyrot truncate before insert
authored
84 @mysqli_query($this->mysqli, 'truncate table `q_milestones`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
1bf9e43 @tommyrot milestones part 2
authored
85 @mysqli_query($this->mysqli, 'insert into `q_milestones` (`ruid`, `milestone`, `date`) values '.ltrim($values, ', ')) or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
86 }
87 }
88
ebb34a3 @tommyrot calculate milestones
authored
89 public function do_maintenance($mysqli)
90 {
91 $this->mysqli = $mysqli;
92 $this->output('notice', 'do_maintenance(): performing database maintenance routines');
93 $query = @mysqli_query($this->mysqli, 'select count(*) as `usercount` from `user_status`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
94 $rows = mysqli_num_rows($query);
95
96 if (!empty($rows)) {
97 $result = mysqli_fetch_object($query);
98 }
99
100 if (empty($result->usercount)) {
101 $this->output('warning', 'do_maintenance(): database is empty, nothing to do');
102 } else {
103 $this->fix_user_status_errors();
104 $this->register_most_active_alias();
105 $this->make_materialized_views();
106 $this->calculate_milestones();
107 $this->output('notice', 'do_maintenance(): maintenance completed');
108 }
109 }
110
0dee125 base for sss3
tommyrot authored
111 /**
62f5e2e various small fixes and polishing
tommyrot authored
112 * Fix user status errors.
0dee125 base for sss3
tommyrot authored
113 *
114 * | uid | ruid | status | type
115 * +------------+---------------+---------------+----------------------------------
116 * | x | x | 0 | unlinked (default)
117 * | x | x | 1 | registered nick, can have aliases
118 * | x | y | 2 | alias
119 * | x | x | 3 | registered bot, can have aliases
120 *
121 * Conditions that don't fit the schema depicted above will be set to the default, unlinked state.
122 */
123 private function fix_user_status_errors()
124 {
125 /**
126 * Nicks with uid = ruid can only have status = 0, 1 or 3. Set back to 0 if status = 2.
127 */
5117f33 @tommyrot fix a wrong sql query which can cause sss to exit when manually linki…
authored
128 @mysqli_query($this->mysqli, 'update `user_status` set `status` = 0 where `uid` = `ruid` and `status` = 2') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
4c8483e @tommyrot cleaner way of doing debug messages
authored
129 $rows_affected = mysqli_affected_rows($this->mysqli);
130
131 if (!empty($rows_affected)) {
132 $this->output('debug', 'fix_user_status_errors(): '.$rows_affected.' uid'.(($rows_affected > 1) ? 's' : '').' set to default (alias of self)');
133 }
0dee125 base for sss3
tommyrot authored
134
135 /**
136 * Nicks with uid != ruid can only have status = 2. Set back to 0 if status != 2 and set uid = ruid accordingly.
137 */
c91713f @tommyrot set ruid=uid instead of the other way around. uid is primary, ruid ca…
authored
138 @mysqli_query($this->mysqli, 'update `user_status` set `ruid` = `uid`, `status` = 0 where `uid` != `ruid` and `status` != 2') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
4c8483e @tommyrot cleaner way of doing debug messages
authored
139 $rows_affected = mysqli_affected_rows($this->mysqli);
140
141 if (!empty($rows_affected)) {
142 $this->output('debug', 'fix_user_status_errors(): '.$rows_affected.' uid'.(($rows_affected > 1) ? 's' : '').' set to default (alias with invalid status)');
143 }
0dee125 base for sss3
tommyrot authored
144
145 /**
c71d463 @tommyrot 5.0
authored
146 * Every alias must have their ruid set to the uid of a registered nick, which in turn has uid = ruid and status = 1 or 3. Unlink aliases
147 * pointing to non ruids.
0dee125 base for sss3
tommyrot authored
148 */
3bd21ab @tommyrot trivial order and output
authored
149 $query = @mysqli_query($this->mysqli, 'select `ruid` from `user_status` where `status` in (1,3) order by `uid` asc') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
0264c51 run less queries to do the same, make debug messages a bit less cryptic
tommyrot authored
150 $rows = mysqli_num_rows($query);
0dee125 base for sss3
tommyrot authored
151
152 if (!empty($rows)) {
5117f33 @tommyrot fix a wrong sql query which can cause sss to exit when manually linki…
authored
153 $ruids = '';
0dee125 base for sss3
tommyrot authored
154
0264c51 run less queries to do the same, make debug messages a bit less cryptic
tommyrot authored
155 while ($result = mysqli_fetch_object($query)) {
5117f33 @tommyrot fix a wrong sql query which can cause sss to exit when manually linki…
authored
156 $ruids .= ','.$result->ruid;
157 }
158
159 if (!empty($ruids)) {
c91713f @tommyrot set ruid=uid instead of the other way around. uid is primary, ruid ca…
authored
160 @mysqli_query($this->mysqli, 'update `user_status` set `ruid` = `uid`, `status` = 0 where `status` = 2 and `ruid` not in ('.ltrim($ruids, ',').')') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
4c8483e @tommyrot cleaner way of doing debug messages
authored
161 $rows_affected = mysqli_affected_rows($this->mysqli);
162
163 if (!empty($rows_affected)) {
164 $this->output('debug', 'fix_user_status_errors(): '.$rows_affected.' uid'.(($rows_affected > 1) ? 's' : '').' set to default (alias of non registered)');
165 }
0dee125 base for sss3
tommyrot authored
166 }
167 }
168 }
169
170 /**
c71d463 @tommyrot 5.0
authored
171 * Make materialized views, which are stored copies of dynamic views. Query tables are top level materialized views based on various sub views and
172 * contain accumulated stats per ruid. Legend: mv_ materialized view, q_ query table, t_ template, v_ view. Combinations do exist.
0dee125 base for sss3
tommyrot authored
173 */
174 private function make_materialized_views()
175 {
176 /**
177 * Create materialized views based on templates.
178 */
179 $tables = array('activedays', 'events', 'ex_actions', 'ex_exclamations', 'ex_kicked', 'ex_kicks', 'ex_questions', 'ex_uppercased', 'lines', 'quote');
180
181 foreach ($tables as $table) {
182 @mysqli_query($this->mysqli, 'drop table if exists `new_mv_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
183 @mysqli_query($this->mysqli, 'create table `new_mv_'.$table.'` like `t_mv_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
184 @mysqli_query($this->mysqli, 'insert into `new_mv_'.$table.'` select * from `v_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
185 @mysqli_query($this->mysqli, 'drop table if exists `mv_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
186 @mysqli_query($this->mysqli, 'rename table `new_mv_'.$table.'` to `mv_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
187 }
188
189 /**
190 * Create query tables based on templates and possibly *requiring* previously created materialized views.
191 */
192 $tables = array('activity_by_day', 'activity_by_month', 'activity_by_year', 'events', 'lines', 'smileys');
193
194 foreach ($tables as $table) {
195 @mysqli_query($this->mysqli, 'drop table if exists `new_q_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
196 @mysqli_query($this->mysqli, 'create table `new_q_'.$table.'` like `t_q_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
197 @mysqli_query($this->mysqli, 'insert into `new_q_'.$table.'` select * from `v_q_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
198 @mysqli_query($this->mysqli, 'drop table if exists `q_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
199 @mysqli_query($this->mysqli, 'rename table `new_q_'.$table.'` to `q_'.$table.'`') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
200 }
201 }
202
203 /**
204 * Make the alias with the most lines the new registered nick for the user or bot it is linked to.
205 */
206 private function register_most_active_alias()
207 {
208 /**
fc0e5d8 @tommyrot rewrite some comments and change the debug message to something reada…
authored
209 * Find out which alias (uid) has the most lines for each registered user or bot (ruid).
0dee125 base for sss3
tommyrot authored
210 */
3bd21ab @tommyrot trivial order and output
authored
211 $query = @mysqli_query($this->mysqli, 'select `ruid`, `csnick`, (select `user_status`.`uid` from `user_status` join `user_lines` on `user_status`.`uid` = `user_lines`.`uid` where `ruid` = `t1`.`ruid` order by `l_total` desc, `user_status`.`uid` asc limit 1) as `uid`, `status` from `user_status` as `t1` join `user_details` on `t1`.`uid` = `user_details`.`uid` where `status` in (1,3)') or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
01e0c7c @tommyrot improve register_most_active_alias() by having it use one query total…
authored
212 $rows = mysqli_num_rows($query);
0dee125 base for sss3
tommyrot authored
213
214 if (empty($rows)) {
c71d463 @tommyrot 5.0
authored
215 return null;
0dee125 base for sss3
tommyrot authored
216 }
217
01e0c7c @tommyrot improve register_most_active_alias() by having it use one query total…
authored
218 while ($result = mysqli_fetch_object($query)) {
219 /**
fc0e5d8 @tommyrot rewrite some comments and change the debug message to something reada…
authored
220 * No records need to be updated if:
221 * - All aliases linked to the registered user or bot have zero lines. The uid value will be null in this case.
222 * - The alias with the most lines is already set to be the registered user or bot.
01e0c7c @tommyrot improve register_most_active_alias() by having it use one query total…
authored
223 */
fc0e5d8 @tommyrot rewrite some comments and change the debug message to something reada…
authored
224 if (!is_null($result->uid) && $result->uid != $result->ruid) {
225 $registered = $result->csnick;
226 $query_alias = @mysqli_query($this->mysqli, 'select `csnick` from `user_details` where `uid` = '.$result->uid) or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
227 $result_alias = mysqli_fetch_object($query_alias);
228 $alias = $result_alias->csnick;
229
0dee125 base for sss3
tommyrot authored
230 /**
c1e59c5 @tommyrot wasnt finished updating the comments yet, here we go
authored
231 * Update records:
c71d463 @tommyrot 5.0
authored
232 * - Make the alias (uid) the new registered nick for the user or bot by setting ruid = uid. The status will be set to either
233 * 1 or 3, identical to previous value.
234 * - Update the ruid field of all records that still point to the old registered nick (ruid) and set it to the new one (uid).
235 * Explicitly set the status to 2 so all records including the old registered nick are marked as alias.
0dee125 base for sss3
tommyrot authored
236 */
01e0c7c @tommyrot improve register_most_active_alias() by having it use one query total…
authored
237 @mysqli_query($this->mysqli, 'update `user_status` set `ruid` = '.$result->uid.', `status` = '.$result->status.' where `uid` = '.$result->uid) or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
238 @mysqli_query($this->mysqli, 'update `user_status` set `ruid` = '.$result->uid.', `status` = 2 where `ruid` = '.$result->ruid) or $this->output('critical', 'mysqli: '.mysqli_error($this->mysqli));
fc0e5d8 @tommyrot rewrite some comments and change the debug message to something reada…
authored
239 $this->output('debug', 'register_most_active_alias(): \''.$alias.'\' set to new registered for \''.$registered.'\'');
0dee125 base for sss3
tommyrot authored
240 }
241 }
242 }
243 }
244
245 ?>
Something went wrong with that request. Please try again.