source: lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/lib/analytics-server/analytics/db.php @ 5560

Last change on this file since 5560 was 5560, checked in by mabarracus, 3 years ago

Complete code rewrite
New database model
Improved performance & optimization
Extended information about clients
Fixed older bugs
New testing framework
Fix postinst exit code

File size: 13.5 KB
Line 
1<?php
2class DB{
3
4        private $dbhost;
5        private $dbname;
6        private $dbuser;
7        private $dbpass;
8        private $alias;
9        public $dbconn;
10
11        function DB(){
12                require_once('config.php');
13                global $dbhost,$dbname,$dbpass,$dbuser,$distros;
14               
15                $this->dbhost=$dbhost;
16                $this->dbname=$dbname;
17                $this->dbpass=$dbpass;
18                $this->dbuser=$dbuser;
19                $this->alias=array();
20                $this->info_distro=json_decode($distros,true);
21                if ($this->info_distro == NULL){
22                    die('Error: Wrong json in Config.php');
23                }
24                $this->init_dates();
25                $this->times=0;
26        }
27        function init_dates(){
28                $this->dates=array();
29                $this->dates['today']=date("Y-m-d");
30                $this->dates['first_current']=date("Y-m-").'01';
31                $this->dates['last_old']=date("Y-m-d",strtotime($this->dates['first_current']." -1 days"));
32                $this->dates['first_old']=date("Y-m-",strtotime($this->dates['today']. "-1 months")).'01';
33                $this->dates['last_very_old']=date("Y-m-d",strtotime($this->dates['first_old']." -1 days"));
34                $this->dates['first_very_old']=date("Y-m-",strtotime($this->dates['first_old']." -1 days")).'01';
35                $this->dates['date_current']="(date between '".$this->dates['first_current']."' and '".$this->dates['today']."')";
36                $this->dates['date_old']="(date between '".$this->dates['first_old']."' and '".$this->dates['last_old']."')";
37                $this->dates['date_very_old']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['last_very_old']."')";
38                $this->dates['date_range_last_three_months']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['today']."')";
39
40        }
41        function connect(){
42                $this->dbconn=new mysqli($this->dbhost, $this->dbuser , $this->dbpass, $this->dbname);
43                if ($this->dbconn->connect_error) {
44                    die('Connect Error:'. $this->dbconn->connect_error);
45                }
46        }
47        function disconnect(){
48                $this->dbconn->close();
49        }
50        function init_trans(){
51                $this->dbconn->autocommit(FALSE);
52                $this->dbconn->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
53        }
54
55        function send_data($user,$version,$sabor,$apps,$date=''){
56            if ($date == ''){
57                $sql="INSERT INTO tmp_clients(user,version,sabor,status) values ('$user','$version','$sabor',0)";
58            }else{
59                $sql="INSERT INTO tmp_clients(user,version,sabor,status,date) values ('$user','$version','$sabor',0,'$date')";
60            }
61            $retry=1;
62            $done=false;
63            $cli_id=false;
64            while (! $done and $retry < 4){
65                $res=$this->dbconn->query($sql);
66                if ($res){
67                    $cli_id=$this->dbconn->insert_id; 
68                    $done=true;
69                }else{
70                    $retry+=1;
71                    sleep($retry);
72                }
73            }
74            if ($retry == 4 or $cli_id == false)
75                    throw new Exception('Error sending client data: '.$this->dbconn->error);
76            $err_apps=false;
77            $err_exception=false;
78            if (count($apps) != 0){
79                if ($date == ''){
80                    $sql="insert into tmp_packages(client,app,value) values";
81                }else{
82                    $sql="insert into tmp_packages(client,app,value,date) values";
83                }
84                $values=array();
85                foreach ($apps as $app => $value){
86                    if (trim($app) == '' or trim($value) == ''){
87                        $err_apps=true;
88                        $err_exception=new Exception('Wrong application values');
89                        continue;
90                    }
91                    if ($date == ''){
92                        $values[]="($cli_id,'$app',$value)";
93                    }else{
94                        $values[]="($cli_id,'$app',$value,'$date')";
95                    }
96                }
97                if (count($values) > 0){
98                    $sql.=implode(',',$values);
99                    $done=false;
100                    $retry=1;
101                    while (! $done and $retry < 4){
102                        $res=$this->dbconn->query($sql);
103                        if ($res){
104                            $done=true;
105                        }else{
106                            $retry += 1;
107                            sleep($retry);
108                        }
109                    }
110                    if ($retry == 4 or ! $done){
111                        $err_apps=true;
112                        $err_exception=new Exception('Error sending client app data: '.$this->dbconn->error.' QUERY='.$sql);
113                    }
114                }
115            }
116            //End operations
117            $sql = "Update tmp_clients set status=1 where id = $cli_id and status=0";
118            $retry=1;
119            $done=false;
120            while (! $done and $retry < 4){
121                $res=$this->dbconn->query($sql);
122                if ($res){
123                    $done=true;
124                }else{
125                    $retry+=1;
126                    sleep($retry);
127                }
128            }
129            if ($retry == 4 or $cli_id == false){
130                throw new Exception('Error commiting client data: '.$this->dbconn->error);
131            }
132            if ($err_apps){
133                throw $err_exception;
134            }
135        }
136
137        private function load_alias(){
138                $sql="SELECT name,alias from Alias";
139                $result=$this->dbconn->query($sql);
140                while($row=$result->fetch_array(MYSQLI_ASSOC)){
141                        $this->alias[$row['name']]=$row['alias'];
142                }
143        }
144        function get_extended_data($app){
145            $today=date("Y-m-d");
146            $min_date=date("Y-m",strtotime($today." -1 year")).'-01';
147            $this->times=0;
148            // CLIENTS DISTRIBUTION PER RELEASE/FLAVOUR
149            $sql="select year(date) as year,month(date) as month,Releases_name,Flavours_name,count(*) as num_hosts from (select distinct Client_uid,date,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' )t group by year,month,Releases_name,Flavours_name order by year Desc,month desc,Releases_name asc,num_hosts desc";
150            $stime=microtime(true);
151            $result=$this->dbconn->query($sql);
152            if ($result){
153                $this->times+=microtime(true)-$stime;
154                $clients_month=[];
155                $tmp=[];
156                while($row=$result->fetch_array(MYSQLI_ASSOC)){
157                    $date=$row['year'].'_'.$row['month'];
158                    $tmp[$date][$row['Releases_name']][$row['Flavours_name']]=intval($row['num_hosts']);
159                }
160                foreach ($tmp as $date){
161                    $clients_month[]=$date;
162                }
163            }else{
164                $clients_month=$this->dbconn->error;
165            }
166            // CLIENT UPDATES
167            $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month having count(Client_uid) >= 1 ) t group by year,month order by year desc,month desc";
168            $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated,Releases_name as rel,Flavours_name as fla from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month,Releases_name,Flavours_name having count(Client_uid) >= 1 ) t group by year,month,Releases_name,Flavours_name order by year desc,month desc";
169            $stime=microtime(true);
170            $result=$this->dbconn->query($sql);
171            if ($result){
172                $this->times+=microtime(true)-$stime;
173                $i=0;
174                $tmp=[];
175                while($row=$result->fetch_array(MYSQLI_ASSOC)){
176                    $date=$row['year'].'_'.$row['month'];
177                    $tmp[$date][$row['rel']][$row['fla']]=intval($row['nclients_updated']);
178                }
179                foreach($tmp as $date){
180                    $num_updates_month[]=$date;
181                }
182            }else{
183                $num_updates_month=$this->dbconn->error;
184            }
185            // CLIENT CHANGE RELEASE
186            $sql="select year,month,count(*) as upgrades_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Releases_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
187            $stime=microtime(true);
188            $result=$this->dbconn->query($sql);
189            if ($result){
190                $this->times+=microtime(true)-$stime;
191                $change_releases=[0,0,0,0,0,0,0,0,0,0,0,0];
192                $i=0;
193                while($row=$result->fetch_array(MYSQLI_ASSOC)){
194                    $change_releases[$i++]=intval($row['upgrades_en_mes']);
195                }
196            }else{
197                $change_releases=$this->dbconn->error;
198            }
199            // CLIENT CHANGE FLAVOUR
200            $sql="select year,month,count(*) as cambio_sabor_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Flavours_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
201            $stime=microtime(true);
202            $result=$this->dbconn->query($sql);
203            if ($result){
204                $this->times+=microtime(true)-$stime;
205                $i=0;
206                $change_flavour=[0,0,0,0,0,0,0,0,0,0,0,0];
207                while($row=$result->fetch_array(MYSQLI_ASSOC)){
208                    $change_flavour[$i++]=intval($row['cambio_sabor_en_mes']);
209                }
210            }else{
211                $change_flavour=$this->dbconn->error;
212            }
213           
214            //sanitize input
215            if ($app != NULL){
216                $app=preg_grep('/^[a-zA-Z0-9\-_]+$/',array($app));
217                if ($app != NULL and isset($app[0])){
218                    $app=$this->dbconn->real_escape_string($app[0]);
219                    $stats['apps']=[];
220                    $stats['apps']['app']=$app;
221                    $sql="select year(date) as year,month(date) as month,string,Releases_name as rel,Flavours_name as fla,sum(count) as count from RecvPackages where string='$app' and date >= '$min_date' group by year,month,Releases_name,Flavours_name order by year desc,month desc,sum(count) desc";
222                    $stime=microtime(true);
223                    $result=$this->dbconn->query($sql);
224                    if ($result){
225                        $this->times+=microtime(true)-$stime;
226                        $tmp=[];
227                        while($row=$result->fetch_array(MYSQLI_ASSOC)){
228                            $date=$row['year'].'_'.$row['month'];
229                            $tmp[$date][$row['rel']][$row['fla']]=intval($row['count']);
230                        }
231                        foreach($tmp as $date){
232                            $app_use[]=$date;
233                        }
234                        $stats['apps']['app_use']=$app_use;
235                    }else{
236                        $app_use=$this->dbconn->error;
237                    }
238                }
239            }
240            // FINALIZATION & WRITE STRUCTURE
241            if (isset($clients_month)){
242                $stats['clients']['clients_per_month']=$clients_month;
243            }
244            if (isset($num_updates_month)){
245                $stats['clients']['freq_updates_per_month']=$num_updates_month;
246            }
247            if (isset($change_releases)){
248                $stats['clients']['change_releases']=$change_releases;
249            }
250            if (isset($change_flavour)){
251                $stats['clients']['change_flavours']=$change_flavour;
252            }
253            $stats['debug_query_time']=strval(number_format($this->times,5));
254            return json_encode($stats);
255        }
256
257        function get_historic_data(){
258                $this->load_alias();
259                $obj=[];
260                $this->times=0;
261                foreach ($this->info_distro['distros'] as $distro){
262                        $dname=$distro['name'];
263                        $dlike=$distro['like'];
264                        $obj[$dname]=array();
265                        foreach ($distro['sabor'] as $sabor){
266                                $sname=$sabor['name'];
267                                $slike=$sabor['like'];
268                                $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'current');
269                                $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'old');
270                                $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'very_old');
271                        }
272                }
273                $obj['debug_query_time']=strval(number_format($this->times,3));
274                return json_encode($obj);
275        }
276        function get_chart($version='',$sabor='',$type='current'){
277                if ($version != ''){
278                    $version = " and Releases_name = '$version' ";
279                }
280                if ($sabor != ''){
281                    $sabor = " and Flavours_name = '$sabor' ";
282                }
283                $order=" order by count desc limit 10 ";
284                $group=" group by app ";
285               
286                $where=$this->dates['date_'.$type]." $version $sabor ";
287                $where_clients=$this->dates['date_'.$type]." $version $sabor ";
288
289                $sql="SELECT string as app,sum(count) as count from RecvPackages where $where $group $order";
290                $sql_clients = "select count(distinct Client_uid) as count from Client_Versions where $where_clients $order";
291
292                return array($this->get_result_from_sql($sql),$this->get_clients_from_sql($sql_clients));
293        }
294        function get_clients_from_sql($sql){
295                $stime=microtime(true);
296                if ($result=$this->dbconn->query($sql)){
297                        $etime=microtime(true);
298                        $this->times+=($etime-$stime);
299                        while($row=$result->fetch_array(MYSQLI_ASSOC)){
300                                if (isset($row['count'])){
301                                        return array('nclients'=>$row['count']);
302                                }
303                        }
304                        return array('nclients'=>'not available');
305                }else{
306                        return array('nclients'=>$this->dbconn->error);
307                }
308               
309        }
310        function get_result_from_sql($sql){
311                $stime=microtime(true);
312                if ($result=$this->dbconn->query($sql)){
313                        $etime=microtime(true);
314                        $this->times+=($etime-$stime);
315                        $obj2=[];
316                        $nobj=0;
317                        while($row=$result->fetch_array(MYSQLI_ASSOC)){
318                                if (array_key_exists($row['app'],$this->alias)){
319                                        if (! empty($this->alias[$row['app']])){
320                                                if ($nobj < 10)
321                                                        $obj2[$this->alias[$row['app']]]=$row['count'];
322                                                $nobj++;
323                                        }
324                                }else{
325                                        if ($nobj < 10)
326                                                $obj2[$row['app']]=$row['count'];
327                                        $nobj++;
328                                }
329                        }
330                        return $obj2;
331                }else{
332                    return $this->dbconn->error;
333                }
334        }
335
336} 
337
338?>
Note: See TracBrowser for help on using the repository browser.