// Author: Ricardas Stoma // Company: Kolmisoft // Year: 2018 // About: Script deletes old calls from 'calls' table #define SCRIPT_VERSION "1.3" #define SCRIPT_NAME "m2_delete_old_calls" #define SQL_LIMIT 1000 #define BATCH_SIZE 250 #define IDS_BUFFER_SIZE BATCH_SIZE * 20 + 256 #include "m2_functions.c" // VARIABLES // SQL variables char sql_delete_statement[64] = "DELETE FROM calls WHERE id IN ("; char sql_count_statement[64] = "SELECT COUNT(id) FROM calls WHERE id IN ("; char buffer[4096] = ""; long long int total_calls = 0; // call ids stored in array for future deletion char ids_buffer[IDS_BUFFER_SIZE] = ""; char check_ids_buffer[IDS_BUFFER_SIZE] = ""; long long int ids[SQL_LIMIT]; int older_than = 0; char min_calldate[20] = ""; char max_calldate[20] = ""; // FUNCTION DECLARATIONS int delete_calls_from_database(int calls); int delete_not_answered_calls(); void get_settings_from_conflines(); void get_calls_count(); // MAIN FUNCTION int main(int argc, char *argv[]) { // starting the script m2_init("Starting M2 Delete Old Calls script\n"); get_elasticsearch_host(); // get various settings get_settings_from_conflines(); // delete not answered calls if (older_than > 0) { m2_log("Deleting not answered calls older than %d days\n", older_than) get_calls_count(); if (total_calls > 0) { m2_log("%lld calls will be deleted\n", total_calls); delete_not_answered_calls(); m2_log("Oldest calldate: %s\n", min_calldate); m2_log("Latest calldate: %s\n", max_calldate); if (strlen(min_calldate) && strlen(max_calldate)) { char system_cmd[256] = ""; m2_system_cmd_response_t response; m2_log("Resyncing elasticsearch for period %s - %s\n", min_calldate, max_calldate); sprintf(system_cmd, "/usr/bin/elasticsearch resync interval '%s' '%s'", min_calldate, max_calldate); m2_execute_system_command(system_cmd, &response); m2_log("Status: [%d], response: [%s], error: [%s]\n", response.return_code, response.data, response.error); } } else { m2_log("Nothing to delete\n"); } } else { m2_log("Calls should not be deleted from database (setting value is 0)\n") } m2_log("Script finished\n"); return 0; } int delete_calls_from_database(int calls) { MYSQL_RES *result; MYSQL_ROW row; int i = 0; int batch_counter = 0; // initialize ids_buffer strcpy(ids_buffer, sql_delete_statement); strcpy(check_ids_buffer, sql_count_statement); long long int check_calls = 0; int last_iteration_done = 0; // delete from calls table for (i = 0; i < calls; i++) { sprintf(buffer, "%lld,", ids[i]); strcat(ids_buffer, buffer); strcat(check_ids_buffer, buffer); batch_counter++; // batch is full, send query if (batch_counter == BATCH_SIZE) { last_iteration: ids_buffer[strlen(ids_buffer) - 1] = 0; check_ids_buffer[strlen(check_ids_buffer) - 1] = 0; strcat(ids_buffer, ");"); strcat(check_ids_buffer, ");"); // delete from MySQL if (m2_mysql_query(ids_buffer)) { return 1; } // check if calls with those ids are delete if (m2_mysql_query(check_ids_buffer)) { return 1; } check_calls = -1; result = mysql_store_result(&mysql); if (result) { if (mysql_num_rows(result)) { row = mysql_fetch_row(result); if (row[0]) check_calls = atoll(row[0]); } } mysql_free_result(result); if (check_calls == -1) { m2_log("Can't determine if calls where deleted correctly\n"); m2_log("%s\n", check_ids_buffer); return 1; } else if (check_calls) { m2_log("Tried to delete %d calls, but there are still %lld calls left. Check why some calls where not deleted!\n", BATCH_SIZE, check_calls); m2_log("%s\n", check_ids_buffer); return 1; } *ids_buffer = 0; *check_ids_buffer = 0; strcpy(ids_buffer, sql_delete_statement); strcpy(check_ids_buffer, sql_count_statement); batch_counter = 0; if (last_iteration_done) break; } } // if batch is not full, send query anyway if (strlen(ids_buffer) > strlen(sql_delete_statement) && last_iteration_done == 0) { last_iteration_done = 1; goto last_iteration; } return 0; } /* Delete not answered calls from calls table (older than x days) */ int delete_not_answered_calls() { MYSQL_RES *result; MYSQL_ROW row; char query[2048] = ""; int done = 0; int counter = 0; strcpy(sql_delete_statement, "DELETE FROM calls WHERE id IN ("); sprintf(sql_count_statement, "SELECT COUNT(id) FROM calls WHERE id IN ("); sprintf(query, "SELECT id, calldate FROM calls WHERE disposition != 'ANSWERED' AND calldate < DATE_SUB(DATE_FORMAT(NOW(), '%%Y-%%m-%%d %%H:30:00'), INTERVAL %d DAY) ORDER BY calldate LIMIT %d", older_than, SQL_LIMIT); while (done == 0) { int records = 0; done = 1; memset(ids_buffer, 0, sizeof(ids_buffer)); memset(check_ids_buffer, 0, sizeof(check_ids_buffer)); // get calls count if (m2_mysql_query(query)) { exit(1); } result = mysql_store_result(&mysql); // fetch data while ((row = mysql_fetch_row(result)) != NULL) { if (row[0]) { ids[records] = atoll(row[0]); records++; done = 0; // get oldest calldate and latest calldates if (row[1]) { if (!strlen(min_calldate)) strcpy(min_calldate, row[1]); strcpy(max_calldate, row[1]); } } } mysql_free_result(result); if (delete_calls_from_database(records)) return 1; counter++; if (counter >= 10000) { m2_log("Possible loop detected. Breaking out of it!\n"); return 0; } } return 0; } /* Get various settings from conflines */ void get_settings_from_conflines() { MYSQL_RES *result; MYSQL_ROW row; m2_log("Reading conflines\n"); // get Delete_not_Archived_not_Answered_Calls_older_than value if (m2_mysql_query("SELECT value FROM conflines WHERE name = 'Delete_not_Archived_not_Answered_Calls_older_than'")) { exit(1); } result = mysql_store_result(&mysql); if (result) { if (mysql_num_rows(result)) { row = mysql_fetch_row(result); // check if we get result if (row[0]) { older_than = atoi(row[0]); } } } mysql_free_result(result); } /* Check how many calls need to be deleted */ void get_calls_count() { MYSQL_RES *result; MYSQL_ROW row; char query[1024] = ""; sprintf(query, "SELECT COUNT(*) FROM calls WHERE disposition != 'ANSWERED' AND calldate < DATE_SUB(DATE_FORMAT(NOW(), '%%Y-%%m-%%d %%H:30:00'), INTERVAL %d DAY)", older_than); if (m2_mysql_query(query)) { exit(1); } result = mysql_store_result(&mysql); while ((row = mysql_fetch_row(result)) != NULL) { if (row[0]) { total_calls = atoi(row[0]); } } mysql_free_result(result); }