[Non-ACR] SAM Score improvement changes in global variables
[platform/core/pim/contacts-service.git] / server / ctsvc_server_bg.c
1 /*
2  * Contact Service
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <glib.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include <account.h>
25
26 #include "contacts.h"
27 #include "ctsvc_internal.h"
28 #include "ctsvc_inotify.h"
29 #include "ctsvc_handle.h"
30 #include "ctsvc_db_schema.h"
31 #include "ctsvc_db_sqlite.h"
32 #include "ctsvc_server_service.h"
33 #include "ctsvc_server_bg.h"
34 #include "ctsvc_server_utils.h"
35 #include "ctsvc_db_utils.h"
36 #include "ctsvc_db_plugin_addressbook_helper.h"
37 #include "ctsvc_db_access_control.h"
38
39 #define CTSVC_SERVER_BG_DELETE_COUNT 50
40 #define CTSVC_SERVER_BG_DELETE_STEP_TIME 1
41 #define CTSVC_SERVER_BG_DELETE_THREAD "ctsvc_server_bg_delete"
42
43 #define CTSVC_SERVER_BG_BASE_CPU_USAGE 10  /* Delete contacts when cpu usage is under the value */
44
45 typedef enum {
46         STEP_1, /* get contact_ids */
47         STEP_2, /* delete data */
48         STEP_3, /* delete activity */
49         STEP_4, /* delete search_index, contact(image by trigger) */
50 } __ctsvc_delete_step_e;
51
52 typedef struct {
53         GSList *contact_ids;
54         int current_contact_id;
55         __ctsvc_delete_step_e step;
56 } __ctsvc_delete_data_s;
57
58 static GThread *__ctsvc_server_bg_delete_thread = NULL;
59 static GCond __ctsvc_server_bg_delete_cond;
60 static GMutex __ctsvc_server_bg_delete_mutex;
61
62 static account_subscribe_h account = NULL;
63
64 static int __ctsvc_server_bg_contact_delete_step1(__ctsvc_delete_data_s *data)
65 {
66         char query[CTS_SQL_MIN_LEN] = {0,};
67         int ret;
68         cts_stmt stmt = NULL;
69         int count = 0;
70         GSList *cursor;
71
72         if (data->contact_ids == NULL) {
73                 /* get event_list */
74                 snprintf(query, sizeof(query), "SELECT contact_id FROM "CTS_TABLE_CONTACTS" WHERE deleted = 1");
75                 ret = ctsvc_query_prepare(query, &stmt);
76                 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
77
78                 while (1 == (ret = ctsvc_stmt_step(stmt))) {
79                         int id = 0;
80                         id = ctsvc_stmt_get_int(stmt, 0);
81                         data->contact_ids = g_slist_append(data->contact_ids, GINT_TO_POINTER(id));
82                 }
83                 ctsvc_stmt_finalize(stmt);
84                 if (ret < CONTACTS_ERROR_NONE)
85                         return ret;
86         }
87
88         count = g_slist_length(data->contact_ids);
89         if (count <= 0)
90                 return CONTACTS_ERROR_NO_DATA;
91
92         cursor = g_slist_nth(data->contact_ids, 0);
93         if (cursor) {
94                 data->current_contact_id = GPOINTER_TO_INT(cursor->data);
95                 data->contact_ids = g_slist_remove(data->contact_ids, GINT_TO_POINTER(data->current_contact_id));
96
97                 return CONTACTS_ERROR_NONE;
98         } else {
99                 return CONTACTS_ERROR_NO_DATA;
100         }
101 }
102
103 /* remove data */
104 static int __ctsvc_server_bg_contact_delete_step2(__ctsvc_delete_data_s *data)
105 {
106         CTS_FN_CALL;
107         int ret;
108         char query[CTS_SQL_MIN_LEN] = {0};
109         GSList *list = NULL;
110         cts_stmt stmt = NULL;
111         int count = 0;
112         GSList *cursor;
113
114         /* get event_list */
115         snprintf(query, sizeof(query),
116                         "SELECT id FROM "CTS_TABLE_DATA" WHERE contact_id = %d AND is_my_profile = 0 LIMIT %d",
117                         data->current_contact_id, CTSVC_SERVER_BG_DELETE_COUNT);
118
119         ret = ctsvc_query_prepare(query, &stmt);
120         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
121
122         while (1 == (ret = ctsvc_stmt_step(stmt))) {
123                 int id = 0;
124                 id = ctsvc_stmt_get_int(stmt, 0);
125                 list = g_slist_append(list, GINT_TO_POINTER(id));
126         }
127         ctsvc_stmt_finalize(stmt);
128
129         count = g_slist_length(list);
130         if (count <= 0) {
131                 g_slist_free(list);
132                 return CONTACTS_ERROR_NO_DATA;
133         }
134
135         ret = ctsvc_begin_trans();
136         if (ret != CONTACTS_ERROR_NONE) {
137                 g_slist_free(list);
138                 ERR("DB Fail");
139                 return CONTACTS_ERROR_DB;
140         }
141
142         cursor = g_slist_nth(list, 0);
143         while (cursor) {
144                 int id = GPOINTER_TO_INT(cursor->data);
145                 snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_DATA" WHERE id = %d", id);
146
147                 ret = ctsvc_query_exec(query);
148                 if (ret != CONTACTS_ERROR_NONE) {
149                         /* LCOV_EXCL_START */
150                         ERR("DB Fail");
151                         ctsvc_end_trans(false);
152                         g_slist_free(list);
153                         return ret;
154                         /* LCOV_EXCL_STOP */
155                 }
156                 cursor = g_slist_next(cursor);
157         }
158         g_slist_free(list);
159         ret = ctsvc_end_trans(true);
160
161         return ret;
162 }
163
164 /* remove activities */
165 static int __ctsvc_server_bg_contact_delete_step3(__ctsvc_delete_data_s *data)
166 {
167         CTS_FN_CALL;
168
169         int ret;
170         char query[CTS_SQL_MIN_LEN] = {0};
171         GSList *list = NULL;
172         cts_stmt stmt = NULL;
173         int count = 0;
174         GSList *cursor;
175
176         /* get event_list */
177         snprintf(query, sizeof(query),
178                         "SELECT id FROM "CTS_TABLE_ACTIVITIES" WHERE contact_id = %d LIMIT %d",
179                         data->current_contact_id, CTSVC_SERVER_BG_DELETE_COUNT);
180
181         ret = ctsvc_query_prepare(query, &stmt);
182         RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
183
184         while (1 == (ret = ctsvc_stmt_step(stmt))) {
185                 int id = 0;
186                 id = ctsvc_stmt_get_int(stmt, 0);
187                 list = g_slist_append(list, GINT_TO_POINTER(id));
188         }
189         ctsvc_stmt_finalize(stmt);
190
191         count = g_slist_length(list);
192         if (count <= 0) {
193                 g_slist_free(list);
194                 return CONTACTS_ERROR_NO_DATA;
195         }
196
197         ret = ctsvc_begin_trans();
198         if (ret != CONTACTS_ERROR_NONE) {
199                 g_slist_free(list);
200                 ERR("DB Fail");
201                 return CONTACTS_ERROR_DB;
202         }
203
204         cursor = g_slist_nth(list, 0);
205         while (cursor) {
206                 int id = GPOINTER_TO_INT(cursor->data);
207                 snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_ACTIVITIES" WHERE id = %d", id);
208
209                 ret = ctsvc_query_exec(query);
210                 if (ret != CONTACTS_ERROR_NONE) {
211                         /* LCOV_EXCL_START */
212                         ERR("DB Fail");
213                         ctsvc_end_trans(false);
214                         g_slist_free(list);
215                         return ret;
216                         /* LCOV_EXCL_STOP */
217                 }
218                 cursor = g_slist_next(cursor);
219         }
220         g_slist_free(list);
221         ret = ctsvc_end_trans(true);
222
223         return ret;
224 }
225
226 static int __ctsvc_server_bg_contact_delete_step4(__ctsvc_delete_data_s *data)
227 {
228         int ret;
229         char query[CTS_SQL_MIN_LEN] = {0};
230
231         ret = ctsvc_begin_trans();
232         RETVM_IF(CONTACTS_ERROR_NONE != ret, CONTACTS_ERROR_DB, "DB Fail");
233
234         snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_SEARCH_INDEX" WHERE contact_id = %d",
235                         data->current_contact_id);
236         ret = ctsvc_query_exec(query);
237         if (CONTACTS_ERROR_NONE != ret) {
238                 /* LCOV_EXCL_START */
239                 ERR("DB Fail");
240                 ctsvc_end_trans(false);
241                 return ret;
242                 /* LCOV_EXCL_STOP */
243         }
244
245         snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_CONTACTS" WHERE contact_id = %d",
246                         data->current_contact_id);
247         ret = ctsvc_query_exec(query);
248         if (CONTACTS_ERROR_NONE != ret) {
249                 /* LCOV_EXCL_START */
250                 ERR("DB Fail");
251                 ctsvc_end_trans(false);
252                 return ret;
253                 /* LCOV_EXCL_STOP */
254         }
255
256         ret = ctsvc_end_trans(true);
257         return ret;
258 }
259
260 static bool __ctsvc_server_bg_contact_delete_step(int ret, __ctsvc_delete_data_s *data)
261 {
262         if (ret != CONTACTS_ERROR_NONE && ret != CONTACTS_ERROR_NO_DATA) {
263                 /* LCOV_EXCL_START */
264                 if (data->contact_ids)
265                         g_slist_free(data->contact_ids);
266                 ERR("Fail(%d)", ret);
267                 return false;
268                 /* LCOV_EXCL_STOP */
269         }
270
271         switch (data->step) {
272         case STEP_1:
273                 if (ret == CONTACTS_ERROR_NO_DATA) {
274                         /* LCOV_EXCL_START */
275                         if (data->contact_ids)
276                                 g_slist_free(data->contact_ids);
277                         ERR("step_1 no_data");
278                         return false;
279                         /* LCOV_EXCL_STOP */
280                 }
281                 data->step = STEP_2;
282                 break;
283         case STEP_2:
284                 if (ret == CONTACTS_ERROR_NO_DATA)
285                         data->step = STEP_3;
286                 break;
287         case STEP_3:
288                 if (ret == CONTACTS_ERROR_NO_DATA)
289                         data->step = STEP_4;
290                 break;
291         case STEP_4:
292                 data->step = STEP_1;
293                 break;
294         default:
295                 data->step = STEP_1;
296                 break;
297         }
298
299         return true;
300 }
301
302 static bool  __ctsvc_server_db_delete_run(__ctsvc_delete_data_s *data)
303 {
304         CTS_FN_CALL;
305         int ret = CONTACTS_ERROR_NONE;
306
307         RETV_IF(NULL == data, false);
308
309         switch (data->step) {
310         case STEP_1:
311                 /* get deleted contact id list */
312                 ret = __ctsvc_server_bg_contact_delete_step1(data);
313                 break;
314         case STEP_2:
315                 /* delete data of current contact id (MAX CTSVC_SERVER_BG_DELETE_COUNT) */
316                 ret = __ctsvc_server_bg_contact_delete_step2(data);
317                 break;
318         case STEP_3:
319                 /* delete activity of current contact id (MAX CTSVC_SERVER_BG_DELETE_COUNT each time) */
320                 ret = __ctsvc_server_bg_contact_delete_step3(data);
321                 break;
322         case STEP_4:
323                 /* delete search index of current contact id */
324                 ret = __ctsvc_server_bg_contact_delete_step4(data);
325                 break;
326         default:
327                 /* LCOV_EXCL_START */
328                 ERR("invalid step");
329                 if (data->contact_ids)
330                         g_slist_free(data->contact_ids);
331                 return false;
332                 /* LCOV_EXCL_STOP */
333         }
334
335         return __ctsvc_server_bg_contact_delete_step(ret, data);
336 }
337
338 typedef struct {
339         unsigned long int cpu_work_time;
340         unsigned long int cpu_total_time;
341 } process_stat;
342
343 static process_stat* __ctsvc_get_cpu_stat()
344 {
345         int i;
346         int ret;
347         long unsigned int cpu_time[10];
348         process_stat *result = NULL;
349
350         FILE *fstat = fopen("/proc/stat", "r");
351         if (fstat == NULL)
352                 return NULL;
353
354         memset(cpu_time, 0x0, sizeof(cpu_time));
355         ret = fscanf(fstat, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
356                         &cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3],
357                         &cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7],
358                         &cpu_time[8], &cpu_time[9]);
359         fclose(fstat);
360
361         if (ret < 0)
362                 return NULL;
363
364         result = calloc(1, sizeof(process_stat));
365         if (NULL == result) {
366                 /* LCOV_EXCL_START */
367                 ERR("calloc() Fail");
368                 return NULL;
369                 /* LCOV_EXCL_STOP */
370         }
371         for (i = 0; i < 10; i++) {
372                 if (i < 3)
373                         result->cpu_work_time += cpu_time[i];
374                 result->cpu_total_time += cpu_time[i];
375         }
376
377         return result;
378 }
379
380 static bool __ctsvc_cpu_is_busy()
381 {
382         unsigned long int total_time_diff;
383         unsigned long int work_time_diff;
384         process_stat *result1 = NULL;
385         process_stat *result2 = NULL;
386         double cpu_usage;
387
388         result1 = __ctsvc_get_cpu_stat();
389         sleep(1);
390         result2 = __ctsvc_get_cpu_stat();
391         if (result1 == NULL || result2 == NULL) {
392                 free(result1);
393                 free(result2);
394                 return false;
395         }
396
397         total_time_diff = result2->cpu_total_time - result1->cpu_total_time;
398         work_time_diff = result2->cpu_work_time - result1->cpu_work_time;
399
400         free(result1);
401         free(result2);
402
403         cpu_usage = ((double)work_time_diff/(double)total_time_diff) * 100;
404         INFO("cpu usage : %.2lf (%ld/%ld)", cpu_usage, work_time_diff, total_time_diff);
405         if (CTSVC_SERVER_BG_BASE_CPU_USAGE < cpu_usage)
406                 return true;
407         return false;
408 }
409
410 static gpointer __ctsvc_server_bg_delete(gpointer user_data)
411 {
412         CTS_FN_CALL;
413         int ret;
414         __ctsvc_delete_data_s *callback_data = NULL;
415
416         while (1) {
417                 callback_data = calloc(1, sizeof(__ctsvc_delete_data_s));
418                 if (callback_data == NULL) {
419                         /* LCOV_EXCL_START */
420                         ERR("calloc fail");
421                         continue;
422                         /* LCOV_EXCL_STOP */
423                 }
424                 callback_data->step = STEP_1;
425
426                 ret = ctsvc_connect();
427                 if (CONTACTS_ERROR_NONE != ret) {
428                         /* LCOV_EXCL_START */
429                         ERR("contacts_connect() fail(%d)", ret);
430                         free(callback_data);
431                         continue;
432                         /* LCOV_EXCL_STOP */
433                 }
434                 ctsvc_set_client_access_info(NULL, NULL);
435
436                 ctsvc_server_stop_timeout();
437                 while (1) {
438                         if (__ctsvc_cpu_is_busy()) { /* sleep 1 sec in function */
439                                 /* LCOV_EXCL_START */
440                                 ERR("Now CPU is busy.. waiting");
441                                 sleep(CTSVC_SERVER_BG_DELETE_STEP_TIME*59); /* sleep 60 sec(1 min) totally */
442                                 continue;
443                                 /* LCOV_EXCL_STOP */
444                         }
445                         if (__ctsvc_server_db_delete_run(callback_data) == false) {
446                                 DBG("end");
447                                 free(callback_data);
448                                 break;
449                         }
450                 }
451
452                 ctsvc_unset_client_access_info();
453
454                 ret = ctsvc_disconnect();
455
456                 if (CONTACTS_ERROR_NONE != ret)
457                         /* LCOV_EXCL_START */
458                         ERR("contacts_disconnect Fail(%d)", ret);
459                 /* LCOV_EXCL_STOP */
460                 ctsvc_server_start_timeout();
461
462                 g_mutex_lock(&__ctsvc_server_bg_delete_mutex);
463                 DBG("wait");
464                 g_cond_wait(&__ctsvc_server_bg_delete_cond, &__ctsvc_server_bg_delete_mutex);
465                 g_mutex_unlock(&__ctsvc_server_bg_delete_mutex);
466         }
467
468         ctsvc_server_start_timeout();
469         return NULL;
470 }
471
472 void ctsvc_server_bg_delete_start()
473 {
474         CTS_FN_CALL;
475
476         if (__ctsvc_server_bg_delete_thread == NULL) {
477                 g_mutex_init(&__ctsvc_server_bg_delete_mutex);
478                 g_cond_init(&__ctsvc_server_bg_delete_cond);
479                 __ctsvc_server_bg_delete_thread = g_thread_new(CTSVC_SERVER_BG_DELETE_THREAD,
480                                 __ctsvc_server_bg_delete, NULL);
481         }
482
483         /* don't use mutex. */
484         g_cond_signal(&__ctsvc_server_bg_delete_cond);
485 }
486
487 static void __ctsvc_server_addressbook_deleted_cb(const char *view_uri, void *data)
488 {
489         /* access control update */
490         ctsvc_reset_all_client_access_info();
491
492         ctsvc_server_bg_delete_start();
493 }
494
495 static void __ctsvc_server_contact_deleted_cb(const char *view_uri, void *data)
496 {
497         ctsvc_server_bg_delete_start();
498 }
499
500 static bool __ctsvc_server_account_delete_cb(const char *event_type, int account_id, void *user_data)
501 {
502         CTS_FN_CALL;
503         INFO("event_type : %s, account_id : %d", event_type, account_id);
504
505         if (STRING_EQUAL == strcmp(event_type, ACCOUNT_NOTI_NAME_DELETE)) {
506                 ctsvc_server_stop_timeout();
507                 ctsvc_addressbook_delete(account_id);
508         }
509         ctsvc_server_start_timeout();
510         return true;
511 }
512
513 void ctsvc_server_bg_add_cb()
514 {
515         int ret;
516
517         ret = ctsvc_inotify_subscribe(_contacts_address_book._uri, __ctsvc_server_addressbook_deleted_cb, NULL);
518         DBG("call ctsvc_inotify_subscribe (_contacts_address_book)  : return (%d)", ret);
519
520         ret = ctsvc_inotify_subscribe(_contacts_contact._uri, __ctsvc_server_contact_deleted_cb, NULL);
521         DBG("call ctsvc_inotify_subscribe (_contacts_contact): return (%d)", ret);
522
523         ret = account_subscribe_create(&account);
524         if (ACCOUNT_ERROR_NONE == ret) {
525                 ret = account_subscribe_notification(account, __ctsvc_server_account_delete_cb, NULL);
526                 if (ACCOUNT_ERROR_NONE != ret)
527                         /* LCOV_EXCL_START */
528                         ERR("account_subscribe_notification() Fail(%d)", ret);
529                 /* LCOV_EXCL_STOP */
530         } else {
531                 /* LCOV_EXCL_START */
532                 ERR("account_subscribe_create() Fail(%d)", ret);
533                 /* LCOV_EXCL_STOP */
534         }
535 }
536
537 void ctsvc_server_bg_remove_cb()
538 {
539         int ret;
540
541         ret = ctsvc_inotify_unsubscribe(_contacts_address_book._uri, __ctsvc_server_addressbook_deleted_cb, NULL);
542         ERR("call ctsvc_inotify_unsubscribe (_contacts_address_book): return (%d)", ret);
543         ret = ctsvc_inotify_unsubscribe(_contacts_contact._uri, __ctsvc_server_contact_deleted_cb, NULL);
544         ERR("call ctsvc_inotify_unsubscribe (_contacts_contact) : return (%d)", ret);
545
546         if (account) {
547                 account_unsubscribe_notification(account);  /* unsubscirbe & destroy */
548                 account = NULL;
549         }
550 }
551