summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2023-03-27 11:24:02 -0400
committerRay Strode <rstrode@redhat.com>2023-03-27 15:27:39 -0400
commitff58f16bd5c75bea47939fed41716845cd427208 (patch)
tree882b0e0859bb09ddc33a9288a26097db3c83e238
parenta6e627bf5797a812aebe90ad840b20a4950f064f (diff)
downloadaccountsservice-ff58f16bd5c75bea47939fed41716845cd427208.tar.gz
user-manager: Deduplicate ActUser objects when possible
If act_user_manager_get_user_by_id is called twice in a row for the same user, two ActUser objects get generated, each ultimately representing the same user. That is less than ideal since the ActUser objects are owned by the user manager, not by the callers. This commit tries to minimize the amount of duplicate ActUser objects that can get put in the wild, by checking for existig in-flight requests and consolidating them. Note there can still be duplicated users if there is a act_user_manager_get_user and act_user_manager_get_user_by_id call for the same user at the same time. There's no way to deduplicate the objects in that case.
-rw-r--r--src/libaccountsservice/act-user-manager.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
index fe042a1..ac59729 100644
--- a/src/libaccountsservice/act-user-manager.c
+++ b/src/libaccountsservice/act-user-manager.c
@@ -1921,6 +1921,32 @@ fetch_user_with_id_from_accounts_service (ActUserManager *manager,
fetch_user_incrementally (request);
}
+static ActUser *
+check_fetch_user_requests_for_user (ActUserManager *manager,
+ const char *username)
+{
+ ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
+ GSList *node;
+
+ node = priv->fetch_user_requests;
+ while (node != NULL) {
+ ActUserManagerFetchUserRequest *request;
+ GSList *next_node;
+
+ request = node->data;
+ next_node = node->next;
+
+ if (request->type == ACT_USER_MANAGER_FETCH_USER_FROM_USERNAME_REQUEST) {
+ if (g_strcmp0 (request->username, username) == 0)
+ return request->user;
+ }
+
+ node = next_node;
+ }
+
+ return NULL;
+}
+
/**
* act_user_manager_get_user:
* @manager: the manager to query.
@@ -1945,6 +1971,14 @@ act_user_manager_get_user (ActUserManager *manager,
user = lookup_user_by_name (manager, username);
+ if (user == NULL) {
+ user = check_fetch_user_requests_for_user (manager, username);
+
+ if (user != NULL) {
+ g_debug ("ActUserManager: User with username '%s' fetched by username more than once before it loaded", username);
+ }
+ }
+
/* if we don't have it loaded try to load it now */
if (user == NULL) {
g_debug ("ActUserManager: trying to track new user with username %s", username);
@@ -2004,6 +2038,32 @@ load_user (ActUserManager *manager,
_act_user_update_from_object_path (user, object_path);
}
+static ActUser *
+check_fetch_user_requests_for_user_with_id (ActUserManager *manager,
+ uid_t id)
+{
+ ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
+ GSList *node;
+
+ node = priv->fetch_user_requests;
+ while (node != NULL) {
+ ActUserManagerFetchUserRequest *request;
+ GSList *next_node;
+
+ request = node->data;
+ next_node = node->next;
+
+ if (request->type == ACT_USER_MANAGER_FETCH_USER_FROM_ID_REQUEST) {
+ if (request->uid == id)
+ return request->user;
+ }
+
+ node = next_node;
+ }
+
+ return NULL;
+}
+
/**
* act_user_manager_get_user_by_id:
* @manager: the manager to query.
@@ -2029,6 +2089,14 @@ act_user_manager_get_user_by_id (ActUserManager *manager,
object_path = g_strdup_printf ("/org/freedesktop/Accounts/User%lu", (gulong) id);
user = g_hash_table_lookup (priv->users_by_object_path, object_path);
+ if (user == NULL) {
+ user = check_fetch_user_requests_for_user_with_id (manager, id);
+
+ if (user != NULL) {
+ g_debug ("ActUserManager: User with UID %d fetched more than once before it loaded", (int) id);
+ }
+ }
+
if (user != NULL) {
return user;
} else {