mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Dump full memory maps around failing Windows reattach code.
This morning's results from buildfarm member dory make it pretty clear that something is getting mapped into the just-freed space, but not what that something is. Replace my minimalistic probes with a full dump of the process address space and module space, based on Noah's work at <20170403065106.GA2624300%40tornado.leadboat.com> This is all (probably) to get reverted once we have fixed the problem, but for now we need information. Discussion: https://postgr.es/m/25495.1524517820@sss.pgh.pa.us
This commit is contained in:
parent
c5e46c7c3b
commit
6ba0cc4bd3
@ -79,7 +79,7 @@ libpostgres.a: postgres
|
|||||||
endif # cygwin
|
endif # cygwin
|
||||||
|
|
||||||
ifeq ($(PORTNAME), win32)
|
ifeq ($(PORTNAME), win32)
|
||||||
LIBS += -lsecur32
|
LIBS += -lsecur32 -lpsapi
|
||||||
|
|
||||||
postgres: $(OBJS) $(WIN32RES)
|
postgres: $(OBJS) $(WIN32RES)
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) -Wl,--stack=$(WIN32_STACK_RLIMIT) -Wl,--export-all-symbols -Wl,--out-implib=libpostgres.a $(call expand_subsys,$(OBJS)) $(WIN32RES) $(LIBS) -o $@$(X)
|
$(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) -Wl,--stack=$(WIN32_STACK_RLIMIT) -Wl,--export-all-symbols -Wl,--out-implib=libpostgres.a $(call expand_subsys,$(OBJS)) $(WIN32RES) $(LIBS) -o $@$(X)
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <psapi.h>
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/dsm.h"
|
#include "storage/dsm.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
@ -24,6 +26,88 @@ static Size UsedShmemSegSize = 0;
|
|||||||
static bool EnableLockPagesPrivilege(int elevel);
|
static bool EnableLockPagesPrivilege(int elevel);
|
||||||
static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
|
static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
|
||||||
|
|
||||||
|
/* Dump all modules loaded into proc */
|
||||||
|
static void
|
||||||
|
dumpdlls(HANDLE proc)
|
||||||
|
{
|
||||||
|
HMODULE dll[1024];
|
||||||
|
DWORD size_used = 1;
|
||||||
|
int i,
|
||||||
|
n;
|
||||||
|
|
||||||
|
if (!EnumProcessModules(proc, dll, sizeof(dll), &size_used))
|
||||||
|
{
|
||||||
|
elog(LOG, "EnumProcessModules failed: %lu", GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n = (int) (size_used / sizeof(*dll));
|
||||||
|
elog(LOG, "EnumProcessModules: %d modules in process 0x%p", n, proc);
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
char name[MAXPGPATH];
|
||||||
|
|
||||||
|
if (!GetModuleFileNameEx(proc, dll[i], name, sizeof(name)))
|
||||||
|
sprintf(name, "GetModuleFileNameEx failed: %lu", GetLastError());
|
||||||
|
elog(LOG, "%d: 0x%p %s", i + 1, dll[i], name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mi_type(DWORD code)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case MEM_IMAGE:
|
||||||
|
return "img";
|
||||||
|
case MEM_MAPPED:
|
||||||
|
return "map";
|
||||||
|
case MEM_PRIVATE:
|
||||||
|
return "prv";
|
||||||
|
}
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mi_state(DWORD code)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case MEM_COMMIT:
|
||||||
|
return "commit";
|
||||||
|
case MEM_FREE:
|
||||||
|
return "free ";
|
||||||
|
case MEM_RESERVE:
|
||||||
|
return "reserv";
|
||||||
|
}
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dumpmem(const char *reason, HANDLE proc)
|
||||||
|
{
|
||||||
|
char *addr = 0;
|
||||||
|
MEMORY_BASIC_INFORMATION mi;
|
||||||
|
|
||||||
|
elog(LOG, "%s memory map", reason);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
memset(&mi, 0, sizeof(mi));
|
||||||
|
if (!VirtualQueryEx(proc, addr, &mi, sizeof(mi)))
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_INVALID_PARAMETER)
|
||||||
|
break;
|
||||||
|
elog(LOG, "VirtualQueryEx failed: %lu", GetLastError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
elog(LOG, "0x%p+0x%p %s (alloc 0x%p) %s",
|
||||||
|
mi.BaseAddress, (void *) mi.RegionSize,
|
||||||
|
mi_type(mi.Type), mi.AllocationBase, mi_state(mi.State));
|
||||||
|
addr += mi.RegionSize;
|
||||||
|
} while (addr > 0);
|
||||||
|
|
||||||
|
dumpdlls(proc);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate shared memory segment name. Expand the data directory, to generate
|
* Generate shared memory segment name. Expand the data directory, to generate
|
||||||
* an identifier unique for this data directory. Then replace all backslashes
|
* an identifier unique for this data directory. Then replace all backslashes
|
||||||
@ -388,19 +472,11 @@ PGSharedMemoryReAttach(void)
|
|||||||
{
|
{
|
||||||
PGShmemHeader *hdr;
|
PGShmemHeader *hdr;
|
||||||
void *origUsedShmemSegAddr = UsedShmemSegAddr;
|
void *origUsedShmemSegAddr = UsedShmemSegAddr;
|
||||||
MEMORY_BASIC_INFORMATION previnfo;
|
|
||||||
MEMORY_BASIC_INFORMATION afterinfo;
|
|
||||||
DWORD preverr;
|
|
||||||
DWORD aftererr;
|
|
||||||
|
|
||||||
Assert(UsedShmemSegAddr != NULL);
|
Assert(UsedShmemSegAddr != NULL);
|
||||||
Assert(IsUnderPostmaster);
|
Assert(IsUnderPostmaster);
|
||||||
|
|
||||||
/* Preliminary probe of region we intend to release */
|
dumpmem("before VirtualFree", GetCurrentProcess());
|
||||||
if (VirtualQuery(UsedShmemSegAddr, &previnfo, sizeof(previnfo)) != 0)
|
|
||||||
preverr = 0;
|
|
||||||
else
|
|
||||||
preverr = GetLastError();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release memory region reservation that was made by the postmaster
|
* Release memory region reservation that was made by the postmaster
|
||||||
@ -409,48 +485,14 @@ PGSharedMemoryReAttach(void)
|
|||||||
elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
|
elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
|
||||||
UsedShmemSegAddr, GetLastError());
|
UsedShmemSegAddr, GetLastError());
|
||||||
|
|
||||||
/* Verify post-release state */
|
dumpmem("after VirtualFree", GetCurrentProcess());
|
||||||
if (VirtualQuery(UsedShmemSegAddr, &afterinfo, sizeof(afterinfo)) != 0)
|
|
||||||
aftererr = 0;
|
|
||||||
else
|
|
||||||
aftererr = GetLastError();
|
|
||||||
|
|
||||||
hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
|
hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
|
||||||
if (!hdr)
|
if (!hdr)
|
||||||
{
|
{
|
||||||
DWORD maperr = GetLastError();
|
DWORD maperr = GetLastError();
|
||||||
MEMORY_BASIC_INFORMATION postinfo;
|
|
||||||
DWORD posterr;
|
|
||||||
|
|
||||||
/* Capture post-failure state */
|
dumpmem("after MapViewOfFileEx", GetCurrentProcess());
|
||||||
if (VirtualQuery(UsedShmemSegAddr, &postinfo, sizeof(postinfo)) != 0)
|
|
||||||
posterr = 0;
|
|
||||||
else
|
|
||||||
posterr = GetLastError();
|
|
||||||
|
|
||||||
if (preverr == 0)
|
|
||||||
elog(LOG, "VirtualQuery(%p) before free reports region of size %zu, base %p, has state 0x%lx",
|
|
||||||
UsedShmemSegAddr, previnfo.RegionSize,
|
|
||||||
previnfo.AllocationBase, previnfo.State);
|
|
||||||
else
|
|
||||||
elog(LOG, "VirtualQuery(%p) before free failed: error code %lu",
|
|
||||||
UsedShmemSegAddr, preverr);
|
|
||||||
|
|
||||||
if (aftererr == 0)
|
|
||||||
elog(LOG, "VirtualQuery(%p) after free reports region of size %zu, base %p, has state 0x%lx",
|
|
||||||
UsedShmemSegAddr, afterinfo.RegionSize,
|
|
||||||
afterinfo.AllocationBase, afterinfo.State);
|
|
||||||
else
|
|
||||||
elog(LOG, "VirtualQuery(%p) after free failed: error code %lu",
|
|
||||||
UsedShmemSegAddr, aftererr);
|
|
||||||
|
|
||||||
if (posterr == 0)
|
|
||||||
elog(LOG, "VirtualQuery(%p) after map reports region of size %zu, base %p, has state 0x%lx",
|
|
||||||
UsedShmemSegAddr, postinfo.RegionSize,
|
|
||||||
postinfo.AllocationBase, postinfo.State);
|
|
||||||
else
|
|
||||||
elog(LOG, "VirtualQuery(%p) after map failed: error code %lu",
|
|
||||||
UsedShmemSegAddr, posterr);
|
|
||||||
|
|
||||||
elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
|
elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
|
||||||
UsedShmemSegID, UsedShmemSegAddr, maperr);
|
UsedShmemSegID, UsedShmemSegAddr, maperr);
|
||||||
@ -597,5 +639,7 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dumpmem("after reserve", hChild);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# src/makefiles/Makefile.win32
|
# src/makefiles/Makefile.win32
|
||||||
|
|
||||||
|
override CPPFLAGS+= -DPSAPI_VERSION=1
|
||||||
|
|
||||||
ifdef PGXS
|
ifdef PGXS
|
||||||
BE_DLLLIBS= -L$(libdir) -lpostgres
|
BE_DLLLIBS= -L$(libdir) -lpostgres
|
||||||
override CPPFLAGS+= -I$(includedir_server)/port/win32
|
override CPPFLAGS+= -I$(includedir_server)/port/win32
|
||||||
|
@ -174,8 +174,10 @@ sub mkvcbuild
|
|||||||
'repl_gram.y', 'syncrep_scanner.l',
|
'repl_gram.y', 'syncrep_scanner.l',
|
||||||
'syncrep_gram.y');
|
'syncrep_gram.y');
|
||||||
$postgres->AddDefine('BUILDING_DLL');
|
$postgres->AddDefine('BUILDING_DLL');
|
||||||
|
$postgres->AddDefine('PSAPI_VERSION=1');
|
||||||
$postgres->AddLibrary('secur32.lib');
|
$postgres->AddLibrary('secur32.lib');
|
||||||
$postgres->AddLibrary('ws2_32.lib');
|
$postgres->AddLibrary('ws2_32.lib');
|
||||||
|
$postgres->AddLibrary('psapi.lib');
|
||||||
$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
|
||||||
$postgres->FullExportDLL('postgres.lib');
|
$postgres->FullExportDLL('postgres.lib');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user