From: Justin Pryzby Date: Wed, 4 Mar 2020 17:38:03 -0600 Subject: [PATCH v6 3/4] Convert data structure to use a list --- src/backend/utils/adt/genfile.c | 78 +++++++++++++++++---------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index c5148f547b..bc473e79ef 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -37,8 +37,9 @@ typedef struct { - char *location; - DIR *dirdesc; + /* List of opened dirs */ + List *location; + List *dirdesc; bool include_dot_dirs; /* Used in ls_dir_files: */ @@ -474,10 +475,9 @@ pg_ls_dir(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = palloc(sizeof(directory_fctx)); - fctx->location = convert_and_check_filename(PG_GETARG_TEXT_PP(0)); - + fctx->location = lappend(NIL, convert_and_check_filename(PG_GETARG_TEXT_PP(0))); + fctx->dirdesc = lappend(NIL, AllocateDir(linitial(fctx->location))); fctx->include_dot_dirs = include_dot_dirs; - fctx->dirdesc = AllocateDir(fctx->location); if (!fctx->dirdesc) { @@ -490,7 +490,7 @@ pg_ls_dir(PG_FUNCTION_ARGS) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", - fctx->location))); + (char*)linitial(fctx->location)))); } funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); @@ -499,7 +499,7 @@ pg_ls_dir(PG_FUNCTION_ARGS) funcctx = SRF_PERCALL_SETUP(); fctx = (directory_fctx *) funcctx->user_fctx; - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + while ((de = ReadDir(linitial(fctx->dirdesc), linitial(fctx->location))) != NULL) { if (!fctx->include_dot_dirs && (strcmp(de->d_name, ".") == 0 || @@ -509,7 +509,9 @@ pg_ls_dir(PG_FUNCTION_ARGS) SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(de->d_name)); } - FreeDir(fctx->dirdesc); + FreeDir(linitial(fctx->dirdesc)); + list_free(fctx->dirdesc); + list_free_deep(fctx->location); SRF_RETURN_DONE(funcctx); } @@ -528,20 +530,25 @@ pg_ls_dir_1arg(PG_FUNCTION_ARGS) } /* - * Populate fctx with list of pathnames and stat structues. Generate a full - * list of the stat structures all at once - the alternative is to re-stat - * everything later on, which then requires somehow handling cases like the 2nd - * stat fails, or the 2nd stat returns a dir which didn't exist at the time we - * originally looked, or existed but wasn't a dir. stat()ing everything all at - * once gets as close as we can to a consistent view of the filesystem, from - * which files might be removed or renamed or reordered. + * Populate fctx with list of pathnames and stat structues. + * + * Generate a full list of the stat structures all at once. That gets as close + * as we can to a consistent view of the filesystem, from which files might be + * removed or renamed or reordered. + * + * recurse is the recursion level into a stack of dirs, or -1 to not decend + * into directories. */ static void -populate_paths(directory_fctx *fctx, bool recurse) +populate_paths(directory_fctx *fctx, int recurse) { struct dirent *de; struct stat attrib; - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + + DIR *dirdesc = llast(fctx->dirdesc); + char *location = llast(fctx->location); + + while ((de = ReadDir(dirdesc, location)) != NULL) { char path[MAXPGPATH]; @@ -550,28 +557,23 @@ populate_paths(directory_fctx *fctx, bool recurse) continue; /* Get the file info */ - snprintf(path, sizeof(path), "%s/%s", fctx->location, de->d_name); + snprintf(path, sizeof(path), "%s/%s", location, de->d_name); if (stat(path, &attrib) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat file \"%s\": %m", path))); /* Ignore anything but regular files, or dirs, if requested */ - if (S_ISDIR(attrib.st_mode)) + if (recurse == -1) + ; /* Do nothing, fall through */ + else if (S_ISDIR(attrib.st_mode)) { - /* Save current dir while recursing */ - directory_fctx oldfctx = *fctx; - - fctx->location = path; - fctx->dirdesc = AllocateDir(path); - - if (recurse) - populate_paths(fctx, recurse); - - /* Restore previous dir */ - FreeDir(fctx->dirdesc); - fctx->dirdesc = oldfctx.dirdesc; - fctx->location = oldfctx.location; + /* Reallocate location and dirdesc whenever recursing */ + fctx->location = lappend(fctx->location, path); + fctx->dirdesc = lappend(fctx->dirdesc, AllocateDir(path)); + populate_paths(fctx, 1+recurse); + FreeDir(llast(fctx->dirdesc)); + list_delete_last(fctx->dirdesc); } else if (!S_ISREG(attrib.st_mode)) continue; @@ -619,8 +621,8 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok, bool funcctx->tuple_desc = BlessTupleDesc(tupdesc); - fctx->location = pstrdup(dir); - fctx->dirdesc = AllocateDir(fctx->location); + fctx->location = lappend(NIL, pstrdup(dir)); + fctx->dirdesc = lappend(NIL, AllocateDir(dir)); fctx->npaths = 0; fctx->path = palloc(sizeof(*fctx->path)); fctx->stat = palloc(sizeof(*fctx->stat)); @@ -636,10 +638,10 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok, bool ereport(ERROR, (errcode_for_file_access(), errmsg("could not open directory \"%s\": %m", - fctx->location))); + dir))); } - populate_paths(fctx, dir_ok); + populate_paths(fctx, dir_ok ? 0 : -1); funcctx->max_calls = fctx->npaths; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); @@ -674,7 +676,9 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok, bool pfree(fctx->path); pfree(fctx->stat); - FreeDir(fctx->dirdesc); + FreeDir(linitial(fctx->dirdesc)); + list_free(fctx->dirdesc); + list_free(fctx->location); SRF_RETURN_DONE(funcctx); } -- 2.17.0 --V88s5gaDVPzZ0KCq Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6-0004-Read-each-dir-incrementally-during-each-SRF-call.patch"