ypldap currently packs all the user and group lines into contiguous blocks
of memory so it can move from one entry to the next by pointer arithmetic.
This doesn't make much sense because the entries are also in red black trees
(that's how it looks up the entry in the first place) and RB_NEXT() is not
slow.

The one piece of the tree flattening code that seems worth keeping is
strdup()ing the netid lines so they don't take 1kB per user.

ok?

Index: entries.c
===================================================================
RCS file: /cvs/src/usr.sbin/ypldap/entries.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 entries.c
--- entries.c   18 Jul 2023 13:06:33 -0000      1.6
+++ entries.c   20 Sep 2023 07:17:00 -0000
@@ -34,86 +34,6 @@
 #include <limits.h>
 
 #include "ypldap.h"
-#include "log.h"
-
-void
-flatten_entries(struct env *env)
-{
-       size_t           len;
-       char            *linep;
-       char            *endp;
-       char            *tmp;
-       struct userent  *ue;
-       struct groupent *ge;
-
-       log_debug("flattening trees");
-       /*
-        * This takes all the line pointers in RB elements and
-        * concatenates them in a single string, to be able to
-        * implement next element lookup without tree traversal.
-        *
-        * An extra octet is alloced to make space for an additional NUL.
-        */
-       if ((linep = calloc(1, env->sc_user_line_len + 1)) == NULL) {
-               /*
-                * XXX: try allocating a smaller chunk of memory
-                */
-               fatal("out of memory");
-       }
-       endp = linep;
-
-       RB_FOREACH(ue, user_name_tree, env->sc_user_names) {
-               /*
-                * we convert the first nul back to a column,
-                * copy the string and then convert it back to a nul.
-                */
-               ue->ue_line[strlen(ue->ue_line)] = ':';
-               log_debug("pushing line: %s", ue->ue_line);
-               len = strlen(ue->ue_line) + 1;
-               memcpy(endp, ue->ue_line, len);
-               endp[strcspn(endp, ":")] = '\0';
-               free(ue->ue_line);
-               ue->ue_line = endp;
-               endp += len;
-
-               /*
-                * To save memory strdup(3) the netid_line which originally used
-                * LINE_WIDTH bytes
-                */
-               tmp = ue->ue_netid_line;
-               ue->ue_netid_line = strdup(tmp);
-               if (ue->ue_netid_line == NULL) {
-                       fatal("out of memory");
-               }
-               free(tmp);
-       }
-       env->sc_user_lines = linep;
-       log_debug("done pushing users");
-
-       if ((linep = calloc(1, env->sc_group_line_len + 1)) == NULL) {
-               /*
-                * XXX: try allocating a smaller chunk of memory
-                */
-               fatal("out of memory");
-       }
-       endp = linep;
-       RB_FOREACH(ge, group_name_tree, env->sc_group_names) {
-               /*
-                * we convert the first nul back to a column,
-                * copy the string and then convert it back to a nul.
-                */
-               ge->ge_line[strlen(ge->ge_line)] = ':';
-               log_debug("pushing line: %s", ge->ge_line);
-               len = strlen(ge->ge_line) + 1;
-               memcpy(endp, ge->ge_line, len);
-               endp[strcspn(endp, ":")] = '\0';
-               free(ge->ge_line);
-               ge->ge_line = endp;
-               endp += len;
-       }
-       env->sc_group_lines = linep;
-       log_debug("done pushing groups");
-}
 
 int
 userent_name_cmp(struct userent *ue1, struct userent *ue2)
Index: yp.c
===================================================================
RCS file: /cvs/src/usr.sbin/ypldap/yp.c,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 yp.c
--- yp.c        18 Jul 2023 13:06:33 -0000      1.22
+++ yp.c        20 Sep 2023 07:17:00 -0000
@@ -557,21 +557,25 @@ ypresp_key_val *
 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
 {
        static struct ypresp_key_val    res;
+       struct userent                  *ue;
+       struct groupent                 *ge;
 
        if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
                return (&res);
 
        if (strcmp(arg->map, "passwd.byname") == 0 ||
            strcmp(arg->map, "master.passwd.byname") == 0) {
-               if (env->sc_user_lines == NULL)
+               ue = RB_MIN(user_name_tree, env->sc_user_names);
+               if (ue == NULL)
                        return (NULL);
 
-               yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
+               yp_make_keyval(&res, ue->ue_line, ue->ue_line);
        } else if (strcmp(arg->map, "group.byname") == 0) {
-               if (env->sc_group_lines == NULL)
+               ge = RB_MIN(group_name_tree, env->sc_group_names);
+               if (ge == NULL)
                        return (NULL);
 
-               yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
+               yp_make_keyval(&res, ge->ge_line, ge->ge_line);
        } else {
                log_debug("unknown map %s", arg->map);
                res.stat = YP_NOMAP;
@@ -587,7 +591,6 @@ ypproc_next_2_svc(ypreq_key *arg, struct
        struct userent                  *ue;
        struct groupent                  gkey;
        struct groupent                 *ge;
-       char                            *line;
        static struct ypresp_key_val     res;
        char                             key[YPMAXRECORD+1];
 
@@ -605,9 +608,13 @@ ypproc_next_2_svc(ypreq_key *arg, struct
                        res.stat = YP_NOKEY;
                        return (&res);
                }
-               line = ue->ue_line + (strlen(ue->ue_line) + 1);
-               line = line + (strlen(line) + 1);
-               yp_make_keyval(&res, line, line);
+               if ((ue = RB_NEXT(user_name_tree, env->sc_user_names,
+                   ue)) == NULL) {
+                       res.stat = YP_NOKEY;
+                       return (&res);
+               }
+
+               yp_make_keyval(&res, ue->ue_line, ue->ue_line);
                return (&res);
 
 
@@ -622,10 +629,13 @@ ypproc_next_2_svc(ypreq_key *arg, struct
                        res.stat = YP_NOKEY;
                        return (&res);
                }
+               if ((ge = RB_NEXT(group_name_tree, env->sc_group_names,
+                   ge)) == NULL) {
+                       res.stat = YP_NOKEY;
+                       return (&res);
+               }
 
-               line = ge->ge_line + (strlen(ge->ge_line) + 1);
-               line = line + (strlen(line) + 1);
-               yp_make_keyval(&res, line, line);
+               yp_make_keyval(&res, ge->ge_line, ge->ge_line);
                return (&res);
        } else {
                log_debug("unknown map %s", arg->map);
Index: ypldap.c
===================================================================
RCS file: /cvs/src/usr.sbin/ypldap/ypldap.c,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 ypldap.c
--- ypldap.c    31 Mar 2023 03:38:26 -0000      1.24
+++ ypldap.c    20 Sep 2023 07:17:00 -0000
@@ -129,8 +129,6 @@ main_start_update(struct env *env)
        env->update_trashed = 0;
 
        log_debug("starting directory update");
-       env->sc_user_line_len = 0;
-       env->sc_group_line_len = 0;
        if ((env->sc_user_names_t = calloc(1,
            sizeof(*env->sc_user_names_t))) == NULL ||
            (env->sc_group_names_t = calloc(1,
@@ -182,6 +180,7 @@ main_create_user_groups(struct env *env)
        gid_t                    pw_gid;
        char                    *bp, *cp;
        char                    *p;
+       char                    *tmp;
        const char              *errstr = NULL;
        size_t                   len;
 
@@ -268,6 +267,18 @@ main_create_user_groups(struct env *env)
                }
        }
 
+       /*
+        * now reallocate the netid lines to save space
+        */
+       RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) {
+               tmp = ue->ue_netid_line;
+               ue->ue_netid_line = strdup(tmp);
+               if (ue->ue_netid_line == NULL) {
+                       fatal("out of memory");
+               }
+               free(tmp);
+       }
+
        return (0);
 }
 
@@ -287,55 +298,31 @@ main_end_update(struct env *env)
                return;
        }
 
-       if (env->sc_user_names == NULL) {
-               env->sc_user_names = env->sc_user_names_t;
-               env->sc_user_lines = NULL;
-               env->sc_user_names_t = NULL;
-
-               env->sc_group_names = env->sc_group_names_t;
-               env->sc_group_lines = NULL;
-               env->sc_group_names_t = NULL;
-
-               flatten_entries(env);
-               goto make_uids;
-       }
-
-       /*
-        * clean previous tree.
-        */
-       while ((ue = RB_ROOT(env->sc_user_names)) != NULL) {
-               RB_REMOVE(user_name_tree, env->sc_user_names,
-                   ue);
-               free(ue->ue_netid_line);
-               free(ue);
+       if (env->sc_user_names != NULL) {
+               while ((ue = RB_ROOT(env->sc_user_names)) != NULL) {
+                       RB_REMOVE(user_name_tree, env->sc_user_names,
+                           ue);
+                       free(ue->ue_line);
+                       free(ue->ue_netid_line);
+                       free(ue);
+               }
+               free(env->sc_user_names);
        }
-       free(env->sc_user_names);
-       free(env->sc_user_lines);
-
        env->sc_user_names = env->sc_user_names_t;
-       env->sc_user_lines = NULL;
        env->sc_user_names_t = NULL;
 
-       while ((ge = RB_ROOT(env->sc_group_names)) != NULL) {
-               RB_REMOVE(group_name_tree,
-                   env->sc_group_names, ge);
-               free(ge);
+       if (env->sc_group_names != NULL) {
+               while ((ge = RB_ROOT(env->sc_group_names)) != NULL) {
+                       RB_REMOVE(group_name_tree,
+                           env->sc_group_names, ge);
+                       free(ge->ge_line);
+                       free(ge);
+               }
+               free(env->sc_group_names);
        }
-       free(env->sc_group_names);
-       free(env->sc_group_lines);
-
        env->sc_group_names = env->sc_group_names_t;
-       env->sc_group_lines = NULL;
        env->sc_group_names_t = NULL;
 
-
-       flatten_entries(env);
-
-       /*
-        * trees are flat now. build up uid, gid and netid trees.
-        */
-
-make_uids:
        RB_INIT(&env->sc_user_uids);
        RB_INIT(&env->sc_group_gids);
        RB_FOREACH(ue, user_name_tree, env->sc_user_names)
@@ -344,7 +331,6 @@ make_uids:
        RB_FOREACH(ge, group_name_tree, env->sc_group_names)
                RB_INSERT(group_gid_tree,
                    &env->sc_group_gids, ge);
-
 }
 
 void
@@ -387,7 +373,6 @@ main_dispatch_client(int fd, short event
                        break;
                case IMSG_PW_ENTRY: {
                        struct userent  *ue;
-                       size_t           len;
 
                        if (env->update_trashed)
                                break;
@@ -401,19 +386,16 @@ main_dispatch_client(int fd, short event
                                fatal("out of memory");
                        }
                        ue->ue_uid = ir.ir_key.ik_uid;
-                       len = strlen(ue->ue_line) + 1;
                        ue->ue_line[strcspn(ue->ue_line, ":")] = '\0';
                        if (RB_INSERT(user_name_tree, env->sc_user_names_t,
                            ue) != NULL) { /* dup */
                                free(ue->ue_line);
                                free(ue);
-                       } else
-                               env->sc_user_line_len += len;
+                       }
                        break;
                }
                case IMSG_GRP_ENTRY: {
                        struct groupent *ge;
-                       size_t           len;
 
                        if (env->update_trashed)
                                break;
@@ -427,14 +409,12 @@ main_dispatch_client(int fd, short event
                                fatal("out of memory");
                        }
                        ge->ge_gid = ir.ir_key.ik_gid;
-                       len = strlen(ge->ge_line) + 1;
                        ge->ge_line[strcspn(ge->ge_line, ":")] = '\0';
                        if (RB_INSERT(group_name_tree, env->sc_group_names_t,
                            ge) != NULL) { /* dup */
                                free(ge->ge_line);
                                free(ge);
-                       } else
-                               env->sc_group_line_len += len;
+                       }
                        break;
                }
                case IMSG_TRASH_UPDATE:
Index: ypldap.h
===================================================================
RCS file: /cvs/src/usr.sbin/ypldap/ypldap.h,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 ypldap.h
--- ypldap.h    18 Jul 2023 13:06:33 -0000      1.24
+++ ypldap.h    20 Sep 2023 07:17:00 -0000
@@ -183,10 +184,6 @@ struct env {
        RB_HEAD(group_gid_tree,groupent) sc_group_gids;
        struct user_name_tree            *sc_user_names_t;
        struct group_name_tree           *sc_group_names_t;
-       size_t                           sc_user_line_len;
-       size_t                           sc_group_line_len;
-       char                            *sc_user_lines;
-       char                            *sc_group_lines;
 
        struct yp_data                  *sc_yp;
 
@@ -207,7 +204,6 @@ int          imsg_compose_event(struct imsgev 
                    pid_t, int, void *, u_int16_t);
 
 /* entries.c */
-void            flatten_entries(struct env *);
 int             userent_name_cmp(struct userent *, struct userent *);
 int             userent_uid_cmp(struct userent *, struct userent *);
 int             groupent_name_cmp(struct groupent *, struct groupent *);

Reply via email to