From 85180440e39e3374338cf3598bd479dec3f27754 Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Thu, 3 Dec 2020 14:57:22 -0500 Subject: [PATCH 1/2] app_voicemail: Attempt to optimize mailbox resequencing Change-Id: Iea3d4ee5f0794e2b22af74a8ff986b296ca78307 --- apps/app_voicemail.c | 122 ++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 37 deletions(-) diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 2929cf2cda..cfe374efac 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -4052,7 +4052,7 @@ bail: * * \return greater than zero if the message exists, zero when the message does not exist or on error. */ -static int message_exists(char *dir, int msgnum) +static int message_exists_with_connection(struct odbc_obj *conn, char *dir, int msgnum) { int x = 0; int res; @@ -4062,17 +4062,10 @@ static int message_exists(char *dir, int msgnum) char msgnums[20]; char *argv[] = { dir, msgnums }; struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; - struct odbc_obj *obj; - - obj = ast_odbc_request_obj(odbc_database, 0); - if (!obj) { - ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return 0; - } snprintf(msgnums, sizeof(msgnums), "%d", msgnum); snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + stmt = ast_odbc_prepare_and_execute(conn, generic_prepare, &gps); if (!stmt) { ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); goto bail; @@ -4098,10 +4091,26 @@ bail_with_handle: SQLFreeHandle(SQL_HANDLE_STMT, stmt); bail: - ast_odbc_release_obj(obj); return x; } +static int message_exists(char *dir, int msgnum) +{ + int res; + struct odbc_obj *conn; + + conn = ast_odbc_request_obj(odbc_database, 0); + if (!conn) { + ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return 0; + } + + res = message_exists_with_connection(conn, dir, msgnum); + + ast_odbc_release_obj(conn); + return res; +} + /*! * \brief returns the number of messages found. * \param vmu @@ -4169,36 +4178,43 @@ bail: * * \return the value greater than zero on success to indicate the number of messages, less than zero on error. */ -static void delete_file(const char *sdir, int smsg) +static void delete_file_with_connection(struct odbc_obj *conn, const char *sdir, int smsg) { SQLHSTMT stmt; char sql[PATH_MAX]; char msgnums[20]; char *argv[] = { NULL, msgnums }; struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; - struct odbc_obj *obj; - - obj = ast_odbc_request_obj(odbc_database, 0); - if (!obj) { - ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; - } argv[0] = ast_strdupa(sdir); snprintf(msgnums, sizeof(msgnums), "%d", smsg); snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + stmt = ast_odbc_prepare_and_execute(conn, generic_prepare, &gps); if (!stmt) { ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); } else { SQLFreeHandle(SQL_HANDLE_STMT, stmt); } - ast_odbc_release_obj(obj); return; } +static void delete_file(const char *sdir, int smsg) +{ + struct odbc_obj *conn; + + conn = ast_odbc_request_obj(odbc_database, 0); + if (!conn) { + ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return; + } + + delete_file_with_connection(conn, sdir, smsg); + + ast_odbc_release_obj(conn); +} + /*! * \brief Copies a voicemail from one mailbox to another. * \param sdir the folder for which to look for the message to be copied. @@ -4445,23 +4461,16 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail * The is usually used to resequence the messages in the mailbox, such as to delete messag index 0, it would be called successively to slide all the other messages down one index. * But in theory, because the SQL query performs an update on (dir, msgnum, mailboxuser, mailboxcontext) in the database, it should be possible to have the message relocated to another mailbox or context as well. */ -static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg) +static void rename_file_with_connection(struct odbc_obj *obj, char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg) { SQLHSTMT stmt; char sql[PATH_MAX]; char msgnums[20]; char msgnumd[20]; - struct odbc_obj *obj; char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums }; struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; - delete_file(ddir, dmsg); - - obj = ast_odbc_request_obj(odbc_database, 0); - if (!obj) { - ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; - } + delete_file_with_connection(obj, ddir, dmsg); snprintf(msgnums, sizeof(msgnums), "%d", smsg); snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); @@ -4471,6 +4480,22 @@ static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxco ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); else SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + return; +} + +static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg) +{ + struct odbc_obj *obj; + + obj = ast_odbc_request_obj(odbc_database, 0); + if (!obj) { + ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return; + } + + rename_file_with_connection(obj, sdir, smsg, mailboxuser, mailboxcontext, ddir, dmsg); + ast_odbc_release_obj(obj); return; } @@ -7161,7 +7186,30 @@ leave_vm_out: return res; } -#if !defined(IMAP_STORAGE) +#if defined(ODBC_STORAGE) +static void resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount) +{ + int x, dest; + struct odbc_obj *conn; + + conn = ast_odbc_request_obj(odbc_database, 0); + if (!conn) { + ast_log(LOG_WARNING, "Unable to resequence mailbox %s@%s\n", vmu->mailbox, vmu->context); + return; + } + + for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) { + if (message_exists_with_connection(conn, dir, x)) { + if (x != dest) { + rename_file_with_connection(conn, dir, x, vmu->mailbox, vmu->context, dir, dest); + } + dest++; + } + } + + ast_odbc_release_obj(conn); +} +#elif !defined(IMAP_STORAGE) static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount) { /* we know the actual number of messages, so stop process when number is hit */ @@ -7170,10 +7218,6 @@ static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount) char sfn[PATH_MAX]; char dfn[PATH_MAX]; - if (vm_lock_path(dir)) { - return ERROR_LOCK_PATH; - } - for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) { make_file(sfn, sizeof(sfn), dir, x); if (EXISTS(dir, x, sfn, NULL)) { @@ -7186,7 +7230,6 @@ static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount) dest++; } } - ast_unlock_path(dir); return dest; } @@ -9123,15 +9166,20 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box) /* for local storage, checks directory for messages up to maxmsg limit */ last_msg = last_message_index(vmu, vms->curdir); - ast_unlock_path(vms->curdir); if (last_msg < -1) { + ast_unlock_path(vms->curdir); return last_msg; - } else if (vms->lastmsg != last_msg) { + } + + if (vms->lastmsg != last_msg) { ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg); + /* Must be called with the VM directory locked */ resequence_mailbox(vmu, vms->curdir, count_msg); } + ast_unlock_path(vms->curdir); + return 0; } #endif -- 2.25.1