From 450116f38c45498f1b0dec42b3c029c0e7057a36 Mon Sep 17 00:00:00 2001 From: tradke Date: Fri, 21 Dec 2001 17:02:46 +0000 Subject: Changed recovery code to use opendir(3), readdir(3), closedir(3) instead of non-POSIX routine scandir(3). This also gets rid of a nasty compiler warning (scandir isn't standardized). git-svn-id: http://svn.cactuscode.org/arrangements/CactusBase/IOUtil/trunk@143 b32723a9-ab3a-4a60-88e2-2e5d99d7c17a --- src/CheckpointRecovery.c | 234 +++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 119 deletions(-) diff --git a/src/CheckpointRecovery.c b/src/CheckpointRecovery.c index 71e98c1..a2858ae 100644 --- a/src/CheckpointRecovery.c +++ b/src/CheckpointRecovery.c @@ -19,11 +19,7 @@ #include #include #include - -#ifdef HAVE_SCANDIR -#include #include -#endif static const char *rcsid = "$Header$"; CCTK_FILEVERSION(CactusBase_IOUtil_CheckpointRecovery_c) @@ -44,23 +40,22 @@ static cHandledData *RecoverFunctions = NULL; static int num_functions = 0; static int checkpoint_file_exists = 0; -#ifdef HAVE_SCANDIR -/* prefix and extension of potential recovery files */ -static char *recoverFilePrefix; -static const char *recoverFileExtension; -#endif + +/******************************************************************** + ******************** Internal Typedefs ************************ + ********************************************************************/ +typedef struct +{ + char *basename; + int iteration; +} filelist_t; /******************************************************************** ******************** Internal Routines ************************ ********************************************************************/ static void SetInputFlag (int vindex, const char *optstring, void *arg); - -#ifdef HAVE_SCANDIR -/* prototypes of the select and sort routine used by scandir(3) */ -static int IOUtil_RecoverFileSelect (struct dirent *entry); -static int IOUtil_RecoverFileCompare (struct dirent **a, struct dirent **b); -#endif +static int CompareFiles (const void *a, const void *b); /************************************************************************ @@ -508,7 +503,8 @@ void IOUtil_RecoverIDFromDatafiles (cGH *GH) 0 if in "autoprobe" mode and no cp files were found, or
+1 if parameter recovery was successful for some cp file,
-1 if in "auto" mode and no checkpoint files were found, - or if parameter recovery failed for some cp file + or if parameter recovery failed for some cp file,
+ -2 if in "auto*" mode and recovery dir doesn't exist @endreturndesc @@*/ int IOUtil_RecoverParameters (int (*recoverFn) (cGH *GH, @@ -517,20 +513,17 @@ int IOUtil_RecoverParameters (int (*recoverFn) (cGH *GH, const char *fileExtension, const char *fileType) { - int retval; /* the return value */ - cGH *dummyGH = NULL; /* there's no GH yet but the callback routine - expects a GH pointer */ -#ifdef HAVE_SCANDIR - int i, nRecoverFiles; - struct dirent **recoverFileList = NULL; -#endif + int len, extension_len, recover_file_len, retval; + unsigned int num_files; + DIR *dir; + const char *p; + struct dirent *file; + filelist_t *filelist, *tmp; DECLARE_CCTK_PARAMETERS if (CCTK_Equals (recover, "auto") || CCTK_Equals (recover, "autoprobe")) { - retval = CCTK_Equals (recover, "auto") ? -1 : 0; -#ifdef HAVE_SCANDIR if (verbose) { CCTK_VInfo (CCTK_THORNSTRING, "Searching for %s checkpoint files " @@ -538,54 +531,115 @@ int IOUtil_RecoverParameters (int (*recoverFn) (cGH *GH, fileType, recover_file, recovery_dir); } - /* set the file prefix and extension for selecting valid checkpoint files */ - /* we have to pass it via global variables to the select() routine - because it doesn't receive user-supplied arguments */ - recoverFilePrefix = (char *) malloc (strlen (recover_file) + 5); - sprintf (recoverFilePrefix, "%s.it_", recover_file); - recoverFileExtension = fileExtension; + dir = opendir (recovery_dir); + if (! dir) + { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "Recovery directory '%s' doesn't exist", recovery_dir); + return (-2); + } /* get the list of potential recovery files */ - nRecoverFiles = scandir (recovery_dir, &recoverFileList, - IOUtil_RecoverFileSelect, - IOUtil_RecoverFileCompare); + extension_len = strlen (fileExtension); + recover_file_len = strlen (recover_file); + num_files = 0; + filelist = NULL; - if (nRecoverFiles <= 0) + while ((file = readdir (dir)) != NULL) { - CCTK_VWarn (retval ? 1 : 3, __LINE__, __FILE__, CCTK_THORNSTRING, - "No %s checkpoint files with basefilename '%s' found in " - "recovery directory '%s'", - fileType, recover_file, recovery_dir); + /* first check the file prefix */ + if (strncmp (file->d_name, recover_file, recover_file_len) || + strncmp (file->d_name + recover_file_len, ".it_", 4)) + { + continue; + } + + /* now check if there is an iteration number following the file prefix */ + for (p = file->d_name + recover_file_len + 4; *p && *p != '.'; p++) + { + if (! isdigit ((int) *p)) + { + break; + } + } + if (*p != '.') + { + continue; + } + + /* check for a '.file_' suffix for chunked output + We only select the chunked output file of processor 0 in that case. */ + if (! strncmp (p, ".file_", 6) && strncmp (p, ".file_0", 7)) + { + continue; + } + + /* finally check the file type suffix */ + len = strlen (file->d_name); + if (len < extension_len || + strcmp (file->d_name + len - extension_len, fileExtension)) + { + continue; + } + + /* found a recovery file by that basename */ + if (num_files == 0) + { + tmp = (filelist_t *) malloc (sizeof (filelist_t)); + } + else + { + tmp = (filelist_t *) realloc (filelist, + (num_files+1) * sizeof (filelist_t)); + } + if (tmp == NULL) + { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "Failed to allocate memory for file list"); + continue; + } + filelist = tmp; + filelist[num_files].basename = strdup (file->d_name); + /* cut the filename after the iteration number field */ + filelist[num_files].basename[p - file->d_name] = 0; + filelist[num_files].iteration = atoi (file->d_name + recover_file_len+4); + + num_files++; } - else + closedir (dir); + + retval = CCTK_Equals (recover, "auto") ? -1 : 0; + if (num_files) { + /* sort the list according to their iteration numbers */ + qsort (filelist, num_files, sizeof (filelist_t), CompareFiles); + /* loop over all recovery files found and call the callback routine; skip all following files after the first successful recovery (when recoverFn() returned a positive value) */ - for (i = 0; i < nRecoverFiles; i++) + while (num_files--) { if (retval <= 0) { - retval = recoverFn (dummyGH, recoverFileList[i]->d_name, + retval = recoverFn (NULL, filelist[num_files].basename, CP_RECOVER_PARAMETERS); } - free (recoverFileList[i]); + free (filelist[num_files].basename); } - free (recoverFileList); + free (filelist); + } + else + { + CCTK_VWarn (retval ? 1 : 3, __LINE__, __FILE__, CCTK_THORNSTRING, + "No %s checkpoint files with basefilename '%s' found in " + "recovery directory '%s'", + fileType, recover_file, recovery_dir); } -#else - /* no scandir(3) ? give up ! */ - CCTK_WARN (0, "You cannot use 'IO::recover = \"auto\"' on " - "this architecture because it doesn't provide scandir(3) to " - "automatically look for checkpoint files.\n" - "Please use 'IO::recover = \"manual\"' instead !"); - -#endif } else { /* just call the recovery routine */ - retval = (*recoverFn) (dummyGH, recover_file, CP_RECOVER_PARAMETERS); + retval = (*recoverFn) (NULL, recover_file, CP_RECOVER_PARAMETERS); } if (retval < 0) @@ -798,72 +852,6 @@ int IOUtil_RestartFromRecovery (const cGH *GH) /***************************** local routines ******************************/ -#ifdef HAVE_SCANDIR - -/* function to be called by scandir(3) to select potential recovery - files in the given recovery directory (see IOUtil_RecoverParameters()) */ -static int IOUtil_RecoverFileSelect (struct dirent *entry) -{ - char *p; - int len, prefixLen, extLen; - - - len = strlen (entry->d_name); - prefixLen = strlen (recoverFilePrefix); - - /* At first check for recoverFilePrefix in the beginning of the filename */ - if (strncmp (entry->d_name, recoverFilePrefix, prefixLen)) - { - return (0); - } - - /* Now check if there is an iteration number following the file prefix. */ - for (p = (char *) entry->d_name + prefixLen; *p && *p != '.'; p++) - { - if (! isdigit ((int) *p)) - { - return (0); - } - } - - /* Check for a '.file_' suffix for chunked output. - We only select the chunked output file of processor 0 in that case. */ - if (p - entry->d_name < len) - { - if (! strncmp (p, ".file_", 6) && strncmp (p, ".file_0", 7)) - { - return (0); - } - } - - /* Finally check the suffix */ - extLen = strlen (recoverFileExtension); - if (len < extLen || strcmp (entry->d_name+len-extLen, recoverFileExtension)) - { - return (0); - } - - /* Cut the file name after the iteration number field - because we only need the basefilename later on. */ - *p = 0; - - return (1); -} - - -/* function to be called by scandir(3) to sort the list of potential recovery - files by their iteration number (see IOUtil_RecoverParameters()) */ -static int IOUtil_RecoverFileCompare (struct dirent **a, struct dirent **b) -{ - int len = strlen (recoverFilePrefix); - - - /* note that this causes the file list to be sorted in descendent order */ - return (atoi ((*b)->d_name + len) - atoi ((*a)->d_name + len)); -} -#endif /* HAVE_SCANDIR */ - - /* callback for CCTK_TraverseString() to set the input flag for the given variable */ static void SetInputFlag (int vindex, const char *optstring, void *flags) @@ -877,3 +865,11 @@ static void SetInputFlag (int vindex, const char *optstring, void *flags) optstring); } } + + +/* callback for qsort() to sort the list of recovery files found */ +static int CompareFiles (const void *a, const void *b) +{ + return (((const filelist_t *) a)->iteration - + ((const filelist_t *) b)->iteration); +} -- cgit v1.2.3