]> granicus.if.org Git - postgresql/commitdiff
Fix removal of files in pgstats directories
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 19 Aug 2013 21:48:17 +0000 (17:48 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 19 Aug 2013 21:52:52 +0000 (17:52 -0400)
Instead of deleting all files in stats_temp_directory and the permanent
directory on a crash, only remove those files that match the pattern of
files we actually write in them, to avoid possibly clobbering existing
unrelated contents of the temporary directory.  Per complaint from Jeff
Janes, and subsequent discussion, starting at message
CAMkU=1z9+7RsDODnT4=cDFBRBp8wYQbd_qsLcMtKEf-oFwuOdQ@mail.gmail.com

Also, fix a bug in the same routine to avoid removing files from the
permanent directory twice (instead of once from that directory and then
from the temporary directory), also per report from Jeff Janes, in
message
CAMkU=1wbk947=-pAosDMX5VC+sQw9W4ttq6RM9rXu=MjNeEQKA@mail.gmail.com

src/backend/postmaster/pgstat.c

index dac5bca78aab80dc306fcd97da1864357576ef6b..f42f1839c229c4be14d69c5de6f1cf0c64a3f59d 100644 (file)
@@ -562,15 +562,37 @@ pgstat_reset_remove_files(const char *directory)
        struct dirent *entry;
        char            fname[MAXPGPATH];
 
-       dir = AllocateDir(pgstat_stat_directory);
-       while ((entry = ReadDir(dir, pgstat_stat_directory)) != NULL)
+       dir = AllocateDir(directory);
+       while ((entry = ReadDir(dir, directory)) != NULL)
        {
-               if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+               int             nitems;
+               Oid             tmp_oid;
+               char    tmp_type[8];
+               char    tmp_rest[2];
+
+               if (strncmp(entry->d_name, ".", 2) == 0 ||
+                       strncmp(entry->d_name, "..", 3) == 0)
                        continue;
 
-               /* XXX should we try to ignore files other than the ones we write? */
+               /*
+                * Skip directory entries that don't match the file names we write.
+                * See get_dbstat_filename for the database-specific pattern.
+                */
+               nitems = sscanf(entry->d_name, "db_%u.%5s%1s",
+                                               &tmp_oid, tmp_type, tmp_rest);
+               if (nitems != 2)
+               {
+                       nitems = sscanf(entry->d_name, "global.%5s%1s",
+                                                       tmp_type, tmp_rest);
+                       if (nitems != 1)
+                               continue;
+               }
+
+               if (strncmp(tmp_type, "tmp", 4) != 0 &&
+                       strncmp(tmp_type, "stat", 5) != 0)
+                       continue;
 
-               snprintf(fname, MAXPGPATH, "%s/%s", pgstat_stat_directory,
+               snprintf(fname, MAXPGPATH, "%s/%s", directory,
                                 entry->d_name);
                unlink(fname);
        }
@@ -3627,6 +3649,7 @@ get_dbstat_filename(bool permanent, bool tempname, Oid databaseid,
 {
        int                     printed;
 
+       /* NB -- pgstat_reset_remove_files knows about the pattern this uses */
        printed = snprintf(filename, len, "%s/db_%u.%s",
                                           permanent ? PGSTAT_STAT_PERMANENT_DIRECTORY :
                                           pgstat_stat_directory,