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 *);