/soc/2015/igor.gajowiak/chatlog: b77bc1210637: SQLite log optimi...
Igor Gajowiak <[email protected]>
| Newsgroups | gmane.comp.gnome.gaim.cvs |
|---|---|
| Message-ID | <[email protected]> |
Changeset: b77bc1210637be15a44a034d4f4db7afc4e16bf7 Author: Igor Gajowiak <[email protected]> Date: 2015-07-19 14:06 +0200 Branch: default URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/b77bc1210637 Description: SQLite log optimization: reusing prepared queries diffstat: libpurple/accounts.c | 7 +- libpurple/conversation.c | 9 +- libpurple/genericlog.h | 3 + libpurple/message.c | 15 + libpurple/message.h | 22 + libpurple/plugins/log/logsqlite.c | 454 ++++++++++++++++++++++++++++++------- 6 files changed, 411 insertions(+), 99 deletions(-) diffs (truncated from 702 to 300 lines): diff --git a/libpurple/accounts.c b/libpurple/accounts.c --- a/libpurple/accounts.c +++ b/libpurple/accounts.c @@ -924,7 +924,7 @@ password_migration_cb(PurpleAccount *acc } static void -show_unread_im_msgs(PurpleConnection *gc) +show_unseen_im_msgs(PurpleConnection *gc) { PurpleAccount *account = purple_connection_get_account(gc); @@ -937,6 +937,9 @@ show_unread_im_msgs(PurpleConnection *gc for(GList *it = unseen_msgs; it != NULL; it = it->next) { PurpleMessage *msg = it->data; + purple_message_set_flags(msg, purple_message_get_flags(msg) | + PURPLE_MESSAGE_NO_LOG); + // Create or get a conversation PurpleIMConversation *conv = purple_im_conversation_new( account, purple_message_get_author(msg)); @@ -1036,7 +1039,7 @@ purple_accounts_init(void) purple_signal_connect(conn_handle, "signed-on", handle, PURPLE_CALLBACK(signed_on_cb), NULL); purple_signal_connect(conn_handle, "signed-on", handle, - PURPLE_CALLBACK(show_unread_im_msgs), NULL); + PURPLE_CALLBACK(show_unseen_im_msgs), NULL); purple_signal_connect(conn_handle, "signed-off", handle, PURPLE_CALLBACK(signed_off_cb), NULL); purple_signal_connect(conn_handle, "connection-error", handle, diff --git a/libpurple/conversation.c b/libpurple/conversation.c --- a/libpurple/conversation.c +++ b/libpurple/conversation.c @@ -622,6 +622,13 @@ void purple_message_get_contents(pmsg)); log = log->next; } + + GError *error; + if (!purple_genericlog_logim(account, pmsg, &error)) { + purple_debug_error("conversation", "Logging failed: %s (code=%d)", + error->message, error->code); + g_error_free(error); + } } if (ops) { @@ -633,8 +640,6 @@ void ops->write_conv(conv, pmsg); } - // TODO: add error handling? - purple_genericlog_logim(account, pmsg, NULL); add_message_to_history(conv, pmsg); purple_signal_emit(purple_conversations_get_handle(), diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h --- a/libpurple/genericlog.h +++ b/libpurple/genericlog.h @@ -89,6 +89,9 @@ struct _PurpleGenericLogClass #define PURPLE_GENERICLOG_DEFAULT "genericlog-sqlitelog" +#define PURPLE_GENERICLOG_PROPERTY_ID "id" +#define PURPLE_GENERICLOG_PROPERTY_NAME "name" + /**************************************************************************/ /* PurpleGenericLog intance methods */ /**************************************************************************/ diff --git a/libpurple/message.c b/libpurple/message.c --- a/libpurple/message.c +++ b/libpurple/message.c @@ -63,6 +63,21 @@ static GHashTable *messages = NULL; ******************************************************************************/ PurpleMessage * +purple_message_new(const gchar *author, const gchar *author_alias, + const gchar *recipient, const gchar *contents, guint64 timestamp, + PurpleMessageFlags flags) +{ + return g_object_new(PURPLE_TYPE_MESSAGE, + "author", author, + "author-alias", author_alias, + "recipient", recipient, + "contents", contents, + "time", timestamp, + "flags", flags, + NULL); +} + +PurpleMessage * purple_message_new_outgoing(const gchar *who, const gchar *contents, PurpleMessageFlags flags) { diff --git a/libpurple/message.h b/libpurple/message.h --- a/libpurple/message.h +++ b/libpurple/message.h @@ -84,6 +84,28 @@ GType purple_message_get_type(void); /** + * purple_message_new: + * @author: Message's author. + * @author_alias: Author's alias. + * @recipient: Message's recipient. + * @contents: The contents of a message. + * @timestamp: The time of transmitting a message. + * @flags: The message flags. + * + * Deserializes a message. + * + * This function should be used when a complete + * message deserialization is needed. For sending or receiving a message + * see purple_message_new_outgoing, purple_message_new_incoming. + * + * Returns: the new #PurpleMessage. + */ +PurpleMessage * +purple_message_new(const gchar *author, const gchar *author_alias, + const gchar *recipient, const gchar *contents, guint64 timestamp, + PurpleMessageFlags flags); + +/** * purple_message_new_outgoing: * @who: Message's recipient. * @contents: The contents of a message. diff --git a/libpurple/plugins/log/logsqlite.c b/libpurple/plugins/log/logsqlite.c --- a/libpurple/plugins/log/logsqlite.c +++ b/libpurple/plugins/log/logsqlite.c @@ -39,8 +39,160 @@ #define SQLITELOG_MESSAGE_ID_ATTR "sqlitelog-msg-id" +#define SQLITELOG_DEBUG_CATEGORY "sqlite-log" + static sqlite3 *sqlitelog_db_handle = NULL; +/**************************************************************************/ +/* Prepared queries */ +/**************************************************************************/ + +static sqlite3_stmt *get_accunt_id_q = NULL; + +static const char *get_accunt_id_q_str = + "SELECT Id FROM Accounts " + "WHERE Username = ?1 AND ProtocolId = ?2;"; + +typedef enum +{ + GET_ACCOUNT_ID_QUERY_PARAM_USERNAME = 1, + GET_ACCOUNT_ID_QUERY_PARAM_PROTOCOLID = 2, +} GetAccountIdQueryParam; + +typedef enum +{ + GET_ACCOUNT_ID_QUERY_COL_ID = 0 +} GetAccountIdQueryCol; + +static sqlite3_stmt *insert_account_q = NULL; + +static const char *insert_account_q_str = + "INSERT INTO Accounts " + "(Username, ProtocolId) VALUES(?1, ?2);"; + +typedef enum +{ + INSERT_ACCOUNT_QUERY_PARAM_USERNAME = 1, + INSERT_ACCOUNT_QUERY_PARAM_PROTOCOLID = 2, +} InsertAccountQueryParam; + +static sqlite3_stmt *insert_message_q = NULL; + +static const char *insert_message_q_str = + "INSERT INTO Messages (Author, AuthorAlias, Recipient, " + "Contents, MsgTime, Flags, Seen, AccountId) " + "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);"; + +typedef enum +{ + INSERT_MESSAGE_QUERY_PARAM_AUTHOR = 1, + INSERT_MESSAGE_QUERY_PARAM_AUTHORALIAS = 2, + INSERT_MESSAGE_QUERY_PARAM_RECIPIENT = 3, + INSERT_MESSAGE_QUERY_PARAM_CONTENTS = 4, + INSERT_MESSAGE_QUERY_PARAM_MSGTIME = 5, + INSERT_MESSAGE_QUERY_PARAM_FLAGS = 6, + INSERT_MESSAGE_QUERY_PARAM_SEEN = 7, + INSERT_MESSAGE_QUERY_PARAM_ACCOUNTID = 8, +} InsertMessageQueryParam; + +static sqlite3_stmt *get_unseen_msgs_q = NULL; + +static const char *get_unseen_msgs_q_str = + "SELECT Messages.Id, Author, AuthorAlias, Recipient, Contents, " + "MsgTime, Flags, Seen " + "FROM Messages JOIN Accounts ON Accounts.Id = AccountId " + "WHERE Username = ?1 AND ProtocolId = ?2 AND Seen = 0 " + "ORDER BY Messages.Id DESC;"; + +typedef enum +{ + GET_UNSEEN_MSGS_QUERY_PARAM_USERNAME = 1, + GET_UNSEEN_MSGS_QUERY_PARAM_PROTOCOLID = 2, +} GetUnseenMsgsQueryParam; + +typedef enum +{ + GET_UNSEEN_MSGS_QUERY_COL_ID = 0, + GET_UNSEEN_MSGS_QUERY_COL_AUTHOR = 1, + GET_UNSEEN_MSGS_QUERY_COL_AUTHORALIAS = 2, + GET_UNSEEN_MSGS_QUERY_COL_RECIPIENT = 3, + GET_UNSEEN_MSGS_QUERY_COL_CONTENTS = 4, + GET_UNSEEN_MSGS_QUERY_COL_MSGTIME = 5, + GET_UNSEEN_MSGS_QUERY_COL_FLAGS = 6, + GET_UNSEEN_MSGS_QUERY_COL_SEEN = 7, +} GetUnseenMsgsQueryCol; + +static sqlite3_stmt *mark_as_seen_q = NULL; + +static const char *mark_as_seen_q_str = + "UPDATE Messages SET Seen = 1 WHERE Id = ?1;"; + +typedef enum +{ + MARK_AS_SEEN_QUERY_PARAM_ID = 1 +} MarkAsSeenQueryParam; + +static void +sqlitelog_finalize_query(sqlite3_stmt **query) +{ + g_assert(query); + + if (sqlite3_finalize(*query) != SQLITE_OK) { + purple_debug_error(SQLITELOG_DEBUG_CATEGORY, + "Failed to finalize query %p", *query); + } + + *query = NULL; +} + +static void +sqlitelog_finalize_queries() +{ + sqlitelog_finalize_query(&get_accunt_id_q); + sqlitelog_finalize_query(&insert_account_q); + sqlitelog_finalize_query(&insert_message_q); + sqlitelog_finalize_query(&get_unseen_msgs_q); + sqlitelog_finalize_query(&mark_as_seen_q); +} + +static gboolean +sqlitelog_prepare_query(const char *query_str, sqlite3_stmt **query) +{ + g_assert(query_str); + g_assert(query); + + sqlite3_stmt *handle; + + int rc = sqlite3_prepare_v2(sqlitelog_db_handle, + query_str, -1, &handle, NULL); + if (rc != SQLITE_OK) { + purple_debug_error(SQLITELOG_DEBUG_CATEGORY, + "Failed to prepare query '%s', details: %s", query_str, + sqlite3_errmsg(sqlitelog_db_handle)); + + return FALSE; + } + + *query = handle; + return TRUE; +} + +static gboolean +sqlitelog_prepare_queries() +{ + if (!sqlitelog_prepare_query(get_accunt_id_q_str, &get_accunt_id_q) || + !sqlitelog_prepare_query(insert_account_q_str, &insert_account_q) || + !sqlitelog_prepare_query(insert_message_q_str, &insert_message_q) || + !sqlitelog_prepare_query(get_unseen_msgs_q_str, &get_unseen_msgs_q) || + !sqlitelog_prepare_query(mark_as_seen_q_str, &mark_as_seen_q)) { + + sqlitelog_finalize_queries(); + return FALSE; + } + + return TRUE; +} + static gboolean sqlitelog_db_file_exists(const gchar *db_path) { @@ -62,7 +214,7 @@ sqlitelog_create_tables(sqlite3 *db_hand "Id INTEGER PRIMARY KEY AUTOINCREMENT," "Author TEXT," "AuthorAlias TEXT," - "Recipient TEXT NOT NULL," + "Recipient TEXT," "Contents TEXT NOT NULL," "MsgTime INTEGER NOT NULL," "Flags INTEGER NOT NULL," _______________________________________________ Commits mailing list [email protected] https://pidgin.im/cgi-bin/mailman/listinfo/commits