mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Get rid of the dynamic shared memory state file.
Instead of storing the ID of the dynamic shared memory control segment in a file within the data directory, store it in the main control segment. This avoids a number of nasty corner cases, most seriously that doing an online backup and then using it on the same machine (e.g. to fire up a standby) would result in the standby clobbering all of the master's dynamic shared memory segments. Per complaints from Heikki Linnakangas, Fujii Masao, and Tom Lane.
This commit is contained in:
parent
0886fc6a5c
commit
11a65eed16
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "portability/mem.h"
|
#include "portability/mem.h"
|
||||||
|
#include "storage/dsm.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/pg_shmem.h"
|
#include "storage/pg_shmem.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
@ -421,7 +422,8 @@ CreateAnonymousSegment(Size *size)
|
|||||||
* zero will be passed.
|
* zero will be passed.
|
||||||
*/
|
*/
|
||||||
PGShmemHeader *
|
PGShmemHeader *
|
||||||
PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
PGSharedMemoryCreate(Size size, bool makePrivate, int port,
|
||||||
|
PGShmemHeader **shim)
|
||||||
{
|
{
|
||||||
IpcMemoryKey NextShmemSegID;
|
IpcMemoryKey NextShmemSegID;
|
||||||
void *memAddress;
|
void *memAddress;
|
||||||
@ -509,10 +511,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The segment appears to be from a dead Postgres process, or from a
|
* The segment appears to be from a dead Postgres process, or from a
|
||||||
* previous cycle of life in this same process. Zap it, if possible.
|
* previous cycle of life in this same process. Zap it, if possible,
|
||||||
|
* and any associated dynamic shared memory segments, as well.
|
||||||
* This probably shouldn't fail, but if it does, assume the segment
|
* This probably shouldn't fail, but if it does, assume the segment
|
||||||
* belongs to someone else after all, and continue quietly.
|
* belongs to someone else after all, and continue quietly.
|
||||||
*/
|
*/
|
||||||
|
if (hdr->dsm_control != 0)
|
||||||
|
dsm_cleanup_using_control_segment(hdr->dsm_control);
|
||||||
shmdt(memAddress);
|
shmdt(memAddress);
|
||||||
if (shmctl(shmid, IPC_RMID, NULL) < 0)
|
if (shmctl(shmid, IPC_RMID, NULL) < 0)
|
||||||
continue;
|
continue;
|
||||||
@ -539,6 +544,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
hdr = (PGShmemHeader *) memAddress;
|
hdr = (PGShmemHeader *) memAddress;
|
||||||
hdr->creatorPID = getpid();
|
hdr->creatorPID = getpid();
|
||||||
hdr->magic = PGShmemMagic;
|
hdr->magic = PGShmemMagic;
|
||||||
|
hdr->dsm_control = 0;
|
||||||
|
|
||||||
/* Fill in the data directory ID info, too */
|
/* Fill in the data directory ID info, too */
|
||||||
if (stat(DataDir, &statbuf) < 0)
|
if (stat(DataDir, &statbuf) < 0)
|
||||||
@ -554,6 +560,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
*/
|
*/
|
||||||
hdr->totalsize = size;
|
hdr->totalsize = size;
|
||||||
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
|
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
|
||||||
|
*shim = hdr;
|
||||||
|
|
||||||
/* Save info for possible future use */
|
/* Save info for possible future use */
|
||||||
UsedShmemSegAddr = memAddress;
|
UsedShmemSegAddr = memAddress;
|
||||||
@ -608,6 +615,7 @@ PGSharedMemoryReAttach(void)
|
|||||||
if (hdr != origUsedShmemSegAddr)
|
if (hdr != origUsedShmemSegAddr)
|
||||||
elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
|
elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
|
||||||
hdr, origUsedShmemSegAddr);
|
hdr, origUsedShmemSegAddr);
|
||||||
|
dsm_set_control_handle(((PGShmemHeader *) hdr)->dsm_control);
|
||||||
|
|
||||||
UsedShmemSegAddr = hdr; /* probably redundant */
|
UsedShmemSegAddr = hdr; /* probably redundant */
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,8 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
PGShmemHeader *
|
PGShmemHeader *
|
||||||
PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
PGSharedMemoryCreate(Size size, bool makePrivate, int port,
|
||||||
|
PGShmemHeader **shim)
|
||||||
{
|
{
|
||||||
void *memAddress;
|
void *memAddress;
|
||||||
PGShmemHeader *hdr;
|
PGShmemHeader *hdr;
|
||||||
@ -245,12 +246,14 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
*/
|
*/
|
||||||
hdr->totalsize = size;
|
hdr->totalsize = size;
|
||||||
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
|
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
|
||||||
|
hdr->dsm_control = 0;
|
||||||
|
|
||||||
/* Save info for possible future use */
|
/* Save info for possible future use */
|
||||||
UsedShmemSegAddr = memAddress;
|
UsedShmemSegAddr = memAddress;
|
||||||
UsedShmemSegSize = size;
|
UsedShmemSegSize = size;
|
||||||
UsedShmemSegID = hmap2;
|
UsedShmemSegID = hmap2;
|
||||||
|
|
||||||
|
*shim = NULL;
|
||||||
return hdr;
|
return hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +292,7 @@ PGSharedMemoryReAttach(void)
|
|||||||
hdr, origUsedShmemSegAddr);
|
hdr, origUsedShmemSegAddr);
|
||||||
if (hdr->magic != PGShmemMagic)
|
if (hdr->magic != PGShmemMagic)
|
||||||
elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
|
elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
|
||||||
|
dsm_set_control_handle(hdr->dsm_control);
|
||||||
|
|
||||||
UsedShmemSegAddr = hdr; /* probably redundant */
|
UsedShmemSegAddr = hdr; /* probably redundant */
|
||||||
}
|
}
|
||||||
|
@ -39,13 +39,11 @@
|
|||||||
#include "storage/dsm.h"
|
#include "storage/dsm.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/lwlock.h"
|
#include "storage/lwlock.h"
|
||||||
|
#include "storage/pg_shmem.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/resowner_private.h"
|
#include "utils/resowner_private.h"
|
||||||
|
|
||||||
#define PG_DYNSHMEM_STATE_FILE PG_DYNSHMEM_DIR "/state"
|
|
||||||
#define PG_DYNSHMEM_NEW_STATE_FILE PG_DYNSHMEM_DIR "/state.new"
|
|
||||||
#define PG_DYNSHMEM_STATE_BUFSIZ 512
|
|
||||||
#define PG_DYNSHMEM_CONTROL_MAGIC 0x9a503d32
|
#define PG_DYNSHMEM_CONTROL_MAGIC 0x9a503d32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -95,10 +93,7 @@ typedef struct dsm_control_header
|
|||||||
dsm_control_item item[FLEXIBLE_ARRAY_MEMBER];
|
dsm_control_item item[FLEXIBLE_ARRAY_MEMBER];
|
||||||
} dsm_control_header;
|
} dsm_control_header;
|
||||||
|
|
||||||
static void dsm_cleanup_using_control_segment(void);
|
|
||||||
static void dsm_cleanup_for_mmap(void);
|
static void dsm_cleanup_for_mmap(void);
|
||||||
static bool dsm_read_state_file(dsm_handle *h);
|
|
||||||
static void dsm_write_state_file(dsm_handle h);
|
|
||||||
static void dsm_postmaster_shutdown(int code, Datum arg);
|
static void dsm_postmaster_shutdown(int code, Datum arg);
|
||||||
static dsm_segment *dsm_create_descriptor(void);
|
static dsm_segment *dsm_create_descriptor(void);
|
||||||
static bool dsm_control_segment_sane(dsm_control_header *control,
|
static bool dsm_control_segment_sane(dsm_control_header *control,
|
||||||
@ -146,7 +141,7 @@ static void *dsm_control_impl_private = NULL;
|
|||||||
* startup time.
|
* startup time.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
dsm_postmaster_startup(void)
|
dsm_postmaster_startup(PGShmemHeader *shim)
|
||||||
{
|
{
|
||||||
void *dsm_control_address = NULL;
|
void *dsm_control_address = NULL;
|
||||||
uint32 maxitems;
|
uint32 maxitems;
|
||||||
@ -159,26 +154,13 @@ dsm_postmaster_startup(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for, and remove, shared memory segments left behind by a dead
|
* If we're using the mmap implementations, clean up any leftovers.
|
||||||
* postmaster. This isn't necessary on Windows, which always removes them
|
* Cleanup isn't needed on Windows, and happens earlier in startup for
|
||||||
* when the last reference is gone.
|
* POSIX and System V shared memory, via a direct call to
|
||||||
|
* dsm_cleanup_using_control_segment.
|
||||||
*/
|
*/
|
||||||
switch (dynamic_shared_memory_type)
|
if (dynamic_shared_memory_type == DSM_IMPL_MMAP)
|
||||||
{
|
dsm_cleanup_for_mmap();
|
||||||
case DSM_IMPL_POSIX:
|
|
||||||
case DSM_IMPL_SYSV:
|
|
||||||
dsm_cleanup_using_control_segment();
|
|
||||||
break;
|
|
||||||
case DSM_IMPL_MMAP:
|
|
||||||
dsm_cleanup_for_mmap();
|
|
||||||
break;
|
|
||||||
case DSM_IMPL_WINDOWS:
|
|
||||||
/* Nothing to do. */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
elog(ERROR, "unknown dynamic shared memory type: %d",
|
|
||||||
dynamic_shared_memory_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine size for new control segment. */
|
/* Determine size for new control segment. */
|
||||||
maxitems = PG_DYNSHMEM_FIXED_SLOTS
|
maxitems = PG_DYNSHMEM_FIXED_SLOTS
|
||||||
@ -187,23 +169,30 @@ dsm_postmaster_startup(void)
|
|||||||
maxitems);
|
maxitems);
|
||||||
segsize = dsm_control_bytes_needed(maxitems);
|
segsize = dsm_control_bytes_needed(maxitems);
|
||||||
|
|
||||||
/* Loop until we find an unused identifier for the new control segment. */
|
/*
|
||||||
|
* Loop until we find an unused identifier for the new control segment.
|
||||||
|
* We sometimes use 0 as a sentinel value indicating that no control
|
||||||
|
* segment is known to exist, so avoid using that value for a real
|
||||||
|
* control segment.
|
||||||
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Assert(dsm_control_address == NULL);
|
Assert(dsm_control_address == NULL);
|
||||||
Assert(dsm_control_mapped_size == 0);
|
Assert(dsm_control_mapped_size == 0);
|
||||||
dsm_control_handle = random();
|
dsm_control_handle = random();
|
||||||
|
if (dsm_control_handle == 0)
|
||||||
|
continue;
|
||||||
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
|
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
|
||||||
&dsm_control_impl_private, &dsm_control_address,
|
&dsm_control_impl_private, &dsm_control_address,
|
||||||
&dsm_control_mapped_size, ERROR))
|
&dsm_control_mapped_size, ERROR))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dsm_control = dsm_control_address;
|
dsm_control = dsm_control_address;
|
||||||
on_shmem_exit(dsm_postmaster_shutdown, 0);
|
on_shmem_exit(dsm_postmaster_shutdown, PointerGetDatum(shim));
|
||||||
elog(DEBUG2,
|
elog(DEBUG2,
|
||||||
"created dynamic shared memory control segment %u (%zu bytes)",
|
"created dynamic shared memory control segment %u (%zu bytes)",
|
||||||
dsm_control_handle, segsize);
|
dsm_control_handle, segsize);
|
||||||
dsm_write_state_file(dsm_control_handle);
|
shim->dsm_control = dsm_control_handle;
|
||||||
|
|
||||||
/* Initialize control segment. */
|
/* Initialize control segment. */
|
||||||
dsm_control->magic = PG_DYNSHMEM_CONTROL_MAGIC;
|
dsm_control->magic = PG_DYNSHMEM_CONTROL_MAGIC;
|
||||||
@ -216,8 +205,8 @@ dsm_postmaster_startup(void)
|
|||||||
* invocation still exists. If so, remove the dynamic shared memory
|
* invocation still exists. If so, remove the dynamic shared memory
|
||||||
* segments to which it refers, and then the control segment itself.
|
* segments to which it refers, and then the control segment itself.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
dsm_cleanup_using_control_segment(void)
|
dsm_cleanup_using_control_segment(dsm_handle old_control_handle)
|
||||||
{
|
{
|
||||||
void *mapped_address = NULL;
|
void *mapped_address = NULL;
|
||||||
void *junk_mapped_address = NULL;
|
void *junk_mapped_address = NULL;
|
||||||
@ -227,14 +216,10 @@ dsm_cleanup_using_control_segment(void)
|
|||||||
Size junk_mapped_size = 0;
|
Size junk_mapped_size = 0;
|
||||||
uint32 nitems;
|
uint32 nitems;
|
||||||
uint32 i;
|
uint32 i;
|
||||||
dsm_handle old_control_handle;
|
|
||||||
dsm_control_header *old_control;
|
dsm_control_header *old_control;
|
||||||
|
|
||||||
/*
|
/* If dynamic shared memory is disabled, there's nothing to do. */
|
||||||
* Read the state file. If it doesn't exist or is empty, there's nothing
|
if (dynamic_shared_memory_type == DSM_IMPL_NONE)
|
||||||
* more to do.
|
|
||||||
*/
|
|
||||||
if (!dsm_read_state_file(&old_control_handle))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -346,111 +331,6 @@ dsm_cleanup_for_mmap(void)
|
|||||||
FreeDir(dir);
|
FreeDir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read and parse the state file.
|
|
||||||
*
|
|
||||||
* If the state file is empty or the contents are garbled, it probably means
|
|
||||||
* that the operating system rebooted before the data written by the previous
|
|
||||||
* postmaster made it to disk. In that case, we can just ignore it; any shared
|
|
||||||
* memory from before the reboot should be gone anyway.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
dsm_read_state_file(dsm_handle *h)
|
|
||||||
{
|
|
||||||
int statefd;
|
|
||||||
char statebuf[PG_DYNSHMEM_STATE_BUFSIZ];
|
|
||||||
int nbytes = 0;
|
|
||||||
char *endptr,
|
|
||||||
*s;
|
|
||||||
dsm_handle handle;
|
|
||||||
|
|
||||||
/* Read the state file to get the ID of the old control segment. */
|
|
||||||
statefd = BasicOpenFile(PG_DYNSHMEM_STATE_FILE, O_RDONLY | PG_BINARY, 0);
|
|
||||||
if (statefd < 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT)
|
|
||||||
return false;
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not open file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_STATE_FILE)));
|
|
||||||
}
|
|
||||||
nbytes = read(statefd, statebuf, PG_DYNSHMEM_STATE_BUFSIZ - 1);
|
|
||||||
if (nbytes < 0)
|
|
||||||
{
|
|
||||||
close(statefd);
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not read file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_STATE_FILE)));
|
|
||||||
}
|
|
||||||
/* make sure buffer is NUL terminated */
|
|
||||||
statebuf[nbytes] = '\0';
|
|
||||||
close(statefd);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We expect to find the handle of the old control segment here,
|
|
||||||
* on a line by itself.
|
|
||||||
*/
|
|
||||||
handle = strtoul(statebuf, &endptr, 10);
|
|
||||||
for (s = endptr; *s == ' ' || *s == '\t'; ++s)
|
|
||||||
;
|
|
||||||
if (*s != '\n' && *s != '\0')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Looks good. */
|
|
||||||
*h = handle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write our control segment handle to the state file, so that if the
|
|
||||||
* postmaster is killed without running it's on_shmem_exit hooks, the
|
|
||||||
* next postmaster can clean things up after restart.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dsm_write_state_file(dsm_handle h)
|
|
||||||
{
|
|
||||||
int statefd;
|
|
||||||
char statebuf[PG_DYNSHMEM_STATE_BUFSIZ];
|
|
||||||
int nbytes;
|
|
||||||
|
|
||||||
/* Create or truncate the file. */
|
|
||||||
statefd = open(PG_DYNSHMEM_NEW_STATE_FILE,
|
|
||||||
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600);
|
|
||||||
if (statefd < 0)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not create file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_NEW_STATE_FILE)));
|
|
||||||
|
|
||||||
/* Write contents. */
|
|
||||||
snprintf(statebuf, PG_DYNSHMEM_STATE_BUFSIZ, "%u\n", dsm_control_handle);
|
|
||||||
nbytes = strlen(statebuf);
|
|
||||||
if (write(statefd, statebuf, nbytes) != nbytes)
|
|
||||||
{
|
|
||||||
if (errno == 0)
|
|
||||||
errno = ENOSPC; /* if no error signalled, assume no space */
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not write file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_NEW_STATE_FILE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close file. */
|
|
||||||
close(statefd);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Atomically rename file into place, so that no one ever sees a partially
|
|
||||||
* written state file.
|
|
||||||
*/
|
|
||||||
if (rename(PG_DYNSHMEM_NEW_STATE_FILE, PG_DYNSHMEM_STATE_FILE) < 0)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not rename file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_NEW_STATE_FILE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At shutdown time, we iterate over the control segment and remove all
|
* At shutdown time, we iterate over the control segment and remove all
|
||||||
* remaining dynamic shared memory segments. We avoid throwing errors here;
|
* remaining dynamic shared memory segments. We avoid throwing errors here;
|
||||||
@ -466,6 +346,7 @@ dsm_postmaster_shutdown(int code, Datum arg)
|
|||||||
void *junk_mapped_address = NULL;
|
void *junk_mapped_address = NULL;
|
||||||
void *junk_impl_private = NULL;
|
void *junk_impl_private = NULL;
|
||||||
Size junk_mapped_size = 0;
|
Size junk_mapped_size = 0;
|
||||||
|
PGShmemHeader *shim = (PGShmemHeader *) DatumGetPointer(arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If some other backend exited uncleanly, it might have corrupted the
|
* If some other backend exited uncleanly, it might have corrupted the
|
||||||
@ -510,13 +391,7 @@ dsm_postmaster_shutdown(int code, Datum arg)
|
|||||||
&dsm_control_impl_private, &dsm_control_address,
|
&dsm_control_impl_private, &dsm_control_address,
|
||||||
&dsm_control_mapped_size, LOG);
|
&dsm_control_mapped_size, LOG);
|
||||||
dsm_control = dsm_control_address;
|
dsm_control = dsm_control_address;
|
||||||
|
shim->dsm_control = 0;
|
||||||
/* And, finally, remove the state file. */
|
|
||||||
if (unlink(PG_DYNSHMEM_STATE_FILE) < 0)
|
|
||||||
ereport(LOG,
|
|
||||||
(errcode_for_file_access(),
|
|
||||||
errmsg("could not unlink file \"%s\": %m",
|
|
||||||
PG_DYNSHMEM_STATE_FILE)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -536,25 +411,18 @@ dsm_backend_startup(void)
|
|||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
{
|
{
|
||||||
dsm_handle control_handle;
|
|
||||||
void *control_address = NULL;
|
void *control_address = NULL;
|
||||||
|
|
||||||
/* Read the control segment information from the state file. */
|
|
||||||
if (!dsm_read_state_file(&control_handle))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
|
||||||
errmsg("could not parse dynamic shared memory state file")));
|
|
||||||
|
|
||||||
/* Attach control segment. */
|
/* Attach control segment. */
|
||||||
dsm_impl_op(DSM_OP_ATTACH, control_handle, 0,
|
Assert(dsm_control_handle != 0);
|
||||||
|
dsm_impl_op(DSM_OP_ATTACH, dsm_control_handle, 0,
|
||||||
&dsm_control_impl_private, &control_address,
|
&dsm_control_impl_private, &control_address,
|
||||||
&dsm_control_mapped_size, ERROR);
|
&dsm_control_mapped_size, ERROR);
|
||||||
dsm_control_handle = control_handle;
|
|
||||||
dsm_control = control_address;
|
dsm_control = control_address;
|
||||||
/* If control segment doesn't look sane, something is badly wrong. */
|
/* If control segment doesn't look sane, something is badly wrong. */
|
||||||
if (!dsm_control_segment_sane(dsm_control, dsm_control_mapped_size))
|
if (!dsm_control_segment_sane(dsm_control, dsm_control_mapped_size))
|
||||||
{
|
{
|
||||||
dsm_impl_op(DSM_OP_DETACH, control_handle, 0,
|
dsm_impl_op(DSM_OP_DETACH, dsm_control_handle, 0,
|
||||||
&dsm_control_impl_private, &control_address,
|
&dsm_control_impl_private, &control_address,
|
||||||
&dsm_control_mapped_size, WARNING);
|
&dsm_control_mapped_size, WARNING);
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
@ -567,6 +435,20 @@ dsm_backend_startup(void)
|
|||||||
dsm_init_done = true;
|
dsm_init_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
/*
|
||||||
|
* When running under EXEC_BACKEND, we get a callback here when the main
|
||||||
|
* shared memory segment is re-attached, so that we can record the control
|
||||||
|
* handle retrieved from it.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dsm_set_control_handle(dsm_handle h)
|
||||||
|
{
|
||||||
|
Assert(dsm_control_handle == 0 && h != 0);
|
||||||
|
dsm_control_handle = h;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new dynamic shared memory segment.
|
* Create a new dynamic shared memory segment.
|
||||||
*/
|
*/
|
||||||
|
@ -90,6 +90,8 @@ RequestAddinShmemSpace(Size size)
|
|||||||
void
|
void
|
||||||
CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
|
CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
|
||||||
{
|
{
|
||||||
|
PGShmemHeader *shim = NULL;
|
||||||
|
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
PGShmemHeader *seghdr;
|
PGShmemHeader *seghdr;
|
||||||
@ -149,7 +151,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
|
|||||||
/*
|
/*
|
||||||
* Create the shmem segment
|
* Create the shmem segment
|
||||||
*/
|
*/
|
||||||
seghdr = PGSharedMemoryCreate(size, makePrivate, port);
|
seghdr = PGSharedMemoryCreate(size, makePrivate, port, &shim);
|
||||||
|
|
||||||
InitShmemAccess(seghdr);
|
InitShmemAccess(seghdr);
|
||||||
|
|
||||||
@ -254,7 +256,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
|
|||||||
|
|
||||||
/* Initialize dynamic shared memory facilities. */
|
/* Initialize dynamic shared memory facilities. */
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
dsm_postmaster_startup();
|
dsm_postmaster_startup(shim);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now give loadable modules a chance to set up their shmem allocations
|
* Now give loadable modules a chance to set up their shmem allocations
|
||||||
|
@ -18,10 +18,16 @@
|
|||||||
typedef struct dsm_segment dsm_segment;
|
typedef struct dsm_segment dsm_segment;
|
||||||
|
|
||||||
/* Startup and shutdown functions. */
|
/* Startup and shutdown functions. */
|
||||||
extern void dsm_postmaster_startup(void);
|
struct PGShmemHeader; /* avoid including pg_shmem.h */
|
||||||
|
extern void dsm_cleanup_using_control_segment(dsm_handle old_control_handle);
|
||||||
|
extern void dsm_postmaster_startup(struct PGShmemHeader *);
|
||||||
extern void dsm_backend_shutdown(void);
|
extern void dsm_backend_shutdown(void);
|
||||||
extern void dsm_detach_all(void);
|
extern void dsm_detach_all(void);
|
||||||
|
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
extern void dsm_set_control_handle(dsm_handle h);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Functions that create, update, or remove mappings. */
|
/* Functions that create, update, or remove mappings. */
|
||||||
extern dsm_segment *dsm_create(Size size);
|
extern dsm_segment *dsm_create(Size size);
|
||||||
extern dsm_segment *dsm_attach(dsm_handle h);
|
extern dsm_segment *dsm_attach(dsm_handle h);
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#ifndef PG_SHMEM_H
|
#ifndef PG_SHMEM_H
|
||||||
#define PG_SHMEM_H
|
#define PG_SHMEM_H
|
||||||
|
|
||||||
|
#include "storage/dsm_impl.h"
|
||||||
|
|
||||||
typedef struct PGShmemHeader /* standard header for all Postgres shmem */
|
typedef struct PGShmemHeader /* standard header for all Postgres shmem */
|
||||||
{
|
{
|
||||||
int32 magic; /* magic # to identify Postgres segments */
|
int32 magic; /* magic # to identify Postgres segments */
|
||||||
@ -31,6 +33,7 @@ typedef struct PGShmemHeader /* standard header for all Postgres shmem */
|
|||||||
pid_t creatorPID; /* PID of creating process */
|
pid_t creatorPID; /* PID of creating process */
|
||||||
Size totalsize; /* total size of segment */
|
Size totalsize; /* total size of segment */
|
||||||
Size freeoffset; /* offset to first free space */
|
Size freeoffset; /* offset to first free space */
|
||||||
|
dsm_handle dsm_control; /* ID of dynamic shared memory control seg */
|
||||||
void *index; /* pointer to ShmemIndex table */
|
void *index; /* pointer to ShmemIndex table */
|
||||||
#ifndef WIN32 /* Windows doesn't have useful inode#s */
|
#ifndef WIN32 /* Windows doesn't have useful inode#s */
|
||||||
dev_t device; /* device data directory is on */
|
dev_t device; /* device data directory is on */
|
||||||
@ -61,7 +64,7 @@ extern void PGSharedMemoryReAttach(void);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate,
|
extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate,
|
||||||
int port);
|
int port, PGShmemHeader **shim);
|
||||||
extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2);
|
extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2);
|
||||||
extern void PGSharedMemoryDetach(void);
|
extern void PGSharedMemoryDetach(void);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user