Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit54e72b6

Browse files
committed
Refactor rmtree() to use get_dirent_type().
Switch to get_dirent_type() instead of lstat() while traversing adirectory tree, to see if that fixes the intermittent ENOTEMPTY failuresseen in recent pg_upgrade tests, on Windows CI. While refactoring, alsouse AllocateDir() instead of opendir() in the backend, which knows howto handle descriptor pressure.Our CI system currently uses Windows Server 2019, a version known not tohave POSIX unlink semantics enabled by default yet, unlike typicalWindows 10 and 11 systems. That might explain why we see this flappingon CI but (apparently) not in the build farm, though the frequency isquite low.The theory is that some directory entry must be in stateSTATUS_DELETE_PENDING, which lstat() would report as ENOENT, thoughunfortunately we don't know exactly why yet. With this change, rmtree()will not skip them, and try to unlink (again). Our unlink() wrappershould either wait a short time for them to go away when some otherprocess closes the handle, or log a message to tell us the path of theproblem file if not, so we can dig further.Discussion:https://postgr.es/m/20220919213217.ptqfdlcc5idk5xup%40awork3.anarazel.de
1 parent3bef56e commit54e72b6

File tree

1 file changed

+64
-56
lines changed

1 file changed

+64
-56
lines changed

‎src/common/rmtree.c

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,21 @@
2020
#include<unistd.h>
2121
#include<sys/stat.h>
2222

23+
#include"common/file_utils.h"
24+
2325
#ifndefFRONTEND
26+
#include"storage/fd.h"
2427
#definepg_log_warning(...) elog(WARNING, __VA_ARGS__)
28+
#defineLOG_LEVEL WARNING
29+
#defineOPENDIR(x) AllocateDir(x)
30+
#defineCLOSEDIR(x) FreeDir(x)
2531
#else
2632
#include"common/logging.h"
33+
#defineLOG_LEVEL PG_LOG_WARNING
34+
#defineOPENDIR(x) opendir(x)
35+
#defineCLOSEDIR(x) closedir(x)
2736
#endif
2837

29-
3038
/*
3139
*rmtree
3240
*
@@ -41,82 +49,82 @@
4149
bool
4250
rmtree(constchar*path,boolrmtopdir)
4351
{
44-
boolresult= true;
4552
charpathbuf[MAXPGPATH];
46-
char**filenames;
47-
char**filename;
48-
structstatstatbuf;
49-
50-
/*
51-
* we copy all the names out of the directory before we start modifying
52-
* it.
53-
*/
54-
filenames=pgfnames(path);
53+
DIR*dir;
54+
structdirent*de;
55+
boolresult= true;
56+
size_tdirnames_size=0;
57+
size_tdirnames_capacity=8;
58+
char**dirnames=palloc(sizeof(char*)*dirnames_capacity);
5559

56-
if (filenames==NULL)
60+
dir=OPENDIR(path);
61+
if (dir==NULL)
62+
{
63+
pg_log_warning("could not open directory \"%s\": %m",path);
5764
return false;
65+
}
5866

59-
/* now we have the names we can start removing things */
60-
for (filename=filenames;*filename;filename++)
67+
while (errno=0, (de=readdir(dir)))
6168
{
62-
snprintf(pathbuf,MAXPGPATH,"%s/%s",path,*filename);
63-
64-
/*
65-
* It's ok if the file is not there anymore; we were just about to
66-
* delete it anyway.
67-
*
68-
* This is not an academic possibility. One scenario where this
69-
* happens is when bgwriter has a pending unlink request for a file in
70-
* a database that's being dropped. In dropdb(), we call
71-
* ForgetDatabaseSyncRequests() to flush out any such pending unlink
72-
* requests, but because that's asynchronous, it's not guaranteed that
73-
* the bgwriter receives the message in time.
74-
*/
75-
if (lstat(pathbuf,&statbuf)!=0)
76-
{
77-
if (errno!=ENOENT)
78-
{
79-
pg_log_warning("could not stat file or directory \"%s\": %m",
80-
pathbuf);
81-
result= false;
82-
}
69+
if (strcmp(de->d_name,".")==0||
70+
strcmp(de->d_name,"..")==0)
8371
continue;
84-
}
85-
86-
if (S_ISDIR(statbuf.st_mode))
87-
{
88-
/* call ourselves recursively for a directory */
89-
if (!rmtree(pathbuf, true))
90-
{
91-
/* we already reported the error */
92-
result= false;
93-
}
94-
}
95-
else
72+
snprintf(pathbuf,sizeof(pathbuf),"%s/%s",path,de->d_name);
73+
switch (get_dirent_type(pathbuf,de, false,LOG_LEVEL))
9674
{
97-
if (unlink(pathbuf)!=0)
98-
{
99-
if (errno!=ENOENT)
75+
casePGFILETYPE_ERROR:
76+
/* already logged, press on */
77+
break;
78+
casePGFILETYPE_DIR:
79+
80+
/*
81+
* Defer recursion until after we've closed this directory, to
82+
* avoid using more than one file descriptor at a time.
83+
*/
84+
if (dirnames_size==dirnames_capacity)
85+
{
86+
dirnames=repalloc(dirnames,
87+
sizeof(char*)*dirnames_capacity*2);
88+
dirnames_capacity *=2;
89+
}
90+
dirnames[dirnames_size++]=pstrdup(pathbuf);
91+
break;
92+
default:
93+
if (unlink(pathbuf)!=0&&errno!=ENOENT)
10094
{
101-
pg_log_warning("could not remove file or directory \"%s\": %m",
102-
pathbuf);
95+
pg_log_warning("could not unlink file \"%s\": %m",pathbuf);
10396
result= false;
10497
}
105-
}
98+
break;
10699
}
107100
}
108101

102+
if (errno!=0)
103+
{
104+
pg_log_warning("could not read directory \"%s\": %m",path);
105+
result= false;
106+
}
107+
108+
CLOSEDIR(dir);
109+
110+
/* Now recurse into the subdirectories we found. */
111+
for (size_ti=0;i<dirnames_size;++i)
112+
{
113+
if (!rmtree(dirnames[i], true))
114+
result= false;
115+
pfree(dirnames[i]);
116+
}
117+
109118
if (rmtopdir)
110119
{
111120
if (rmdir(path)!=0)
112121
{
113-
pg_log_warning("could not remove file or directory \"%s\": %m",
114-
path);
122+
pg_log_warning("could not remove directory \"%s\": %m",path);
115123
result= false;
116124
}
117125
}
118126

119-
pgfnames_cleanup(filenames);
127+
pfree(dirnames);
120128

121129
returnresult;
122130
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp