summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-03-14 16:43:38 -0400
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-03-14 16:43:38 -0400
commit1522b7c475399d0095d09da1d5c9ae2d462eb8e6 (patch)
tree19ceeeb0e3dcc4c38369c162617a901faae9c208
parent0e15f37026aab2dfc6a537f4682f2ebe3aa93079 (diff)
Useless message cache
-rw-r--r--telepathy-logger/log-store-sqlite-internal.h18
-rw-r--r--telepathy-logger/log-store-sqlite.c749
2 files changed, 242 insertions, 525 deletions
diff --git a/telepathy-logger/log-store-sqlite-internal.h b/telepathy-logger/log-store-sqlite-internal.h
index aa978fa2c..4181c419e 100644
--- a/telepathy-logger/log-store-sqlite-internal.h
+++ b/telepathy-logger/log-store-sqlite-internal.h
@@ -56,7 +56,9 @@ typedef enum
TPL_LOG_STORE_SQLITE_ERROR_FAILED = TPL_LOG_STORE_ERROR_LAST,
/* generic _tpl_log_store_sqlite_get_pending_messages() error, to be used when
* any other code cannot be use, including TPL_LOG_STORE_ERROR ones */
- TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES
+ TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES,
+ TPL_LOG_STORE_SQLITE_ERROR_REMOVE_PENDING_MESSAGES,
+ TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE
} TplLogStoreSqliteError;
@@ -76,17 +78,13 @@ struct _TplLogStoreSqliteClass
GType _tpl_log_store_sqlite_get_type (void);
TplLogStore * _tpl_log_store_sqlite_dup (void);
+
GList * _tpl_log_store_sqlite_get_pending_messages (TplLogStore *self,
TpChannel *channel, GError **error);
-GList * _tpl_log_store_sqlite_get_log_ids (TplLogStore *self,
- TpChannel *channel, gint64 timestamp, GError **error);
-gboolean _tpl_log_store_sqlite_log_id_is_present (TplLogStore *self,
- const gchar* log_id);
-
-void _tpl_log_store_sqlite_set_acknowledgment (TplLogStore *self,
- const gchar* log_id, GError **error);
-void _tpl_log_store_sqlite_set_acknowledgment_by_msg_id (TplLogStore *self,
- TpChannel *channel, guint msg_id, GError **error);
+gboolean _tpl_log_store_sqlite_remove_pending_messages (TplLogStore *self,
+ GList *log_ids, GError **error);
+gboolean _tpl_log_store_sqlite_add_pending_message (TplLogStore *self,
+ TpChannel *channel, const gchar *log_id, gint64 timestamp, GError **error);
gint64 _tpl_log_store_sqlite_get_most_recent (TplLogStoreSqlite *self,
TpAccount *account, const char *identifier);
diff --git a/telepathy-logger/log-store-sqlite.c b/telepathy-logger/log-store-sqlite.c
index 7c17effcc..0f89a12e8 100644
--- a/telepathy-logger/log-store-sqlite.c
+++ b/telepathy-logger/log-store-sqlite.c
@@ -17,6 +17,7 @@
*
* Authors: Danielle Madeley <danielle.madeley@collabora.co.uk>
* Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
*/
#include <config.h>
@@ -44,13 +45,8 @@
static void log_store_iface_init (TplLogStoreInterface *iface);
-static gboolean _insert_to_cache_table (TplLogStore *self,
- TplEvent *message, GError **error);
-static void tpl_log_store_sqlite_purge (TplLogStoreSqlite *self, GTimeSpan delta,
- GError **error);
static gboolean purge_event_timeout (gpointer logstore);
-
G_DEFINE_TYPE_WITH_CODE (TplLogStoreSqlite, _tpl_log_store_sqlite,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (TPL_TYPE_LOG_STORE, log_store_iface_init));
@@ -73,6 +69,7 @@ struct _TplLogStoreSqlitePrivate
static GObject *singleton = NULL;
+
static GObject *
tpl_log_store_sqlite_constructor (GType type,
guint n_props,
@@ -95,6 +92,7 @@ tpl_log_store_sqlite_constructor (GType type,
return singleton;
}
+
static char *
get_db_filename (void)
{
@@ -105,6 +103,7 @@ get_db_filename (void)
NULL);
}
+
static void
tpl_log_store_sqlite_get_property (GObject *self,
guint id,
@@ -132,6 +131,7 @@ tpl_log_store_sqlite_get_property (GObject *self,
}
}
+
static void
tpl_log_store_sqlite_set_property (GObject *self,
guint id,
@@ -151,6 +151,7 @@ tpl_log_store_sqlite_set_property (GObject *self,
}
}
+
static void
tpl_log_store_sqlite_dispose (GObject *self)
{
@@ -171,6 +172,7 @@ tpl_log_store_sqlite_dispose (GObject *self)
G_OBJECT_CLASS (_tpl_log_store_sqlite_parent_class)->dispose (self);
}
+
static void
_tpl_log_store_sqlite_class_init (TplLogStoreSqliteClass *klass)
{
@@ -188,6 +190,7 @@ _tpl_log_store_sqlite_class_init (TplLogStoreSqliteClass *klass)
g_type_class_add_private (gobject_class, sizeof (TplLogStoreSqlitePrivate));
}
+
static void
_tpl_log_store_sqlite_init (TplLogStoreSqlite *self)
{
@@ -222,18 +225,25 @@ _tpl_log_store_sqlite_init (TplLogStoreSqlite *self)
/* end of common part */
/* start of cache table init */
- sqlite3_exec (priv->db, "CREATE TABLE IF NOT EXISTS message_cache ( "
+
+ /* drop deprecated table (since 0.2.6) */
+ sqlite3_exec (priv->db, "DROP TABLE IF EXISTS message_cache",
+ NULL, NULL, &errmsg);
+ if (errmsg != NULL)
+ {
+ CRITICAL ("Failed to drop deprecated message_cache table: %s\n", errmsg);
+ sqlite3_free (errmsg);
+ goto out;
+ }
+
+ sqlite3_exec (priv->db, "CREATE TABLE IF NOT EXISTS pending_messages ( "
"channel TEXT NOT NULL, "
- "account TEXT NOT NULL, "
- "pending_msg_id INTEGER DEFAULT NULL, "
- "log_identifier TEXT PRIMARY KEY, "
- "chat_identifier TEXT NOT NULL, "
- "chatroom BOOLEAN NOT NULL, "
+ "log_id TEXT PRIMARY KEY, "
"date DATETIME NOT NULL)",
NULL, NULL, &errmsg);
if (errmsg != NULL)
{
- CRITICAL ("Failed to create table message_cache: %s\n", errmsg);
+ CRITICAL ("Failed to create table pending_messages: %s\n", errmsg);
sqlite3_free (errmsg);
goto out;
}
@@ -266,6 +276,7 @@ out:
g_free (filename);
}
+
static const char *
get_account_name (TpAccount *account)
{
@@ -273,6 +284,7 @@ get_account_name (TpAccount *account)
strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
}
+
static const char *
get_account_name_from_event (TplEvent *event)
{
@@ -280,6 +292,7 @@ get_account_name_from_event (TplEvent *event)
strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
}
+
static const char *
get_channel_name (TpChannel *chan)
{
@@ -287,12 +300,6 @@ get_channel_name (TpChannel *chan)
strlen (TP_CONN_OBJECT_PATH_BASE);
}
-static const char *
-get_channel_name_from_event (TplEvent *event)
-{
- return _tpl_event_get_channel_path (event) +
- strlen (TP_CONN_OBJECT_PATH_BASE);
-}
static char *
get_date (TplEvent *event)
@@ -305,17 +312,17 @@ get_date (TplEvent *event)
g_date_time_unref (ts);
-
return date;
}
+
static char *
-get_datetime (TplEvent *event)
+get_datetime (gint64 timestamp)
{
GDateTime *ts;
gchar *date;
- ts = g_date_time_new_from_unix_utc (tpl_event_get_timestamp (event));
+ ts = g_date_time_new_from_unix_utc (timestamp);
date = g_date_time_format (ts, TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT);
g_date_time_unref (ts);
@@ -323,119 +330,13 @@ get_datetime (TplEvent *event)
return date;
}
+
static const char *
tpl_log_store_sqlite_get_name (TplLogStore *self)
{
return TPL_LOG_STORE_SQLITE_NAME;
}
-/* returns log-id if present, NULL if not present */
-static gchar *
-_cache_msg_id_is_present (TplLogStore *self,
- TpChannel *channel,
- guint msg_id)
-{
- TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
- sqlite3_stmt *sql = NULL;
- gchar *retval = NULL;
- int e;
-
- g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), NULL);
- g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
-
- /* get all the (chan,msg_id) couples, the most recent first */
- e = sqlite3_prepare_v2 (priv->db,
- "SELECT log_identifier "
- "FROM message_cache "
- "WHERE channel=? AND pending_msg_id=? "
- "GROUP BY date",
- -1, &sql, NULL);
-
- if (e != SQLITE_OK)
- {
- CRITICAL ("Error preparing SQL to check msg_id %d for channel %s"
- " presence: %s", msg_id, get_channel_name (channel),
- sqlite3_errmsg (priv->db));
- goto out;
- }
-
- sqlite3_bind_text (sql, 1, get_channel_name (channel), -1, SQLITE_TRANSIENT);
- sqlite3_bind_int (sql, 2, msg_id);
-
- e = sqlite3_step (sql);
- /* return the first (most recent) event if a raw is found */
- if (e == SQLITE_ROW)
- retval = g_strdup ((const gchar *) sqlite3_column_text (sql, 0));
- else if (e == SQLITE_ERROR)
- CRITICAL ("SQL Error: %s", sqlite3_errmsg (priv->db));
-
-out:
- if (sql != NULL)
- sqlite3_finalize (sql);
-
- return retval;
-}
-
-
-/**
- * _tpl_log_store_sqlite_log_id_is_present:
- * @self: A TplLogStoreSqlite
- * @log_id: the log identifier token
- *
- * Checks if @log_id is present in DB or not.
- *
- * Note that absence of @log_id in the current Sqlite doesn't mean
- * that the message has never been logged. Sqlite currently maintains a record
- * of recent log identifier (currently fresher than 5 days).
- *
- * This method can be safely used for a just arrived or just acknowledged
- * message.
- *
- * Returns: %TRUE if @log_id is found, %FALSE otherwise
- */
-gboolean
-_tpl_log_store_sqlite_log_id_is_present (TplLogStore *self,
- const gchar* log_id)
-{
- TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
- sqlite3_stmt *sql = NULL;
- gboolean retval = TRUE; /* TRUE = present, which usually is a failure */
- int e;
-
- g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), FALSE);
- g_return_val_if_fail (!TPL_STR_EMPTY (log_id), FALSE);
-
- e = sqlite3_prepare_v2 (priv->db, "SELECT log_identifier "
- "FROM message_cache "
- "WHERE log_identifier=?",
- -1, &sql, NULL);
- if (e != SQLITE_OK)
- {
- CRITICAL ("Error preparing SQL to check log_id %s presence: %s",
- log_id, sqlite3_errmsg (priv->db));
- goto out;
- }
-
- sqlite3_bind_text (sql, 1, log_id, -1, SQLITE_TRANSIENT);
-
- e = sqlite3_step (sql);
- if (e == SQLITE_DONE)
- {
- DEBUG ("msg id %s not found, returning FALSE", log_id);
- retval = FALSE;
- }
- else if (e == SQLITE_ROW)
- DEBUG ("msg id %s found, returning TRUE", log_id);
- else if (e != SQLITE_ROW)
- CRITICAL ("SQL Error: %s", sqlite3_errmsg (priv->db));
-
-out:
- if (sql != NULL)
- sqlite3_finalize (sql);
-
- return retval;
-}
-
static gboolean
tpl_log_store_sqlite_add_message_counter (TplLogStore *self,
@@ -585,38 +486,6 @@ out:
return retval;
}
-static gboolean
-tpl_log_store_sqlite_add_message_cache (TplLogStore *self,
- TplEvent *message,
- GError **error)
-{
- const char *log_id;
- gboolean retval = FALSE;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- log_id = _tpl_event_get_log_id (message);
- DEBUG ("received %s, considering if can be cached", log_id);
- if (_tpl_log_store_sqlite_log_id_is_present (self, log_id))
- {
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_PRESENT,
- "in %s: log-id already logged: %s", G_STRFUNC, log_id);
-
- goto out;
- }
-
- DEBUG ("caching %s", log_id);
- retval = _insert_to_cache_table (self, message, error);
-
-out:
- /* check that we set an error if appropriate */
- g_assert ((retval == TRUE && *error == NULL) ||
- (retval == FALSE && *error != NULL));
-
- return retval;
-}
-
/**
* tpl_log_store_sqlite_add_event:
@@ -657,6 +526,7 @@ tpl_log_store_sqlite_add_event (TplLogStore *self,
gboolean retval = FALSE;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
if (!TPL_IS_LOG_STORE_SQLITE (self))
{
g_set_error (error, TPL_LOG_STORE_ERROR,
@@ -664,6 +534,7 @@ tpl_log_store_sqlite_add_event (TplLogStore *self,
"TplLogStoreSqlite intance needed");
goto out;
}
+
if (!TPL_IS_EVENT (message))
{
g_set_error (error, TPL_LOG_STORE_ERROR,
@@ -671,12 +542,6 @@ tpl_log_store_sqlite_add_event (TplLogStore *self,
goto out;
}
- retval = tpl_log_store_sqlite_add_message_cache (self, message, error);
- if (retval == FALSE)
- /* either the message has already been log, or a SQLite fatal error
- * occurred, I won't update the counter table */
- goto out;
-
retval = tpl_log_store_sqlite_add_message_counter (self, message, error);
out:
@@ -688,215 +553,156 @@ out:
return retval;
}
-static gboolean
-_insert_to_cache_table (TplLogStore *self,
- TplEvent *message,
+
+static void
+tpl_log_store_sqlite_purge_pending_messages (TplLogStoreSqlite *self,
+ GTimeSpan delta,
GError **error)
{
TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
- const char *account, *channel, *identifier, *log_id;
- gboolean chatroom;
- char *date = NULL;
- gint msg_id;
sqlite3_stmt *sql = NULL;
- gboolean retval = FALSE;
+ GDateTime *now;
+ GDateTime *timestamp;
+ gchar *date;
int e;
- if (!TPL_IS_TEXT_EVENT (message))
- {
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
- "Message not handled by this log store");
-
- goto out;
- }
+ g_return_if_fail (error == NULL || *error == NULL);
+ g_return_if_fail (TPL_IS_LOG_STORE_SQLITE (self));
- account = get_account_name_from_event (message);
- channel = get_channel_name_from_event (message);
- identifier = _tpl_event_get_target_id (message);
- log_id = _tpl_event_get_log_id (message);
- msg_id = _tpl_text_event_get_pending_msg_id (TPL_TEXT_EVENT (message));
- chatroom = _tpl_event_target_is_room (message);
- date = get_datetime (message);
+ now = g_date_time_new_now_utc ();
+ timestamp = g_date_time_add (now, -delta);
- DEBUG ("channel = %s", channel);
- DEBUG ("account = %s", account);
- DEBUG ("chat_identifier = %s", identifier);
- DEBUG ("log_identifier = %s", log_id);
- DEBUG ("pending_msg_id = %d (%s)", msg_id,
- (TPL_TEXT_EVENT_MSG_ID_IS_VALID (msg_id) ?
- "pending" : "acknowledged or sent"));
- DEBUG ("chatroom = %i", chatroom);
- DEBUG ("date = %s", date);
+ date = g_date_time_format (timestamp,
+ TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT);
- if (TPL_STR_EMPTY (account) || TPL_STR_EMPTY (channel) ||
- TPL_STR_EMPTY (log_id) || TPL_STR_EMPTY (date))
- {
- g_set_error_literal (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
- "passed LogStore has at least one of the needed properties unset: "
- "account-path, channel-path, log-id, timestamp");
+ g_date_time_unref (now);
+ g_date_time_unref (timestamp);
- goto out;
- }
+ DEBUG ("Purging entries older than %s (%u seconds ago)", date, (guint) delta);
e = sqlite3_prepare_v2 (priv->db,
- "INSERT INTO message_cache "
- "(channel, account, pending_msg_id, log_identifier, "
- "chat_identifier, chatroom, date) "
- "VALUES (?, ?, ?, ?, ?, ?, datetime(?))",
+ "DELETE FROM pendign_messages WHERE date<datetime(?)",
-1, &sql, NULL);
+
if (e != SQLITE_OK)
{
g_set_error (error, TPL_LOG_STORE_ERROR,
TPL_LOG_STORE_ERROR_ADD_EVENT,
- "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
+ "SQL Error preparing statement in %s: %s", G_STRFUNC,
+ sqlite3_errmsg (priv->db));
goto out;
}
- sqlite3_bind_text (sql, 1, channel, -1, SQLITE_TRANSIENT);
- sqlite3_bind_text (sql, 2, account, -1, SQLITE_TRANSIENT);
- /* insert NULL if ACKNOWLEDGED (ie sent message's entries, which are created
- * ACK'd */
- if (!TPL_TEXT_EVENT_MSG_ID_IS_VALID (msg_id))
- sqlite3_bind_null (sql, 3);
- else
- sqlite3_bind_int (sql, 3, msg_id);
- sqlite3_bind_text (sql, 4, log_id, -1, SQLITE_TRANSIENT);
- sqlite3_bind_text (sql, 5, identifier, -1, SQLITE_TRANSIENT);
- sqlite3_bind_int (sql, 6, chatroom);
- sqlite3_bind_text (sql, 7, date, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text (sql, 1, date, -1, SQLITE_TRANSIENT);
e = sqlite3_step (sql);
if (e != SQLITE_DONE)
{
g_set_error (error, TPL_LOG_STORE_ERROR,
TPL_LOG_STORE_ERROR_ADD_EVENT,
- "SQL Error bind in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
-
- goto out;
+ "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
}
- retval = TRUE;
-
out:
- g_free (date);
-
if (sql != NULL)
sqlite3_finalize (sql);
- /* check that we set an error if appropriate */
- g_assert ((retval == TRUE && *error == NULL) ||
- (retval == FALSE && *error != NULL));
+ g_free (date);
+}
- return retval;
+
+static gboolean
+purge_event_timeout (gpointer logstore)
+{
+ GError *error = NULL;
+ TplLogStoreSqlite *self = logstore;
+
+ tpl_log_store_sqlite_purge_pending_messages (self,
+ TPL_LOG_STORE_SQLITE_CLEANUP_DELTA_LIMIT,
+ &error);
+
+ if (error != NULL)
+ {
+ CRITICAL ("Unable to purge entries: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* return TRUE to avoid g_timeout_add_seconds cancel the operation */
+ return TRUE;
}
-/**
- * _tpl_log_store_sqlite_get_log_ids:
- * @self: a TplLogStoreSqlite instance
- * @channel: a pointer to a TpChannel or NULL
- * @timestamp: selects entries which timestamp is older than @timestamp.
- * use %G_MAXUINT to obtain all the entries.
- * @error: set if an error occurs
- *
- * It gets all the log-ids for messages matching the object-path of
- * @channel and older than @timestamp.
- *
- * If @channel is %NULL, it will get all the existing log-ids.
- *
- * All the entries will be filtered against @timestamp, returning only log-ids
- * older than this value (gint64). Set it to %G_MAXINT64 or any other value in
- * the future to obtain all the entries.
- * For example, to obtain entries older than one day ago, use
- * @timestamp = (now - 86400)
- *
- * Note that (in case @channel is not %NULL) this method might return log-ids
- * which are not currently related to @channel but just share the object-path,
- * in fact it is possible that an channel-path is reused over time but referring
- * to two completely different channels.
- * There is no way to understand if a channel-path is actually related to a
- * specific TpChannel instance with the same path or not, just knowking its
- * path.
- * This is not a problem, though, since log-ids are unique within TPL. If two
- * log-ids match, they relates to the same TplEvent instance.
- *
- * Returns: a list of log-id
- */
-GList *
-_tpl_log_store_sqlite_get_log_ids (TplLogStore *self,
- TpChannel *channel,
- gint64 unix_timestamp,
- GError **error)
+static GList *
+tpl_log_store_sqlite_get_entities (TplLogStore *self,
+ TpAccount *account)
{
TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
sqlite3_stmt *sql = NULL;
- GList *retval = NULL;
- GDateTime *timestamp;
- gchar *date;
int e;
+ GList *list = NULL;
+ const char *account_name = get_account_name (account);
- g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), NULL);
+ DEBUG ("account = %s", account_name);
- if (channel == NULL)
- /* get the the log-id older than date */
- e = sqlite3_prepare_v2 (priv->db, "SELECT log_identifier "
- "FROM message_cache "
- "WHERE date<datetime(?)",
- -1, &sql, NULL);
- else
- /* get the log-ids related to channel and older than date */
- e = sqlite3_prepare_v2 (priv->db, "SELECT log_identifier "
- "FROM message_cache "
- "WHERE date<datetime(?) AND channel=?",
- -1, &sql, NULL);
+ /* list all the identifiers known to the database */
+ e = sqlite3_prepare_v2 (priv->db,
+ "SELECT DISTINCT identifier, chatroom FROM messagecounts WHERE "
+ "account=?",
+ -1, &sql, NULL);
if (e != SQLITE_OK)
{
- CRITICAL ("Error preparing SQL for log-id list: %s",
+ DEBUG ("Failed to prepare SQL: %s",
sqlite3_errmsg (priv->db));
+
goto out;
}
- timestamp = g_date_time_new_from_unix_utc (unix_timestamp);
- date = g_date_time_format (timestamp,
- TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT);
- sqlite3_bind_text (sql, 1, date, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text (sql, 1, account_name, -1, SQLITE_TRANSIENT);
- g_date_time_unref (timestamp);
- g_free (date);
+ while ((e = sqlite3_step (sql)) == SQLITE_ROW)
+ {
+ TplEntity *entity;
+ const char *identifier;
+ gboolean chatroom;
+ TplEntityType type;
- if (channel != NULL)
- sqlite3_bind_text (sql, 2, get_channel_name (channel), -1,
- SQLITE_TRANSIENT);
+ /* for some reason this returns unsigned char */
+ identifier = (const char *) sqlite3_column_text (sql, 0);
+ chatroom = sqlite3_column_int (sql, 1);
+ type = chatroom ? TPL_ENTITY_ROOM : TPL_ENTITY_CONTACT;
- /* create the log-id list */
- while (SQLITE_ROW == (e = sqlite3_step (sql)))
- {
- gchar *log_id = g_strdup ((const gchar *) sqlite3_column_text (sql, 0));
- retval = g_list_prepend (retval, log_id);
- }
+ DEBUG ("identifier = %s, chatroom = %i", identifier, chatroom);
+ entity = tpl_entity_new (identifier, type, NULL, NULL);
+
+ list = g_list_prepend (list, entity);
+ }
if (e != SQLITE_DONE)
{
- g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR,
- TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES,
- "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
- g_list_foreach (retval, (GFunc) g_free, NULL);
- g_list_free (retval);
- retval = NULL;
+ DEBUG ("Failed to execute SQL: %s",
+ sqlite3_errmsg (priv->db));
+ goto out;
}
out:
if (sql != NULL)
sqlite3_finalize (sql);
- /* check that we set an error if appropriate
- * NOTE: retval == NULL && *error !=
- * NULL doesn't apply to this method, since NULL is also for an empty list */
- g_assert ((retval != NULL && *error == NULL) || retval == NULL);
+ return list;
+}
- return retval;
+static void
+log_store_iface_init (TplLogStoreInterface *iface)
+{
+ iface->get_name = tpl_log_store_sqlite_get_name;
+ iface->add_event = tpl_log_store_sqlite_add_event;
+ iface->get_entities = tpl_log_store_sqlite_get_entities;
+}
+
+TplLogStore *
+_tpl_log_store_sqlite_dup (void)
+{
+ return g_object_new (TPL_TYPE_LOG_STORE_SQLITE, NULL);
}
@@ -906,23 +712,12 @@ out:
* @channel: a pointer to a TpChannel or NULL
* @error: set if an error occurs
*
- * It gets all the log-ids for messages matching the object-path of
- * @channel and which are still set as not acknowledged in the persisten
- * layer.
- * If @channel is %NULL, it will get all the pending messages in the
- * persistence layer, not filtering against any channel.
- *
- * Note that (in case @channel is not %NULL) this method might return log-ids
- * which are not currently related to @channel but just share the object-path,
- * in fact it is possible that an channel-path is reused over time but referring
- * to two completely different channels.
- * There is no way to understand if a channel-path is actually related to a
- * specific TpChannel instance with the same path or not, just knowking its
- * path.
- * This is not a problem, though, since log-ids are unique within TPL. If two
- * log-ids match, they relates to the same TplEvent instance.
+ * Gets a #GList of pending message log-id associated with the @channel
+ * object-path. Note that those pending messaged might only share the
+ * object-path name, for this reason, messages must be validated
+ * against pending list provided by the connection manager.
*
- * Returns: a list of log-id
+ * Returns: (transfer full): a #GList of log-id
*/
GList *
_tpl_log_store_sqlite_get_pending_messages (TplLogStore *self,
@@ -935,37 +730,34 @@ _tpl_log_store_sqlite_get_pending_messages (TplLogStore *self,
int e;
g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), NULL);
- g_return_val_if_fail (TPL_IS_CHANNEL (channel) || channel == NULL, NULL);
+ g_return_val_if_fail (TPL_IS_CHANNEL (channel), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- if (channel == NULL)
- /* get all the pending log-ids */
- e = sqlite3_prepare_v2 (priv->db, "SELECT log_identifier "
- "FROM message_cache "
- "WHERE pending_msg_id is NOT NULL",
- -1, &sql, NULL);
- else
- /* get the pending log-ids related to channel */
- e = sqlite3_prepare_v2 (priv->db, "SELECT log_identifier "
- "FROM message_cache "
- "WHERE pending_msg_id is NOT NULL AND channel=?",
- -1, &sql, NULL);
+ e = sqlite3_prepare_v2 (priv->db, "SELECT log_id"
+ "FROM pending_messages "
+ "WHERE channel=?",
+ -1, &sql, NULL);
+
if (e != SQLITE_OK)
{
CRITICAL ("Error preparing SQL for pending messages list: %s",
sqlite3_errmsg (priv->db));
+ g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES,
+ "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
goto out;
}
- if (channel != NULL)
- sqlite3_bind_text (sql, 1, get_channel_name (channel), -1,
- SQLITE_TRANSIENT);
+ sqlite3_bind_text (sql, 1, get_channel_name (channel), -1,
+ SQLITE_TRANSIENT);
while (SQLITE_ROW == (e = sqlite3_step (sql)))
{
/* create the pending messages list */
gchar *log_id = g_strdup ((const gchar *) sqlite3_column_text (sql, 0));
- retval = g_list_prepend (retval, log_id);
+ retval = g_list_insert_sorted (retval,
+ log_id,
+ (GCompareFunc) g_strcmp0);
}
if (e != SQLITE_DONE)
@@ -992,230 +784,157 @@ out:
return retval;
}
-void
-_tpl_log_store_sqlite_set_acknowledgment_by_msg_id (TplLogStore *self,
- TpChannel *channel,
- guint msg_id,
- GError **error)
-{
- gchar *log_id = NULL;
-
- g_return_if_fail (error == NULL || *error == NULL);
- g_return_if_fail (TPL_IS_LOG_STORE_SQLITE (self));
- g_return_if_fail (TP_IS_CHANNEL (channel));
-
- log_id = _cache_msg_id_is_present (self, channel, msg_id);
-
- if (log_id != NULL)
- {
- DEBUG ("%s: found %s for pending id %d", get_channel_name (channel),
- log_id, msg_id);
- _tpl_log_store_sqlite_set_acknowledgment (self, log_id, error);
- }
- else
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_NOT_PRESENT,
- "Unable to acknowledge pending message %d for channel %s: not found",
- msg_id, get_channel_name (channel));
-
- g_free (log_id);
-}
-void
-_tpl_log_store_sqlite_set_acknowledgment (TplLogStore *self,
- const gchar* log_id,
+/**
+ *_tpl_log_store_sqlite_remove_pending_messages:
+ * @self: a #TplLogStore
+ * @log_ids: a #GList of string
+ * @error: a #GError to be set on error, or NULL
+ *
+ * Removes listed pending IDs.
+ *
+ * Returns: #TRUE on success, #FALSE on error with @error set
+ */
+gboolean
+_tpl_log_store_sqlite_remove_pending_messages (TplLogStore *self,
+ GList *log_ids,
GError **error)
{
TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
+ gboolean retval = TRUE;
+ GString *query = NULL;
+ GList *it;
sqlite3_stmt *sql = NULL;
- int e;
- g_return_if_fail (error == NULL || *error == NULL);
- g_return_if_fail (TPL_IS_LOG_STORE_SQLITE (self));
- g_return_if_fail (!TPL_STR_EMPTY (log_id));
+ g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (log_ids != NULL, FALSE);
- if (!_tpl_log_store_sqlite_log_id_is_present (TPL_LOG_STORE (self), log_id))
- {
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_NOT_PRESENT,
- "log_id %s not found", log_id);
- goto out;
- }
+ query = g_string_new ("DELETE FROM pending_messages WHERE log_id IN (");
- e = sqlite3_prepare_v2 (priv->db, "UPDATE message_cache "
- "SET pending_msg_id=NULL "
- "WHERE log_identifier=?", -1, &sql, NULL);
- if (e != SQLITE_OK)
+ g_string_append_printf (query, "'%s'", (const gchar *) log_ids->data);
+
+ for (it = g_list_next (log_ids); it != NULL; it = g_list_next (it))
+ g_string_append_printf (query, ",'%s'", (const gchar *) it->data);
+
+ g_string_append (query, ")");
+
+ if (sqlite3_prepare_v2 (priv->db, query->str, -1, &sql, NULL) != SQLITE_OK)
{
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
+ g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_REMOVE_PENDING_MESSAGES,
"SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
-
+ retval = FALSE;
goto out;
}
- sqlite3_bind_text (sql, 1, log_id, -1, SQLITE_TRANSIENT);
-
- e = sqlite3_step (sql);
- if (e != SQLITE_DONE)
+ if (sqlite3_step (sql) != SQLITE_DONE)
{
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
+ g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_REMOVE_PENDING_MESSAGES,
"SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
+ retval = FALSE;
+ goto out;
}
out:
+ if (query != NULL)
+ g_string_free (query, TRUE);
+
if (sql != NULL)
sqlite3_finalize (sql);
+
+ return retval;
}
-static void
-tpl_log_store_sqlite_purge (TplLogStoreSqlite *self,
- GTimeSpan delta,
+/**
+ *_tpl_log_store_sqlite_add_pending_message:
+ * @self: a #TplLogStore
+ * @channel: a #TpChannel
+ * @log_id: a string unique identifier for the log
+ * @timestamp: a unix utc timestamp
+ * @error: a #GError to be set on error, or NULL
+ *
+ * Removes listed pending IDs.
+ *
+ * Returns: #TRUE on success, #FALSE on error with @error set
+ */
+gboolean
+_tpl_log_store_sqlite_add_pending_message (TplLogStore *self,
+ TpChannel *channel,
+ const gchar *log_id,
+ gint64 timestamp,
GError **error)
{
TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
+ gboolean retval = FALSE;
+ const gchar *channel_path;
+ gchar *date = NULL;
sqlite3_stmt *sql = NULL;
- GDateTime *now;
- GDateTime *timestamp;
- gchar *date;
int e;
- g_return_if_fail (error == NULL || *error == NULL);
- g_return_if_fail (TPL_IS_LOG_STORE_SQLITE (self));
-
- now = g_date_time_new_now_utc ();
- timestamp = g_date_time_add (now, -delta);
-
- date = g_date_time_format (timestamp,
- TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_date_time_unref (now);
- g_date_time_unref (timestamp);
+ DEBUG ("caching pending message %s", log_id);
- DEBUG ("Purging entries older than %s (%u seconds ago)", date, (guint) delta);
+ channel_path = get_channel_name (channel);
+ date = get_datetime (timestamp);
- e = sqlite3_prepare_v2 (priv->db, "DELETE FROM message_cache "
- "WHERE date<datetime(?)",
- -1, &sql, NULL);
+ DEBUG ("channel = %s", channel_path);
+ DEBUG ("date = %s", date);
- if (e != SQLITE_OK)
+ if (TPL_STR_EMPTY (channel_path)
+ || TPL_STR_EMPTY (log_id)
+ || TPL_STR_EMPTY (date))
{
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
- "SQL Error preparing statement in %s: %s", G_STRFUNC,
- sqlite3_errmsg (priv->db));
-
+ g_set_error_literal (error, TPL_LOG_STORE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE,
+ "passed LogStore has at least one of the needed properties unset: "
+ "channel-path, log-id, timestamp");
goto out;
}
- sqlite3_bind_text (sql, 1, date, -1, SQLITE_TRANSIENT);
-
- e = sqlite3_step (sql);
- if (e != SQLITE_DONE)
- {
- g_set_error (error, TPL_LOG_STORE_ERROR,
- TPL_LOG_STORE_ERROR_ADD_EVENT,
- "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
- }
-
-out:
- if (sql != NULL)
- sqlite3_finalize (sql);
-
- g_free (date);
-}
-
-static gboolean
-purge_event_timeout (gpointer logstore)
-{
- GError *error = NULL;
- TplLogStoreSqlite *self = logstore;
-
- tpl_log_store_sqlite_purge (self, TPL_LOG_STORE_SQLITE_CLEANUP_DELTA_LIMIT,
- &error);
- if (error != NULL)
- {
- CRITICAL ("Unable to purge entries: %s", error->message);
- g_error_free (error);
- }
-
- /* return TRUE to avoid g_timeout_add_seconds cancel the operation */
- return TRUE;
-}
-
-static GList *
-tpl_log_store_sqlite_get_entities (TplLogStore *self,
- TpAccount *account)
-{
- TplLogStoreSqlitePrivate *priv = GET_PRIV (self);
- sqlite3_stmt *sql = NULL;
- int e;
- GList *list = NULL;
- const char *account_name = get_account_name (account);
-
- DEBUG ("account = %s", account_name);
-
- /* list all the identifiers known to the database */
e = sqlite3_prepare_v2 (priv->db,
- "SELECT DISTINCT identifier, chatroom FROM messagecounts WHERE "
- "account=?",
+ "INSERT INTO pending_messages "
+ "(channel, log_id, data) "
+ "VALUES (?, ?, datetime(?))",
-1, &sql, NULL);
if (e != SQLITE_OK)
{
- DEBUG ("Failed to prepare SQL: %s",
- sqlite3_errmsg (priv->db));
-
+ g_set_error (error, TPL_LOG_STORE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE,
+ "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
goto out;
}
- sqlite3_bind_text (sql, 1, account_name, -1, SQLITE_TRANSIENT);
-
- while ((e = sqlite3_step (sql)) == SQLITE_ROW)
- {
- TplEntity *entity;
- const char *identifier;
- gboolean chatroom;
- TplEntityType type;
-
- /* for some reason this returns unsigned char */
- identifier = (const char *) sqlite3_column_text (sql, 0);
- chatroom = sqlite3_column_int (sql, 1);
- type = chatroom ? TPL_ENTITY_ROOM : TPL_ENTITY_CONTACT;
-
- DEBUG ("identifier = %s, chatroom = %i", identifier, chatroom);
-
- entity = tpl_entity_new (identifier, type, NULL, NULL);
+ sqlite3_bind_text (sql, 1, channel_path, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text (sql, 2, log_id, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text (sql, 3, date, -1, SQLITE_TRANSIENT);
- list = g_list_prepend (list, entity);
- }
+ e = sqlite3_step (sql);
if (e != SQLITE_DONE)
{
- DEBUG ("Failed to execute SQL: %s",
- sqlite3_errmsg (priv->db));
+ g_set_error (error, TPL_LOG_STORE_ERROR,
+ TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE,
+ "SQL Error bind in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db));
goto out;
}
+ retval = TRUE;
+
out:
+ g_free (date);
+
if (sql != NULL)
sqlite3_finalize (sql);
- return list;
-}
+ /* check that we set an error if appropriate */
+ g_assert ((retval == TRUE && *error == NULL) ||
+ (retval == FALSE && *error != NULL));
-static void
-log_store_iface_init (TplLogStoreInterface *iface)
-{
- iface->get_name = tpl_log_store_sqlite_get_name;
- iface->add_event = tpl_log_store_sqlite_add_event;
- iface->get_entities = tpl_log_store_sqlite_get_entities;
+ return retval;
}
-TplLogStore *
-_tpl_log_store_sqlite_dup (void)
-{
- return g_object_new (TPL_TYPE_LOG_STORE_SQLITE, NULL);
-}
gint64
_tpl_log_store_sqlite_get_most_recent (TplLogStoreSqlite *self,