Blame SOURCES/Use-a-hash-table-for-MEMORY-ccache-resolution.patch

749169
From 6e29836f794abdd91aa03d334b72b7a7f4800e92 Mon Sep 17 00:00:00 2001
d7027e
From: Greg Hudson <ghudson@mit.edu>
d7027e
Date: Sat, 4 Aug 2018 23:55:18 -0400
d7027e
Subject: [PATCH] Use a hash table for MEMORY ccache resolution
d7027e
d7027e
In cc_memory.c, replace the linked list of caches with a hash table,
d7027e
for better performance with large numbers of memory caches.
d7027e
d7027e
ticket: 8722 (new)
d7027e
(cherry picked from commit 088ba228acce4fd55bbb7c30122fe2703b8beeb8)
d7027e
---
d7027e
 src/lib/krb5/ccache/cc_memory.c | 77 +++++++++++++++------------------
d7027e
 1 file changed, 34 insertions(+), 43 deletions(-)
d7027e
d7027e
diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c
d7027e
index cfd5c6389..114ef6913 100644
d7027e
--- a/src/lib/krb5/ccache/cc_memory.c
d7027e
+++ b/src/lib/krb5/ccache/cc_memory.c
d7027e
@@ -26,6 +26,7 @@
d7027e
 
d7027e
 #include "cc-int.h"
d7027e
 #include "../krb/int-proto.h"
d7027e
+#include "k5-hashtab.h"
d7027e
 #include <errno.h>
d7027e
 
d7027e
 static krb5_error_code KRB5_CALLCONV krb5_mcc_close
d7027e
@@ -118,12 +119,6 @@ typedef struct _krb5_mcc_data {
d7027e
     int generation;             /* Incremented at each initialize */
d7027e
 } krb5_mcc_data;
d7027e
 
d7027e
-/* List of memory caches.  */
d7027e
-typedef struct krb5_mcc_list_node {
d7027e
-    struct krb5_mcc_list_node *next;
d7027e
-    krb5_mcc_data *cache;
d7027e
-} krb5_mcc_list_node;
d7027e
-
d7027e
 /* Iterator over credentials in a memory cache. */
