Re: Atomic rename feature for Windows. - Mailing list pgsql-hackers

From Victor Spirin
Subject Re: Atomic rename feature for Windows.
Date
Msg-id 82cf392d-4dff-946a-56c3-4c5447b87813@postgrespro.ru
Whole thread Raw
In response to Re: Atomic rename feature for Windows.  (Thomas Munro <thomas.munro@gmail.com>)
Responses Re: Atomic rename feature for Windows.
Re: Atomic rename feature for Windows.
List pgsql-hackers
Thank you,

In this variant:

1) renamed file win10.manifest to windows.manifest

2) renamed function pgrename_win10 to pgrename_windows_posix_semantics

3) Function pgrename returns result of pgrename_windows_posix_semantics 
function and not contiue run old version of function.

4) Added call GetLastError() after error MultiByteToWideChar fuction.

> +typedef struct _FILE_RENAME_INFO_VVS {
> +   union {
> +       BOOLEAN ReplaceIfExists;  // FileRenameInfo
> +       DWORD Flags;              // FileRenameInfoEx
> +   } DUMMYUNIONNAME;
> +   HANDLE RootDirectory;
> +   DWORD FileNameLength;
> +   WCHAR FileName[MAX_PATH];
> +} FILE_RENAME_INFO_VVS;
>
> Why can't we use a system header[2] for this?
I have a dynamic memory allocation version in the first patch.

     len = wcslen(to_w);
     rename_info = (FILE_RENAME_INFO*)malloc(sizeof(FILE_RENAME_INFO) + 
(len + 1) * sizeof(wchar_t));

     rename_info->ReplaceIfExists = TRUE;
     rename_info->Flags = FILE_RENAME_FLAG_POSIX_SEMANTICS | 
FILE_RENAME_FLAG_REPLACE_IF_EXISTS;

     rename_info->RootDirectory = NULL;
     rename_info->FileNameLength = len;
     memcpy(rename_info->FileName, to_w, (len + 1) * sizeof(wchar_t));

Is this code better? Maybe there is another correct method?

I checked the pgrename_windows_posix_semantics() function on Windows 7. 
It returns error 87: Parameter is incorrect. Hence, it is necessary to 
check the Windows version and call the old pgrename function for old 
Windows.


Victor Spirin
Postgres Professional:http://www.postgrespro.com
The Russian Postgres Company

07.09.2021 4:40, Thomas Munro пишет:
> On Tue, Sep 7, 2021 at 5:44 AM Victor Spirin <v.spirin@postgrespro.ru> wrote:
>> I have changed the way I add the manifest to projects. I used the
>> AdditionalManifestFiles option for a VS project.
> Hi Victor,
>
> Thanks for working on this!
>
> I wonder if POSIX-style rename is used automatically on recent
> Windows, based on the new clue that DeleteFile() has started
> defaulting to POSIX semantics[1] (maybe it would require ReplaceFile()
> instead of MoveFileEx(), but I have no idea.)  If so, one question is
> whether we'd still want to do this explicit POSIX rename dance, or
> whether we should just wait a bit longer for it to happen
> automatically on all relevant systems (plus tweak to use ReplaceFile()
> if necessary).  If not, we might want to do what you're proposing
> anyway, especially if ReplaceFile() is required, because its interface
> is weird (it only works if the other file exists?).  Hmm, that alone
> would be a good reason to go with your plan regardless, and of course
> it would be good to see this fixed everywhere ASAP.
>
> We still have to answer that question for pgunlink().  I was
> contemplating that over in that other thread, because unlink() ->
> EACCES is blocking something I'm working on.  I found a partial
> solution to that that works even on old and non-NTFS systems, and I
> was thinking that would be enough for now and we could just patiently
> wait until automatic POSIX semantics to arrives on all relevant
> systems as the real long term solution, so I didn't need to expend
> energy doing an intermediate explicit POSIX-mode wrapper like what
> you're proposing.  But then it seems strange to make a different
> choice about that for rename() and unlink().  So... do you think it
> would make sense to extend your patch to cover unlink() too?
>
> It would be great to have a tool in the tree that tests directory
> entry semantics, called something like src/bin/pg_test_dirmod, so that
> it becomes very clear when POSIX semantics are being used.  It could
> test various interesting unlink and rename scenarios through our
> wrappers (concurrent file handles, creating a new file with the name
> of the old one, unlinking the containing directory, ...).  It could
> run on the build farm animals, and we could even ask people to run it
> when they report problems, to try to lift the fog of bizarro Windows
> file system semantics.
>
> How exactly does the function fail on a file system that doesn't
> support the new POSIX semantics?  Assuming there is something like
> ENOSUPP to report "file system says no", do we want to keep trying
> every time, or remember that it doesn't work?  I guess the answer may
> vary per mount point, which makes it hard to track when you only have
> an fd...
>
> If it fails because of a sharing violation, it seems strange that we
> immediately fall back to the old code to do the traditional (and
> horrible) sleep/retry loop.  That means that in rare conditions we can
> still get the old behaviour that leads to problems, just because of a
> transient condition.  Hmm.  Would it make more sense to say: fall back
> to the traditional behaviour only for ENOSUPP (if there is such a
> thing), cope with transient sharing violations without giving up on
> POSIX semantics, and report all other failures immediately?
>
> I agree that the existing enum CHECKSUM_TYPE_NONE + friends should be
> renamed to something less collision-prone and more consistent with the
> name of the enum ("pg_checksum_type"), so I'd vote for adding a PG_
> prefix, in a separate patch.
>
> +    <Manifest>
> +      <AdditionalManifestFiles>src/port/win10.manifest</AdditionalManifestFiles>
> +    </Manifest>
>
> I have no opinion on how you're supposed to test for OS versions, but
> one trivial observation is that that file declares support for many
> Windows releases, and I guess pretty soon you'll need to add 11, and
> then we'll wonder why it says 10 in the file name.  Would it be better
> as "windows.manifest" or something?
>
> +pgrename_win10(const char *from, const char *to)
>
> Same thought on the name: this'll age badly.  What about something
> like pgrename_windows_posix_semantics?
>
> +typedef struct _FILE_RENAME_INFO_VVS {
> +   union {
> +       BOOLEAN ReplaceIfExists;  // FileRenameInfo
> +       DWORD Flags;              // FileRenameInfoEx
> +   } DUMMYUNIONNAME;
> +   HANDLE RootDirectory;
> +   DWORD FileNameLength;
> +   WCHAR FileName[MAX_PATH];
> +} FILE_RENAME_INFO_VVS;
>
> Why can't we use a system header[2] for this?
>
> +   if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)from, -1,
> (LPWSTR)from_w, MAX_PATH) == 0) return -1;
> +   if (MultiByteToWideChar(CP_ACP, 0, (LPCCH)to, -1,
> (LPWSTR)rename_info.FileName, MAX_PATH) == 0) return -1;
>
> Don't these need _dosmaperr(GetLastError())?
>
> [1] https://www.postgresql.org/message-id/20210905214437.y25j42yigwnbdvtg%40alap3.anarazel.de
> [2] https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_rename_info
>
>

Attachment

pgsql-hackers by date:

Previous
From: Andres Freund
Date:
Subject: Re: Gather performance analysis
Next
From: Rachel Heaton
Date:
Subject: Re: Rewriting the test of pg_upgrade as a TAP test - take three - remastered set