Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1keA97-0004k0-43 for pgsql-hackers@arkaria.postgresql.org; Sun, 15 Nov 2020 05:00:13 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1keA94-0008Nw-NH for pgsql-hackers@arkaria.postgresql.org; Sun, 15 Nov 2020 05:00:10 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1keA94-0008Jo-Cb for pgsql-hackers@lists.postgresql.org; Sun, 15 Nov 2020 05:00:10 +0000 Received: from mail-lj1-x22c.google.com ([2a00:1450:4864:20::22c]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1keA8y-00087R-Hf for pgsql-hackers@postgresql.org; Sun, 15 Nov 2020 05:00:06 +0000 Received: by mail-lj1-x22c.google.com with SMTP id i17so14688029ljd.3 for ; Sat, 14 Nov 2020 21:00:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=9JXAjCLVY9wbbXzEtOHAps/nNRtH4XvVY4SwtmRNVEQ=; b=A08eS8KgJZYz9hfN2cnYtTp8DM9+n51fvXX8zZgjgAZXmzH+8H4O4x8GBaPKVBPXuj diDUfMzu5wfUUWWfNr3x/LxhGZBP1FaQfp7kZnv4HKwlpKHAmr3w4LEKwl13Q41a8j5c 2Wbu2UTfbjmLe7I4GVekogZjP14j7ECAvCOMmo6XeoJVGLZezTsHOdkmxyVY2yuVioMP IHmfJUi1I298eHKKPcn5lnnuJwl9n9ubFsRznPXJfU9nviwCosh6Y1YblyyiV1PmnD0Y Kah+Bou29pDYoIHKG1key0gpyTAKpzn/R1YiyRjCYRUVRQ0D1+NDLiMJBl3F/oDqmB20 qE6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=9JXAjCLVY9wbbXzEtOHAps/nNRtH4XvVY4SwtmRNVEQ=; b=G7kActkrlqLj9k8uE2itT+I2tKlxRInNLa93AuKQnbZUmJumEgUaQlN4ZxhmWhm7hp Cp6qSfejeQXM0697FtueRK8vI9Ej+xfAkJ7O/xJTv9dwshIzI9dRlj0sJeEp6Hw7VOkY NfNiJldPtF+y27YKjByp0vYKpIDOIVy0evM+QFv+Yt8OuDa7+eKDOq7Xt7GdG+Dj2g/H 3lHV58lrSuTS2v47/U7lzgMF/qghNj2MlFBz6tq8hnm7ygvfMLqjcKH/R0jsmIW0ImxZ 4PGd0Hqqd2F9BPZP1+kVm7TUPheg3kuJ0jj3sSlxjazkTnDuTh3KbpFGFbZn5uHCMAr7 D8mw== X-Gm-Message-State: AOAM533BTUzjZ63vq06xKHefvdhHeDyPIyz+N2jML2SGNRgSVfXpul5E rvTbws1cRNyPisAyBtVCizmiL7CTDsw= X-Google-Smtp-Source: ABdhPJymJjeQeLFSppIv8IS2l08kZ688Mi6qh8+/G9ZjQmKa+dzsHCIl4eOECN7reJs+Qebreandug== X-Received: by 2002:a05:651c:315:: with SMTP id a21mr3951011ljp.229.1605416402943; Sat, 14 Nov 2020 21:00:02 -0800 (PST) Received: from [1.0.0.7] ([178.155.6.8]) by smtp.gmail.com with ESMTPSA id c12sm2191396lfj.44.2020.11.14.21.00.01 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 14 Nov 2020 21:00:02 -0800 (PST) Subject: Re: More time spending with "delete pending" To: Justin Pryzby Cc: pgsql-hackers References: <20201115011112.GW30691@telsasoft.com> From: Alexander Lakhin Message-ID: <979f4ee6-9960-e37f-f3ee-f458e87777b0@gmail.com> Date: Sun, 15 Nov 2020 08:00:00 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20201115011112.GW30691@telsasoft.com> Content-Type: multipart/mixed; boundary="------------4A71A3FDA19A21992477642F" Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --------------4A71A3FDA19A21992477642F Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit 15.11.2020 04:11, Justin Pryzby wrote: > On Sat, Nov 14, 2020 at 01:00:00PM +0300, Alexander Lakhin wrote: >> As noted in [1], a sensible solution would be putting the same "retry on >> ERROR_ACCESS_DENIED" action in a wrapper for stat(). >> And bed90759f brought in master the _pgstat64() function, where such >> error handling should be placed. >> So please look at the patch (based on the previous one made to fix >> bug#16161), that makes the attached test pass. > Your patch introduces a "loops", but doesn't use it to escape the loop. Indeed, this is my mistake. Please look at the corrected patch (now that code corresponds to the pgwin32_open() as intended). And it rises another question, what if pg_ls_dir_files() is called for a directory where hundreds or thousands of files are really inaccessible due to restrictions? I mean that using CreateFile() in the modified stat() implementation can be rather expensive for an arbitrary file (and worse yet, for many files). On the positive side, for now pg_ls_dir_files() is called only from pg_ls_logdir, pg_ls_waldir, pg_ls_tmpdir, pg_ls_archive_statusdir, where having a bunch of files that are inaccessible for the postgres user is not expected anyway. But probably getting directory contents with correct file sizes (>4GB) in pg_ls_dir_files() can be implemented without calling CreateFile()/stat() at all (as ProcMon shows, the "dir" command doesn't call CreateFile() (or any other system function) for each file in the target directory). Best regards, Alexander --------------4A71A3FDA19A21992477642F Content-Type: text/x-patch; charset=UTF-8; name="fix_pg_ls_dir.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="fix_pg_ls_dir.patch" diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index d34182a7b0..922df49125 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -28,6 +28,7 @@ #include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "port.h" #include "postmaster/syslogger.h" #include "storage/fd.h" #include "utils/acl.h" diff --git a/src/port/win32stat.c b/src/port/win32stat.c index 4351aa4d08..2f9e111627 100644 --- a/src/port/win32stat.c +++ b/src/port/win32stat.c @@ -170,6 +170,7 @@ _pgstat64(const char *name, struct stat *buf) SECURITY_ATTRIBUTES sa; HANDLE hFile; int ret; + int loops = 0; #if _WIN32_WINNT < 0x0600 IO_STATUS_BLOCK ioStatus; FILE_STANDARD_INFORMATION standardInfo; @@ -182,31 +183,63 @@ _pgstat64(const char *name, struct stat *buf) errno = EINVAL; return -1; } - /* fast not-exists check */ if (GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES) { - _dosmaperr(GetLastError()); - return -1; + DWORD err = GetLastError(); + + if (err != ERROR_ACCESS_DENIED) { + _dosmaperr(err); + return -1; + } } /* get a file handle as lightweight as we can */ sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; - hFile = CreateFile(name, - GENERIC_READ, - (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), - &sa, - OPEN_EXISTING, - (FILE_FLAG_NO_BUFFERING | FILE_FLAG_BACKUP_SEMANTICS | - FILE_FLAG_OVERLAPPED), - NULL); - if (hFile == INVALID_HANDLE_VALUE) + while ((hFile = CreateFile(name, + GENERIC_READ, + (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), + &sa, + OPEN_EXISTING, + (FILE_FLAG_NO_BUFFERING | FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED), + NULL)) == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); - CloseHandle(hFile); + /* + * ERROR_ACCESS_DENIED is returned if the file is deleted but not yet + * gone (Windows NT status code is STATUS_DELETE_PENDING). In that + * case we want to wait a bit and try again, giving up after 1 second + * (since this condition should never persist very long). However, + * there are other commonly-hit cases that return ERROR_ACCESS_DENIED, + * so care is needed. In particular that happens if we try to open a + * directory, or of course if there's an actual file-permissions + * problem. To distinguish these cases, try a stat(). In the + * delete-pending case, it will either also get STATUS_DELETE_PENDING, + * or it will see the file as gone and fail with ENOENT. In other + * cases it will usually succeed. The only somewhat-likely case where + * this coding will uselessly wait is if there's a permissions problem + * with a containing directory, which we hope will never happen in any + * performance-critical code paths. + */ + if (err == ERROR_ACCESS_DENIED) + { + if (loops < 10) + { + struct microsoft_native_stat st; + + if (microsoft_native_stat(name, &st) != 0) + { + pg_usleep(100000); + loops++; + continue; + } + } + } + _dosmaperr(err); return -1; } --------------4A71A3FDA19A21992477642F--