d7027e
 struct mcc_cursor {
d7027e
     int generation;
d7027e
@@ -136,10 +131,27 @@ struct krb5_mcc_ptcursor_data {
d7027e
 };
d7027e
 
d7027e
 k5_cc_mutex krb5int_mcc_mutex = K5_CC_MUTEX_PARTIAL_INITIALIZER;
d7027e
-static krb5_mcc_list_node *mcc_head = 0;
d7027e
+static struct k5_hashtab *mcc_hashtab = NULL;
d7027e
 
d7027e
 static void update_mcc_change_time(krb5_mcc_data *);
d7027e
 
d7027e
+/* Ensure that mcc_hashtab is initialized.  Call with krb5int_mcc_mutex
d7027e
+ * locked. */
d7027e
+static krb5_error_code
d7027e
+init_table(krb5_context context)
d7027e
+{
d7027e
+    krb5_error_code ret;
d7027e
+    uint8_t seed[K5_HASH_SEED_LEN];
d7027e
+    krb5_data d = make_data(seed, sizeof(seed));
d7027e
+
d7027e
+    if (mcc_hashtab != NULL)
d7027e
+        return 0;
d7027e
+    ret = krb5_c_random_make_octets(context, &d);
d7027e
+    if (ret)
d7027e
+        return ret;
d7027e
+    return k5_hashtab_create(seed, 64, &mcc_hashtab);
d7027e
+}
d7027e
+
d7027e
 /* Remove creds from d, invalidate any existing cursors, and unset the client
d7027e
  * principal.  The caller is responsible for locking. */
d7027e
 static void
d7027e
@@ -230,21 +242,13 @@ krb5_mcc_close(krb5_context context, krb5_ccache id)
d7027e
 krb5_error_code KRB5_CALLCONV
d7027e
 krb5_mcc_destroy(krb5_context context, krb5_ccache id)
d7027e
 {
d7027e
-    krb5_mcc_list_node **curr, *node;
d7027e
     krb5_mcc_data *d = id->data;
d7027e
     krb5_boolean removed_from_table = FALSE;
d7027e
 
d7027e
+    /* Remove this node from the table if it is still present. */
d7027e
     k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
d7027e
-
d7027e
-    for (curr = &mcc_head; *curr; curr = &(*curr)->next) {
d7027e
-        if ((*curr)->cache == d) {
d7027e
-            node = *curr;
d7027e
-            *curr = node->next;
d7027e
-            free(node);
d7027e
-            removed_from_table = TRUE;
d7027e
-            break;
d7027e
-        }
d7027e
-    }
d7027e
+    if (k5_hashtab_remove(mcc_hashtab, d->name, strlen(d->name)))
d7027e
+        removed_from_table = TRUE;
d7027e
     k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
d7027e
 
d7027e
     /* Empty the cache and remove the reference for the table slot.  There will
d7027e
@@ -289,16 +293,13 @@ krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
d7027e
 {
d7027e
     krb5_os_context os_ctx = &context->os_context;
d7027e
     krb5_ccache lid;
d7027e
-    krb5_mcc_list_node *ptr;
d7027e
     krb5_error_code err;
d7027e
     krb5_mcc_data *d;
d7027e
 
d7027e
     k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
d7027e
-    for (ptr = mcc_head; ptr; ptr=ptr->next)
d7027e
-        if (!strcmp(ptr->cache->name, residual))
d7027e
-            break;
d7027e
-    if (ptr != NULL) {
d7027e
-        d = ptr->cache;
d7027e
+    init_table(context);
d7027e
+    d = k5_hashtab_get(mcc_hashtab, residual, strlen(residual));
d7027e
+    if (d != NULL) {
d7027e
         k5_cc_mutex_lock(context, &d->lock);
d7027e
         d->refcount++;
d7027e
         k5_cc_mutex_unlock(context, &d->lock);
d7027e
@@ -438,18 +439,17 @@ krb5_mcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *curso
d7027e
 }
d7027e
 
d7027e
 /*
d7027e
- * Utility routine: Creates the back-end data for a memory cache, and threads
d7027e
- * it into the global linked list.  Give the new object two references, one for
d7027e
- * the table slot and one for the caller's handle.
d7027e
+ * Utility routine: Creates the back-end data for a memory cache, and adds it
d7027e
+ * to the global table.  Give the new object two references, one for the table
d7027e
+ * slot and one for the caller's handle.
d7027e
  *
d7027e
- * Call with the global list lock held.
d7027e
+ * Call with the global table lock held.
d7027e
  */
d7027e
 static krb5_error_code
d7027e
 new_mcc_data (const char *name, krb5_mcc_data **dataptr)
d7027e
 {
d7027e
     krb5_error_code err;
d7027e
     krb5_mcc_data *d;
d7027e
-    krb5_mcc_list_node *n;
d7027e
 
d7027e
     d = malloc(sizeof(krb5_mcc_data));
d7027e
     if (d == NULL)
d7027e
@@ -476,18 +476,13 @@ new_mcc_data (const char *name, krb5_mcc_data **dataptr)
d7027e
     d->generation = 0;
d7027e
     update_mcc_change_time(d);
d7027e
 
d7027e
-    n = malloc(sizeof(krb5_mcc_list_node));
d7027e
-    if (n == NULL) {
d7027e
+    if (k5_hashtab_add(mcc_hashtab, d->name, strlen(d->name), d) != 0) {
d7027e
         free(d->name);
d7027e
         k5_cc_mutex_destroy(&d->lock);
d7027e
         free(d);
d7027e
         return KRB5_CC_NOMEM;
d7027e
     }
d7027e
 
d7027e
-    n->cache = d;
d7027e
-    n->next = mcc_head;
d7027e
-    mcc_head = n;
d7027e
-
d7027e
     *dataptr = d;
d7027e
     return 0;
d7027e
 }
d7027e
@@ -522,11 +517,10 @@ krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
d7027e
     lid->ops = &krb5_mcc_ops;
d7027e
 
d7027e
     k5_cc_mutex_lock(context, &krb5int_mcc_mutex);
d7027e
+    init_table(context);
d7027e
 
d7027e
     /* Check for uniqueness with mutex locked to avoid race conditions */
d7027e
     while (1) {
d7027e
-        krb5_mcc_list_node *ptr;
d7027e
-
d7027e
         err = krb5int_random_string (context, uniquename, sizeof (uniquename));
d7027e
         if (err) {
d7027e
             k5_cc_mutex_unlock(context, &krb5int_mcc_mutex);
d7027e
@@ -534,12 +528,9 @@ krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
d7027e
             return err;
d7027e
         }
d7027e
 
d7027e
-        for (ptr = mcc_head; ptr; ptr=ptr->next) {
d7027e
-            if (!strcmp(ptr->cache->name, uniquename)) {
d7027e
-                break;  /* got a match, loop again */
d7027e
-            }
d7027e
-        }
d7027e
-        if (!ptr) break; /* got to the end without finding a match */
d7027e
+        if (k5_hashtab_get(mcc_hashtab, uniquename,
d7027e
+                           strlen(uniquename)) == NULL)
d7027e
+            break;
d7027e
     }
d7027e
 
d7027e
     err = new_mcc_data(uniquename, &d);