summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam@afuera.me.uk>2020-08-31 14:02:43 +0000
committerSam Thursfield <sam@afuera.me.uk>2020-08-31 14:02:43 +0000
commitd386eafd5cf09273386f37a2b90d22229a1c4d00 (patch)
tree34f391cd78e75ad48704343aa99c2e60a9fcf478
parented7c9af385ea91d06d37d68f1c0236dbad2e3355 (diff)
parentce8af080728c42c1c8a54e6914837de4c25d4a90 (diff)
downloadtracker-d386eafd5cf09273386f37a2b90d22229a1c4d00.tar.gz
Merge branch 'wip/carlosg/release-memory' into 'master'
Release memory on inactivity See merge request GNOME/tracker!306
-rw-r--r--src/libtracker-data/tracker-data-manager.c6
-rw-r--r--src/libtracker-data/tracker-data-manager.h2
-rw-r--r--src/libtracker-data/tracker-db-interface-sqlite.c12
-rw-r--r--src/libtracker-data/tracker-db-interface-sqlite.h1
-rw-r--r--src/libtracker-data/tracker-db-manager.c41
-rw-r--r--src/libtracker-data/tracker-db-manager.h1
-rw-r--r--src/libtracker-data/tracker-sparql.c18
-rw-r--r--src/libtracker-sparql/direct/tracker-direct-statement.c5
-rw-r--r--src/libtracker-sparql/direct/tracker-direct.c69
-rw-r--r--src/libtracker-sparql/direct/tracker-direct.h2
10 files changed, 157 insertions, 0 deletions
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index fd02de2a8..a5e077041 100644
--- a/src/libtracker-data/tracker-data-manager.c
+++ b/src/libtracker-data/tracker-data-manager.c
@@ -5102,3 +5102,9 @@ tracker_data_manager_rollback_graphs (TrackerDataManager *manager)
{
g_clear_pointer (&manager->transaction_graphs, g_hash_table_unref);
}
+
+void
+tracker_data_manager_release_memory (TrackerDataManager *manager)
+{
+ tracker_db_manager_release_memory (manager->db_manager);
+}
diff --git a/src/libtracker-data/tracker-data-manager.h b/src/libtracker-data/tracker-data-manager.h
index dbd4d86fc..db8b4e509 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -105,6 +105,8 @@ guint tracker_data_manager_get_generation (TrackerDataManager *
void tracker_data_manager_rollback_graphs (TrackerDataManager *manager);
void tracker_data_manager_commit_graphs (TrackerDataManager *manager);
+void tracker_data_manager_release_memory (TrackerDataManager *manager);
+
G_END_DECLS
#endif /* __LIBTRACKER_DATA_MANAGER_H__ */
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c b/src/libtracker-data/tracker-db-interface-sqlite.c
index d758f92e0..23b7b7967 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -3757,3 +3757,15 @@ tracker_db_interface_detach_database (TrackerDBInterface *db_interface,
sqlite3_finalize (stmt);
return retval;
}
+
+gssize
+tracker_db_interface_sqlite_release_memory (TrackerDBInterface *db_interface)
+{
+ db_interface->select_stmt_lru.head = db_interface->select_stmt_lru.tail = NULL;
+ db_interface->select_stmt_lru.size = 0;
+ db_interface->update_stmt_lru.head = db_interface->update_stmt_lru.tail = NULL;
+ db_interface->update_stmt_lru.size = 0;
+ g_hash_table_remove_all (db_interface->dynamic_statements);
+
+ return (gssize) sqlite3_db_release_memory (db_interface->db);
+}
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.h b/src/libtracker-data/tracker-db-interface-sqlite.h
index cdca629f5..6a8ffb235 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.h
+++ b/src/libtracker-data/tracker-db-interface-sqlite.h
@@ -93,6 +93,7 @@ gboolean tracker_db_interface_attach_database (TrackerD
gboolean tracker_db_interface_detach_database (TrackerDBInterface *db_interface,
const gchar *name,
GError **error);
+gssize tracker_db_interface_sqlite_release_memory (TrackerDBInterface *db_interface);
G_END_DECLS
diff --git a/src/libtracker-data/tracker-db-manager.c b/src/libtracker-data/tracker-db-manager.c
index 6b3c4bdd7..a90245235 100644
--- a/src/libtracker-data/tracker-db-manager.c
+++ b/src/libtracker-data/tracker-db-manager.c
@@ -1027,6 +1027,8 @@ ensure_create_database_file (TrackerDBManager *db_manager,
iface = tracker_db_interface_sqlite_new (path,
db_manager->shared_cache_key,
0, error);
+ g_free (path);
+
if (!iface)
return FALSE;
@@ -1085,3 +1087,42 @@ tracker_db_manager_detach_database (TrackerDBManager *db_manager,
{
return tracker_db_interface_detach_database (iface, name, error);
}
+
+void
+tracker_db_manager_release_memory (TrackerDBManager *db_manager)
+{
+ TrackerDBInterface *iface;
+ gint i, len;
+
+ g_async_queue_lock (db_manager->interfaces);
+ len = g_async_queue_length_unlocked (db_manager->interfaces);
+
+ for (i = 0; i < len; i++) {
+ iface = g_async_queue_try_pop_unlocked (db_manager->interfaces);
+ if (!iface)
+ break;
+
+ if (tracker_db_interface_get_is_used (iface))
+ g_async_queue_push_unlocked (db_manager->interfaces, iface);
+ else
+ g_object_unref (iface);
+ }
+
+ if (g_async_queue_length_unlocked (db_manager->interfaces) < len) {
+ g_debug ("Freed %d readonly interfaces",
+ len - g_async_queue_length_unlocked (db_manager->interfaces));
+ }
+
+ if (db_manager->db.iface) {
+ gssize bytes;
+
+ bytes = tracker_db_interface_sqlite_release_memory (db_manager->db.iface);
+
+ if (bytes > 0) {
+ g_debug ("Freed %" G_GSSIZE_MODIFIER "d bytes from writable interface",
+ bytes);
+ }
+ }
+
+ g_async_queue_unlock (db_manager->interfaces);
+}
diff --git a/src/libtracker-data/tracker-db-manager.h b/src/libtracker-data/tracker-db-manager.h
index 486e337ba..5feb64b6f 100644
--- a/src/libtracker-data/tracker-db-manager.h
+++ b/src/libtracker-data/tracker-db-manager.h
@@ -92,6 +92,7 @@ gboolean tracker_db_manager_detach_database (TrackerDBManager
TrackerDBInterface *iface,
const gchar *name,
GError **error);
+void tracker_db_manager_release_memory (TrackerDBManager *db_manager);
G_END_DECLS
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index d372ccfc7..e55795a2b 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -2596,6 +2596,8 @@ handle_as (TrackerSparql *sparql,
binding = tracker_variable_binding_new (var, NULL, NULL);
tracker_binding_set_data_type (binding, type);
tracker_variable_set_sample_binding (var, TRACKER_VARIABLE_BINDING (binding));
+ g_object_unref (binding);
+
_append_string_printf (sparql, "AS %s ",
tracker_variable_get_sql_expression (var));
@@ -3906,6 +3908,7 @@ translate_Clear (TrackerSparql *sparql,
break;
}
+ tracker_token_unset (&sparql->current_state.graph);
g_list_free (graphs);
return handle_silent (silent, inner_error, error);
@@ -3966,6 +3969,7 @@ translate_Drop (TrackerSparql *sparql,
}
g_list_free_full (graphs, g_free);
+ tracker_token_unset (&sparql->current_state.graph);
return handle_silent (silent, inner_error, error);
}
@@ -4011,9 +4015,13 @@ translate_Create (TrackerSparql *sparql,
&inner_error))
goto error;
+ tracker_token_unset (&sparql->current_state.graph);
+
return TRUE;
error:
+ tracker_token_unset (&sparql->current_state.graph);
+
return handle_silent (silent, inner_error, error);
}
@@ -4034,11 +4042,13 @@ translate_Add (TrackerSparql *sparql,
_call_rule (sparql, NAMED_RULE_GraphOrDefault, error);
source = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_TO);
_call_rule (sparql, NAMED_RULE_GraphOrDefault, error);
destination = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
if (g_strcmp0 (source, destination) == 0) {
g_free (source);
@@ -4104,11 +4114,13 @@ translate_Move (TrackerSparql *sparql,
_call_rule (sparql, NAMED_RULE_GraphOrDefault, error);
source = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_TO);
_call_rule (sparql, NAMED_RULE_GraphOrDefault, error);
destination = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
if (g_strcmp0 (source, destination) == 0) {
g_free (source);
@@ -4184,6 +4196,7 @@ translate_Copy (TrackerSparql *sparql,
g_assert (!tracker_token_is_empty (&sparql->current_state.graph) ||
sparql->current_state.graph_op == GRAPH_OP_DEFAULT);
source = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_TO);
@@ -4191,6 +4204,7 @@ translate_Copy (TrackerSparql *sparql,
g_assert (!tracker_token_is_empty (&sparql->current_state.graph) ||
sparql->current_state.graph_op == GRAPH_OP_DEFAULT);
destination = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ tracker_token_unset (&sparql->current_state.graph);
if (g_strcmp0 (source, destination) == 0) {
g_free (source);
@@ -5146,6 +5160,7 @@ translate_ServiceGraphPattern (TrackerSparql *sparql,
binding = tracker_variable_binding_new (var, NULL, NULL);
tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_STRING);
_add_binding (sparql, binding);
+ g_object_unref (binding);
_append_string_printf (sparql, "col%d AS %s ",
i, tracker_variable_get_sql_expression (var));
@@ -5274,6 +5289,7 @@ translate_Bind (TrackerSparql *sparql,
binding = tracker_variable_binding_new (variable, NULL, NULL);
tracker_binding_set_data_type (binding, type);
tracker_variable_set_sample_binding (variable, TRACKER_VARIABLE_BINDING (binding));
+ g_object_unref (binding);
if (!is_empty) {
_append_string (sparql, "FROM (");
@@ -5363,6 +5379,7 @@ translate_InlineDataOneVar (TrackerSparql *sparql,
var = _last_node_variable (sparql);
binding = tracker_variable_binding_new (var, NULL, NULL);
tracker_variable_set_sample_binding (var, TRACKER_VARIABLE_BINDING (binding));
+ g_object_unref (binding);
_append_string (sparql, "(");
_append_variable_sql (sparql, var);
@@ -5418,6 +5435,7 @@ translate_InlineDataFull (TrackerSparql *sparql,
var = _last_node_variable (sparql);
binding = tracker_variable_binding_new (var, NULL, NULL);
tracker_variable_set_sample_binding (var, TRACKER_VARIABLE_BINDING (binding));
+ g_object_unref (binding);
n_args++;
_append_variable_sql (sparql, var);
diff --git a/src/libtracker-sparql/direct/tracker-direct-statement.c b/src/libtracker-sparql/direct/tracker-direct-statement.c
index 8e1bcdd8a..4a281de5d 100644
--- a/src/libtracker-sparql/direct/tracker-direct-statement.c
+++ b/src/libtracker-sparql/direct/tracker-direct-statement.c
@@ -239,6 +239,7 @@ tracker_direct_statement_execute_finish (TrackerSparqlStatement *stmt,
GAsyncResult *res,
GError **error)
{
+ TrackerDirectConnection *conn;
TrackerSparqlCursor *cursor;
GError *inner_error = NULL;
@@ -246,6 +247,10 @@ tracker_direct_statement_execute_finish (TrackerSparqlStatement *stmt,
if (inner_error)
g_propagate_error (error, _translate_internal_error (inner_error));
+ g_object_get (stmt, "connection", &conn, NULL);
+ tracker_direct_connection_update_timestamp (conn);
+ g_object_unref (conn);
+
return cursor;
}
diff --git a/src/libtracker-sparql/direct/tracker-direct.c b/src/libtracker-sparql/direct/tracker-direct.c
index 07423c47b..3d867283c 100644
--- a/src/libtracker-sparql/direct/tracker-direct.c
+++ b/src/libtracker-sparql/direct/tracker-direct.c
@@ -45,6 +45,11 @@ struct _TrackerDirectConnectionPrivate
GList *notifiers;
+ gint64 timestamp;
+ gint64 cleanup_timestamp;
+
+ guint cleanup_timeout_id;
+
guint initialized : 1;
guint closing : 1;
};
@@ -63,6 +68,7 @@ typedef enum {
TASK_TYPE_QUERY,
TASK_TYPE_UPDATE,
TASK_TYPE_UPDATE_BLANK,
+ TASK_TYPE_RELEASE_MEMORY,
} TaskType;
typedef struct {
@@ -103,6 +109,37 @@ task_data_free (TaskData *task)
g_free (task);
}
+static gboolean
+cleanup_timeout_cb (gpointer user_data)
+{
+ TrackerDirectConnection *conn = user_data;
+ TrackerDirectConnectionPrivate *priv;
+ gint64 timestamp;
+ GTask *task;
+
+ priv = tracker_direct_connection_get_instance_private (conn);
+ timestamp = g_get_monotonic_time ();
+
+ /* If we already cleaned up */
+ if (priv->timestamp < priv->cleanup_timestamp)
+ return G_SOURCE_CONTINUE;
+ /* If the connection was used less than 10s ago */
+ if (timestamp - priv->timestamp < 10 * G_USEC_PER_SEC)
+ return G_SOURCE_CONTINUE;
+
+ priv->cleanup_timestamp = timestamp;
+
+ task = g_task_new (conn, NULL, NULL, NULL);
+ g_task_set_task_data (task,
+ task_data_query_new (TASK_TYPE_RELEASE_MEMORY, NULL),
+ (GDestroyNotify) task_data_free);
+
+ g_thread_pool_push (priv->update_thread, task, NULL);
+
+ return G_SOURCE_CONTINUE;
+}
+
+
static void
update_thread_func (gpointer data,
gpointer user_data)
@@ -115,6 +152,7 @@ update_thread_func (gpointer data,
GError *error = NULL;
gpointer retval = NULL;
GDestroyNotify destroy_notify = NULL;
+ gboolean update_timestamp = TRUE;
conn = user_data;
priv = tracker_direct_connection_get_instance_private (conn);
@@ -133,6 +171,10 @@ update_thread_func (gpointer data,
retval = tracker_data_update_sparql_blank (tracker_data, task_data->query, &error);
destroy_notify = (GDestroyNotify) g_variant_unref;
break;
+ case TASK_TYPE_RELEASE_MEMORY:
+ tracker_data_manager_release_memory (priv->data_manager);
+ update_timestamp = FALSE;
+ break;
}
if (error)
@@ -143,6 +185,10 @@ update_thread_func (gpointer data,
g_task_return_boolean (task, TRUE);
g_object_unref (task);
+
+ if (update_timestamp)
+ tracker_direct_connection_update_timestamp (conn);
+
g_mutex_unlock (&priv->mutex);
}
@@ -284,6 +330,9 @@ tracker_direct_connection_initable_init (GInitable *initable,
g_hash_table_unref (namespaces);
+ priv->cleanup_timeout_id =
+ g_timeout_add_seconds (30, cleanup_timeout_cb, conn);
+
return TRUE;
}
@@ -542,6 +591,9 @@ tracker_direct_connection_finalize (GObject *object)
conn = TRACKER_DIRECT_CONNECTION (object);
priv = tracker_direct_connection_get_instance_private (conn);
+ if (!priv->closing)
+ tracker_sparql_connection_close (TRACKER_SPARQL_CONNECTION (object));
+
g_clear_object (&priv->store);
g_clear_object (&priv->ontology);
g_clear_object (&priv->namespace_manager);
@@ -623,6 +675,7 @@ tracker_direct_connection_query (TrackerSparqlConnection *self,
g_mutex_lock (&priv->mutex);
query = tracker_sparql_new (priv->data_manager, sparql);
cursor = tracker_sparql_execute_cursor (query, NULL, &inner_error);
+ tracker_direct_connection_update_timestamp (conn);
g_object_unref (query);
if (cursor)
@@ -695,6 +748,7 @@ tracker_direct_connection_update (TrackerSparqlConnection *self,
g_mutex_lock (&priv->mutex);
data = tracker_data_manager_get_data (priv->data_manager);
tracker_data_update_sparql (data, sparql, &inner_error);
+ tracker_direct_connection_update_timestamp (conn);
g_mutex_unlock (&priv->mutex);
if (inner_error)
@@ -802,6 +856,7 @@ tracker_direct_connection_update_blank (TrackerSparqlConnection *self,
g_mutex_lock (&priv->mutex);
data = tracker_data_manager_get_data (priv->data_manager);
blank_nodes = tracker_data_update_sparql_blank (data, sparql, &inner_error);
+ tracker_direct_connection_update_timestamp (conn);
g_mutex_unlock (&priv->mutex);
if (inner_error)
@@ -899,6 +954,11 @@ tracker_direct_connection_close (TrackerSparqlConnection *self)
priv = tracker_direct_connection_get_instance_private (conn);
priv->closing = TRUE;
+ if (priv->cleanup_timeout_id) {
+ g_source_remove (priv->cleanup_timeout_id);
+ priv->cleanup_timeout_id = 0;
+ }
+
if (priv->update_thread) {
g_thread_pool_free (priv->update_thread, TRUE, TRUE);
priv->update_thread = NULL;
@@ -1040,3 +1100,12 @@ tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn)
priv = tracker_direct_connection_get_instance_private (conn);
return priv->data_manager;
}
+
+void
+tracker_direct_connection_update_timestamp (TrackerDirectConnection *conn)
+{
+ TrackerDirectConnectionPrivate *priv;
+
+ priv = tracker_direct_connection_get_instance_private (conn);
+ priv->timestamp = g_get_monotonic_time ();
+}
diff --git a/src/libtracker-sparql/direct/tracker-direct.h b/src/libtracker-sparql/direct/tracker-direct.h
index 264f1a2d1..c353b51ca 100644
--- a/src/libtracker-sparql/direct/tracker-direct.h
+++ b/src/libtracker-sparql/direct/tracker-direct.h
@@ -53,6 +53,8 @@ TrackerDirectConnection *tracker_direct_connection_new (TrackerSparqlConnectionF
TrackerDataManager *tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn);
+void tracker_direct_connection_update_timestamp (TrackerDirectConnection *conn);
+
/* Internal helper function */
GError *translate_db_interface_error (GError *error);