summaryrefslogtreecommitdiff
path: root/src/backend/storage/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/ipc')
-rw-r--r--src/backend/storage/ipc/Makefile33
-rw-r--r--src/backend/storage/ipc/README31
-rw-r--r--src/backend/storage/ipc/ipc.c193
-rw-r--r--src/backend/storage/ipc/ipci.c137
-rw-r--r--src/backend/storage/ipc/pmsignal.c83
-rw-r--r--src/backend/storage/ipc/shmem.c379
-rw-r--r--src/backend/storage/ipc/shmqueue.c257
-rw-r--r--src/backend/storage/ipc/sinval.c540
-rw-r--r--src/backend/storage/ipc/sinvaladt.c349
9 files changed, 0 insertions, 2002 deletions
diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile
deleted file mode 100644
index 960097b1d18..00000000000
--- a/src/backend/storage/ipc/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Makefile for storage/ipc
-#
-# $Header: /cvsroot/pgsql/src/backend/storage/ipc/Makefile,v 1.17 2001/11/04 19:55:31 tgl Exp $
-#
-
-subdir = src/backend/storage/ipc
-top_builddir = ../../../..
-include $(top_builddir)/src/Makefile.global
-
-# seems to be required 1999/07/22 bjm
-ifeq "$(findstring alpha,$(host_cpu))" "alpha"
-ifeq "$(GCC)" "yes"
-override CFLAGS+= -fno-inline
-endif
-endif
-
-OBJS = ipc.o ipci.o pmsignal.o shmem.o shmqueue.o sinval.o sinvaladt.o
-
-all: SUBSYS.o
-
-SUBSYS.o: $(OBJS)
- $(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
-
-depend dep:
- $(CC) -MM $(CFLAGS) *.c >depend
-
-clean:
- rm -f SUBSYS.o $(OBJS)
-
-ifeq (depend,$(wildcard depend))
-include depend
-endif
diff --git a/src/backend/storage/ipc/README b/src/backend/storage/ipc/README
deleted file mode 100644
index 02d66045f82..00000000000
--- a/src/backend/storage/ipc/README
+++ /dev/null
@@ -1,31 +0,0 @@
-$Header: /cvsroot/pgsql/src/backend/storage/ipc/README,v 1.1.1.1 1996/07/09 06:21:54 scrappy Exp $
-Mon Jul 18 11:09:22 PDT 1988 W.KLAS
-
-Cache invalidation synchronization routines:
-===========================================
-
-The cache synchronization is done using a message queue. Every
-backend can register a message which then has to be read by
-all backends. A message read by all backends is removed from the
-queue automatically. If a message has been lost because the buffer
-was full, all backends that haven't read this message will be
-noticed that they have to reset their cache state. This is done
-at the time when they try to read the message queue.
-
-The message queue is implemented as a shared buffer segment. Actually,
-the queue is a circle to allow fast inserting, reading (invalidate data) and
-maintaining the buffer.
-
-Access to this shared message buffer is synchronized by the lock manager.
-The lock manager treats the buffer as a regular relation and sets
-relation level locks (with mode = LockWait) to block backends while
-another backend is writing or reading the buffer. The identifiers used
-for this special 'relation' are database id = 0 and relation id = 0.
-
-The current implementation prints regular (e)log information
-when a message has been removed from the buffer because the buffer
-is full, and a backend has to reset its cache state. The elog level
-is NOTICE. This can be used to improve teh behavior of backends
-when invalidating or reseting their cache state.
-
-
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
deleted file mode 100644
index e71bb0c17af..00000000000
--- a/src/backend/storage/ipc/ipc.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * ipc.c
- * POSTGRES inter-process communication definitions.
- *
- * This file is misnamed, as it no longer has much of anything directly
- * to do with IPC. The functionality here is concerned with managing
- * exit-time cleanup for either a postmaster or a backend.
- *
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.80 2002/06/20 20:29:34 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include "miscadmin.h"
-#include "storage/ipc.h"
-
-
-/*
- * This flag is set during proc_exit() to change elog()'s behavior,
- * so that an elog() from an on_proc_exit routine cannot get us out
- * of the exit procedure. We do NOT want to go back to the idle loop...
- */
-bool proc_exit_inprogress = false;
-
-
-/* ----------------------------------------------------------------
- * exit() handling stuff
- *
- * These functions are in generally the same spirit as atexit(2),
- * but provide some additional features we need --- in particular,
- * we want to register callbacks to invoke when we are disconnecting
- * from a broken shared-memory context but not exiting the postmaster.
- *
- * Callback functions can take zero, one, or two args: the first passed
- * arg is the integer exitcode, the second is the Datum supplied when
- * the callback was registered.
- * ----------------------------------------------------------------
- */
-
-#define MAX_ON_EXITS 20
-
-static struct ONEXIT
-{
- void (*function) ();
- Datum arg;
-} on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
-
-static int on_proc_exit_index,
- on_shmem_exit_index;
-
-
-/* ----------------------------------------------------------------
- * proc_exit
- *
- * this function calls all the callbacks registered
- * for it (to free resources) and then calls exit.
- * This should be the only function to call exit().
- * -cim 2/6/90
- * ----------------------------------------------------------------
- */
-void
-proc_exit(int code)
-{
- /*
- * Once we set this flag, we are committed to exit. Any elog() will
- * NOT send control back to the main loop, but right back here.
- */
- proc_exit_inprogress = true;
-
- /*
- * Forget any pending cancel or die requests; we're doing our best to
- * close up shop already. Note that the signal handlers will not set
- * these flags again, now that proc_exit_inprogress is set.
- */
- InterruptPending = false;
- ProcDiePending = false;
- QueryCancelPending = false;
- /* And let's just make *sure* we're not interrupted ... */
- ImmediateInterruptOK = false;
- InterruptHoldoffCount = 1;
- CritSectionCount = 0;
-
- elog(DEBUG2, "proc_exit(%d)", code);
-
- /* do our shared memory exits first */
- shmem_exit(code);
-
- /*
- * call all the callbacks registered before calling exit().
- *
- * Note that since we decrement on_proc_exit_index each time, if a
- * callback calls elog(ERROR) or elog(FATAL) then it won't be invoked
- * again when control comes back here (nor will the
- * previously-completed callbacks). So, an infinite loop should not
- * be possible.
- */
- while (--on_proc_exit_index >= 0)
- (*on_proc_exit_list[on_proc_exit_index].function) (code,
- on_proc_exit_list[on_proc_exit_index].arg);
-
- elog(DEBUG2, "exit(%d)", code);
- exit(code);
-}
-
-/* ------------------
- * Run all of the on_shmem_exit routines --- but don't actually exit.
- * This is used by the postmaster to re-initialize shared memory and
- * semaphores after a backend dies horribly.
- * ------------------
- */
-void
-shmem_exit(int code)
-{
- elog(DEBUG2, "shmem_exit(%d)", code);
-
- /*
- * call all the registered callbacks.
- *
- * As with proc_exit(), we remove each callback from the list before
- * calling it, to avoid infinite loop in case of error.
- */
- while (--on_shmem_exit_index >= 0)
- (*on_shmem_exit_list[on_shmem_exit_index].function) (code,
- on_shmem_exit_list[on_shmem_exit_index].arg);
-
- on_shmem_exit_index = 0;
-}
-
-/* ----------------------------------------------------------------
- * on_proc_exit
- *
- * this function adds a callback function to the list of
- * functions invoked by proc_exit(). -cim 2/6/90
- * ----------------------------------------------------------------
- */
-void
- on_proc_exit(void (*function) (), Datum arg)
-{
- if (on_proc_exit_index >= MAX_ON_EXITS)
- elog(FATAL, "Out of on_proc_exit slots");
-
- on_proc_exit_list[on_proc_exit_index].function = function;
- on_proc_exit_list[on_proc_exit_index].arg = arg;
-
- ++on_proc_exit_index;
-}
-
-/* ----------------------------------------------------------------
- * on_shmem_exit
- *
- * this function adds a callback function to the list of
- * functions invoked by shmem_exit(). -cim 2/6/90
- * ----------------------------------------------------------------
- */
-void
- on_shmem_exit(void (*function) (), Datum arg)
-{
- if (on_shmem_exit_index >= MAX_ON_EXITS)
- elog(FATAL, "Out of on_shmem_exit slots");
-
- on_shmem_exit_list[on_shmem_exit_index].function = function;
- on_shmem_exit_list[on_shmem_exit_index].arg = arg;
-
- ++on_shmem_exit_index;
-}
-
-/* ----------------------------------------------------------------
- * on_exit_reset
- *
- * this function clears all on_proc_exit() and on_shmem_exit()
- * registered functions. This is used just after forking a backend,
- * so that the backend doesn't believe it should call the postmaster's
- * on-exit routines when it exits...
- * ----------------------------------------------------------------
- */
-void
-on_exit_reset(void)
-{
- on_shmem_exit_index = 0;
- on_proc_exit_index = 0;
-}
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
deleted file mode 100644
index 04e4f5bc38e..00000000000
--- a/src/backend/storage/ipc/ipci.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * ipci.c
- * POSTGRES inter-process communication initialization code.
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.48 2002/06/20 20:29:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include <sys/types.h>
-
-#include "miscadmin.h"
-#include "access/clog.h"
-#include "access/xlog.h"
-#include "storage/bufmgr.h"
-#include "storage/freespace.h"
-#include "storage/ipc.h"
-#include "storage/lmgr.h"
-#include "storage/lwlock.h"
-#include "storage/pg_sema.h"
-#include "storage/pg_shmem.h"
-#include "storage/pmsignal.h"
-#include "storage/proc.h"
-#include "storage/sinval.h"
-#include "storage/spin.h"
-
-
-/*
- * CreateSharedMemoryAndSemaphores
- * Creates and initializes shared memory and semaphores.
- *
- * This is called by the postmaster or by a standalone backend.
- * It is NEVER called by a backend forked from the postmaster;
- * for such a backend, the shared memory is already ready-to-go.
- *
- * If "makePrivate" is true then we only need private memory, not shared
- * memory. This is true for a standalone backend, false for a postmaster.
- */
-void
-CreateSharedMemoryAndSemaphores(bool makePrivate,
- int maxBackends,
- int port)
-{
- int size;
- int numSemas;
- PGShmemHeader *seghdr;
-
- /*
- * Size of the Postgres shared-memory block is estimated via
- * moderately-accurate estimates for the big hogs, plus 100K for the
- * stuff that's too small to bother with estimating.
- */
- size = BufferShmemSize();
- size += LockShmemSize(maxBackends);
- size += XLOGShmemSize();
- size += CLOGShmemSize();
- size += LWLockShmemSize();
- size += SInvalShmemSize(maxBackends);
- size += FreeSpaceShmemSize();
-#ifdef STABLE_MEMORY_STORAGE
- size += MMShmemSize();
-#endif
- size += 100000;
- /* might as well round it off to a multiple of a typical page size */
- size += 8192 - (size % 8192);
-
- elog(DEBUG2, "invoking IpcMemoryCreate(size=%d)", size);
-
- /*
- * Create the shmem segment
- */
- seghdr = PGSharedMemoryCreate(size, makePrivate, port);
-
- /*
- * Create semaphores
- */
- numSemas = ProcGlobalSemas(maxBackends);
- numSemas += SpinlockSemas();
- PGReserveSemaphores(numSemas, port);
-
- /*
- * Set up shared memory allocation mechanism
- */
- InitShmemAllocation(seghdr);
-
- /*
- * Now initialize LWLocks, which do shared memory allocation and are
- * needed for InitShmemIndex.
- */
- CreateLWLocks();
-
- /*
- * Set up shmem.c index hashtable
- */
- InitShmemIndex();
-
- /*
- * Set up xlog, clog, and buffers
- */
- XLOGShmemInit();
- CLOGShmemInit();
- InitBufferPool();
-
- /*
- * Set up lock manager
- */
- InitLocks();
- if (InitLockTable(maxBackends) == INVALID_TABLEID)
- elog(FATAL, "Couldn't create the lock table");
-
- /*
- * Set up process table
- */
- InitProcGlobal(maxBackends);
-
- /*
- * Set up shared-inval messaging
- */
- CreateSharedInvalidationState(maxBackends);
-
- /*
- * Set up free-space map
- */
- InitFreeSpaceMap();
-
- /*
- * Set up child-to-postmaster signaling mechanism
- */
- PMSignalInit();
-}
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
deleted file mode 100644
index cf351d1b0d0..00000000000
--- a/src/backend/storage/ipc/pmsignal.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pmsignal.c
- * routines for signaling the postmaster from its child processes
- *
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/pmsignal.c,v 1.4 2002/06/20 20:29:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include <signal.h>
-#include <unistd.h>
-
-#include "miscadmin.h"
-#include "storage/pmsignal.h"
-#include "storage/shmem.h"
-
-
-/*
- * The postmaster is signaled by its children by sending SIGUSR1. The
- * specific reason is communicated via flags in shared memory. We keep
- * a boolean flag for each possible "reason", so that different reasons
- * can be signaled by different backends at the same time. (However,
- * if the same reason is signaled more than once simultaneously, the
- * postmaster will observe it only once.)
- *
- * The flags are actually declared as "volatile sig_atomic_t" for maximum
- * portability. This should ensure that loads and stores of the flag
- * values are atomic, allowing us to dispense with any explicit locking.
- */
-
-static volatile sig_atomic_t *PMSignalFlags;
-
-
-/*
- * PMSignalInit - initialize during shared-memory creation
- */
-void
-PMSignalInit(void)
-{
- PMSignalFlags = (sig_atomic_t *)
- ShmemAlloc(NUM_PMSIGNALS * sizeof(sig_atomic_t));
-
- MemSet(PMSignalFlags, 0, NUM_PMSIGNALS * sizeof(sig_atomic_t));
-}
-
-/*
- * SendPostmasterSignal - signal the postmaster from a child process
- */
-void
-SendPostmasterSignal(PMSignalReason reason)
-{
- /* If called in a standalone backend, do nothing */
- if (!IsUnderPostmaster)
- return;
- /* Atomically set the proper flag */
- PMSignalFlags[reason] = true;
- /* Send signal to postmaster (assume it is our direct parent) */
- kill(getppid(), SIGUSR1);
-}
-
-/*
- * CheckPostmasterSignal - check to see if a particular reason has been
- * signaled, and clear the signal flag. Should be called by postmaster
- * after receiving SIGUSR1.
- */
-bool
-CheckPostmasterSignal(PMSignalReason reason)
-{
- /* Careful here --- don't clear flag if we haven't seen it set */
- if (PMSignalFlags[reason])
- {
- PMSignalFlags[reason] = false;
- return true;
- }
- return false;
-}
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
deleted file mode 100644
index 70dfb833752..00000000000
--- a/src/backend/storage/ipc/shmem.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * shmem.c
- * create shared memory and initialize shared memory data structures.
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.66 2002/06/20 20:29:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-/*
- * POSTGRES processes share one or more regions of shared memory.
- * The shared memory is created by a postmaster and is inherited
- * by each backend via fork(). The routines in this file are used for
- * allocating and binding to shared memory data structures.
- *
- * NOTES:
- * (a) There are three kinds of shared memory data structures
- * available to POSTGRES: fixed-size structures, queues and hash
- * tables. Fixed-size structures contain things like global variables
- * for a module and should never be allocated after the process
- * initialization phase. Hash tables have a fixed maximum size, but
- * their actual size can vary dynamically. When entries are added
- * to the table, more space is allocated. Queues link data structures
- * that have been allocated either as fixed size structures or as hash
- * buckets. Each shared data structure has a string name to identify
- * it (assigned in the module that declares it).
- *
- * (b) During initialization, each module looks for its
- * shared data structures in a hash table called the "Shmem Index".
- * If the data structure is not present, the caller can allocate
- * a new one and initialize it. If the data structure is present,
- * the caller "attaches" to the structure by initializing a pointer
- * in the local address space.
- * The shmem index has two purposes: first, it gives us
- * a simple model of how the world looks when a backend process
- * initializes. If something is present in the shmem index,
- * it is initialized. If it is not, it is uninitialized. Second,
- * the shmem index allows us to allocate shared memory on demand
- * instead of trying to preallocate structures and hard-wire the
- * sizes and locations in header files. If you are using a lot
- * of shared memory in a lot of different places (and changing
- * things during development), this is important.
- *
- * (c) memory allocation model: shared memory can never be
- * freed, once allocated. Each hash table has its own free list,
- * so hash buckets can be reused when an item is deleted. However,
- * if one hash table grows very large and then shrinks, its space
- * cannot be redistributed to other tables. We could build a simple
- * hash bucket garbage collector if need be. Right now, it seems
- * unnecessary.
- *
- * See InitSem() in sem.c for an example of how to use the
- * shmem index.
- */
-
-#include "postgres.h"
-
-#include "access/transam.h"
-#include "storage/pg_shmem.h"
-#include "storage/spin.h"
-#include "utils/tqual.h"
-
-
-/* shared memory global variables */
-
-static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
-
-SHMEM_OFFSET ShmemBase; /* start address of shared memory */
-
-static SHMEM_OFFSET ShmemEnd; /* end+1 address of shared memory */
-
-static slock_t *ShmemLock; /* spinlock for shared memory allocation */
-
-static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
-
-static bool ShmemBootstrap = false; /* bootstrapping shmem index? */
-
-
-/*
- * InitShmemAllocation() --- set up shared-memory allocation.
- *
- * Note: the argument should be declared "PGShmemHeader *seghdr",
- * but we use void to avoid having to include ipc.h in shmem.h.
- */
-void
-InitShmemAllocation(void *seghdr)
-{
- PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;
-
- /* Set up basic pointers to shared memory */
- ShmemSegHdr = shmhdr;
- ShmemBase = (SHMEM_OFFSET) shmhdr;
- ShmemEnd = ShmemBase + shmhdr->totalsize;
-
- /*
- * Initialize the spinlock used by ShmemAlloc. We have to do the
- * space allocation the hard way, since ShmemAlloc can't be called
- * yet.
- */
- ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
- shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
- Assert(shmhdr->freeoffset <= shmhdr->totalsize);
-
- SpinLockInit(ShmemLock);
-
- /* ShmemIndex can't be set up yet (need LWLocks first) */
- ShmemIndex = (HTAB *) NULL;
-
- /*
- * Initialize ShmemVariableCache for transaction manager.
- */
- ShmemVariableCache = (VariableCache)
- ShmemAlloc(sizeof(*ShmemVariableCache));
- memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
-}
-
-/*
- * ShmemAlloc -- allocate max-aligned chunk from shared memory
- *
- * Assumes ShmemLock and ShmemSegHdr are initialized.
- *
- * Returns: real pointer to memory or NULL if we are out
- * of space. Has to return a real pointer in order
- * to be compatible with malloc().
- */
-void *
-ShmemAlloc(Size size)
-{
- uint32 newFree;
- void *newSpace;
- /* use volatile pointer to prevent code rearrangement */
- volatile PGShmemHeader *shmemseghdr = ShmemSegHdr;
-
- /*
- * ensure all space is adequately aligned.
- */
- size = MAXALIGN(size);
-
- Assert(shmemseghdr != NULL);
-
- SpinLockAcquire(ShmemLock);
-
- newFree = shmemseghdr->freeoffset + size;
- if (newFree <= shmemseghdr->totalsize)
- {
- newSpace = (void *) MAKE_PTR(shmemseghdr->freeoffset);
- shmemseghdr->freeoffset = newFree;
- }
- else
- newSpace = NULL;
-
- SpinLockRelease(ShmemLock);
-
- if (!newSpace)
- elog(WARNING, "ShmemAlloc: out of memory");
-
- return newSpace;
-}
-
-/*
- * ShmemIsValid -- test if an offset refers to valid shared memory
- *
- * Returns TRUE if the pointer is valid.
- */
-bool
-ShmemIsValid(unsigned long addr)
-{
- return (addr < ShmemEnd) && (addr >= ShmemBase);
-}
-
-/*
- * InitShmemIndex() --- set up shmem index table.
- */
-void
-InitShmemIndex(void)
-{
- HASHCTL info;
- int hash_flags;
- ShmemIndexEnt *result,
- item;
- bool found;
-
- /*
- * Since ShmemInitHash calls ShmemInitStruct, which expects the
- * ShmemIndex hashtable to exist already, we have a bit of a
- * circularity problem in initializing the ShmemIndex itself. We set
- * ShmemBootstrap to tell ShmemInitStruct to fake it.
- */
- ShmemBootstrap = true;
-
- /* create the shared memory shmem index */
- info.keysize = SHMEM_INDEX_KEYSIZE;
- info.entrysize = sizeof(ShmemIndexEnt);
- hash_flags = HASH_ELEM;
-
- /* This will acquire the shmem index lock, but not release it. */
- ShmemIndex = ShmemInitHash("ShmemIndex",
- SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
- &info, hash_flags);
- if (!ShmemIndex)
- elog(FATAL, "InitShmemIndex: couldn't initialize Shmem Index");
-
- /*
- * Now, create an entry in the hashtable for the index itself.
- */
- MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
- strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE);
-
- result = (ShmemIndexEnt *)
- hash_search(ShmemIndex, (void *) &item, HASH_ENTER, &found);
- if (!result)
- elog(FATAL, "InitShmemIndex: Shmem Index out of memory");
-
- Assert(ShmemBootstrap && !found);
-
- result->location = MAKE_OFFSET(ShmemIndex->hctl);
- result->size = SHMEM_INDEX_SIZE;
-
- ShmemBootstrap = false;
-
- /* now release the lock acquired in ShmemInitStruct */
- LWLockRelease(ShmemIndexLock);
-}
-
-/*
- * ShmemInitHash -- Create/Attach to and initialize
- * shared memory hash table.
- *
- * Notes:
- *
- * assume caller is doing some kind of synchronization
- * so that two people dont try to create/initialize the
- * table at once.
- */
-HTAB *
-ShmemInitHash(const char *name, /* table string name for shmem index */
- long init_size, /* initial table size */
- long max_size, /* max size of the table */
- HASHCTL *infoP, /* info about key and bucket size */
- int hash_flags) /* info about infoP */
-{
- bool found;
- void *location;
-
- /*
- * Hash tables allocated in shared memory have a fixed directory; it
- * can't grow or other backends wouldn't be able to find it. So, make
- * sure we make it big enough to start with.
- *
- * The shared memory allocator must be specified too.
- */
- infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
- infoP->alloc = ShmemAlloc;
- hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE;
-
- /* look it up in the shmem index */
- location = ShmemInitStruct(name,
- sizeof(HASHHDR) + infoP->dsize * sizeof(HASHSEGMENT),
- &found);
-
- /*
- * shmem index is corrupted. Let someone else give the error
- * message since they have more information
- */
- if (location == NULL)
- return NULL;
-
- /*
- * if it already exists, attach to it rather than allocate and
- * initialize new space
- */
- if (found)
- hash_flags |= HASH_ATTACH;
-
- /* Now provide the header and directory pointers */
- infoP->hctl = (HASHHDR *) location;
- infoP->dir = (HASHSEGMENT *) (((char *) location) + sizeof(HASHHDR));
-
- return hash_create(name, init_size, infoP, hash_flags);
-}
-
-/*
- * ShmemInitStruct -- Create/attach to a structure in shared
- * memory.
- *
- * This is called during initialization to find or allocate
- * a data structure in shared memory. If no other processes
- * have created the structure, this routine allocates space
- * for it. If it exists already, a pointer to the existing
- * table is returned.
- *
- * Returns: real pointer to the object. FoundPtr is TRUE if
- * the object is already in the shmem index (hence, already
- * initialized).
- */
-void *
-ShmemInitStruct(const char *name, Size size, bool *foundPtr)
-{
- ShmemIndexEnt *result,
- item;
- void *structPtr;
-
- strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
- item.location = BAD_LOCATION;
-
- LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
-
- if (!ShmemIndex)
- {
- /*
- * If the shmem index doesn't exist, we are bootstrapping: we must
- * be trying to init the shmem index itself.
- *
- * Notice that the ShmemIndexLock is held until the shmem index has
- * been completely initialized.
- */
- Assert(strcmp(name, "ShmemIndex") == 0);
- Assert(ShmemBootstrap);
- *foundPtr = FALSE;
- return ShmemAlloc(size);
- }
-
- /* look it up in the shmem index */
- result = (ShmemIndexEnt *)
- hash_search(ShmemIndex, (void *) &item, HASH_ENTER, foundPtr);
-
- if (!result)
- {
- LWLockRelease(ShmemIndexLock);
- elog(ERROR, "ShmemInitStruct: Shmem Index out of memory");
- return NULL;
- }
-
- if (*foundPtr)
- {
- /*
- * Structure is in the shmem index so someone else has allocated
- * it already. The size better be the same as the size we are
- * trying to initialize to or there is a name conflict (or worse).
- */
- if (result->size != size)
- {
- LWLockRelease(ShmemIndexLock);
-
- elog(WARNING, "ShmemInitStruct: ShmemIndex entry size is wrong");
- /* let caller print its message too */
- return NULL;
- }
- structPtr = (void *) MAKE_PTR(result->location);
- }
- else
- {
- /* It isn't in the table yet. allocate and initialize it */
- structPtr = ShmemAlloc(size);
- if (!structPtr)
- {
- /* out of memory */
- Assert(ShmemIndex);
- hash_search(ShmemIndex, (void *) &item, HASH_REMOVE, NULL);
- LWLockRelease(ShmemIndexLock);
-
- elog(WARNING, "ShmemInitStruct: cannot allocate '%s'",
- name);
- *foundPtr = FALSE;
- return NULL;
- }
- result->size = size;
- result->location = MAKE_OFFSET(structPtr);
- }
- Assert(ShmemIsValid((unsigned long) structPtr));
-
- LWLockRelease(ShmemIndexLock);
- return structPtr;
-}
diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c
deleted file mode 100644
index bbd98038ef1..00000000000
--- a/src/backend/storage/ipc/shmqueue.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * shmqueue.c
- * shared memory linked lists
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.21 2002/06/20 20:29:35 momjian Exp $
- *
- * NOTES
- *
- * Package for managing doubly-linked lists in shared memory.
- * The only tricky thing is that SHM_QUEUE will usually be a field
- * in a larger record. SHMQueueNext has to return a pointer
- * to the record itself instead of a pointer to the SHMQueue field
- * of the record. It takes an extra parameter and does some extra
- * pointer arithmetic to do this correctly.
- *
- * NOTE: These are set up so they can be turned into macros some day.
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "storage/shmem.h"
-
-/*#define SHMQUEUE_DEBUG*/
-#ifdef SHMQUEUE_DEBUG
-
-#define SHMQUEUE_DEBUG_ELOG WARNING
-
-static void dumpQ(SHM_QUEUE *q, char *s);
-#endif
-
-
-/*
- * ShmemQueueInit -- make the head of a new queue point
- * to itself
- */
-void
-SHMQueueInit(SHM_QUEUE *queue)
-{
- Assert(SHM_PTR_VALID(queue));
- (queue)->prev = (queue)->next = MAKE_OFFSET(queue);
-}
-
-/*
- * SHMQueueIsDetached -- TRUE if element is not currently
- * in a queue.
- */
-#ifdef NOT_USED
-bool
-SHMQueueIsDetached(SHM_QUEUE *queue)
-{
- Assert(SHM_PTR_VALID(queue));
- return (queue)->prev == INVALID_OFFSET;
-}
-#endif
-
-/*
- * SHMQueueElemInit -- clear an element's links
- */
-void
-SHMQueueElemInit(SHM_QUEUE *queue)
-{
- Assert(SHM_PTR_VALID(queue));
- (queue)->prev = (queue)->next = INVALID_OFFSET;
-}
-
-/*
- * SHMQueueDelete -- remove an element from the queue and
- * close the links
- */
-void
-SHMQueueDelete(SHM_QUEUE *queue)
-{
- SHM_QUEUE *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
- SHM_QUEUE *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(nextElem));
- Assert(SHM_PTR_VALID(prevElem));
-
-#ifdef SHMQUEUE_DEBUG
- dumpQ(queue, "in SHMQueueDelete: begin");
-#endif
-
- prevElem->next = (queue)->next;
- nextElem->prev = (queue)->prev;
-
- (queue)->prev = (queue)->next = INVALID_OFFSET;
-}
-
-/*
- * SHMQueueInsertBefore -- put elem in queue before the given queue
- * element. Inserting "before" the queue head puts the elem
- * at the tail of the queue.
- */
-void
-SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
-{
- SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
- SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(elem));
-
-#ifdef SHMQUEUE_DEBUG
- dumpQ(queue, "in SHMQueueInsertBefore: begin");
-#endif
-
- (elem)->next = prevPtr->next;
- (elem)->prev = queue->prev;
- (queue)->prev = elemOffset;
- prevPtr->next = elemOffset;
-
-#ifdef SHMQUEUE_DEBUG
- dumpQ(queue, "in SHMQueueInsertBefore: end");
-#endif
-}
-
-/*
- * SHMQueueInsertAfter -- put elem in queue after the given queue
- * element. Inserting "after" the queue head puts the elem
- * at the head of the queue.
- */
-#ifdef NOT_USED
-void
-SHMQueueInsertAfter(SHM_QUEUE *queue, SHM_QUEUE *elem)
-{
- SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
- SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(elem));
-
-#ifdef SHMQUEUE_DEBUG
- dumpQ(queue, "in SHMQueueInsertAfter: begin");
-#endif
-
- (elem)->prev = nextPtr->prev;
- (elem)->next = queue->next;
- (queue)->next = elemOffset;
- nextPtr->prev = elemOffset;
-
-#ifdef SHMQUEUE_DEBUG
- dumpQ(queue, "in SHMQueueInsertAfter: end");
-#endif
-}
-#endif /* NOT_USED */
-
-/*--------------------
- * SHMQueueNext -- Get the next element from a queue
- *
- * To start the iteration, pass the queue head as both queue and curElem.
- * Returns NULL if no more elements.
- *
- * Next element is at curElem->next. If SHMQueue is part of
- * a larger structure, we want to return a pointer to the
- * whole structure rather than a pointer to its SHMQueue field.
- * I.E. struct {
- * int stuff;
- * SHMQueue elem;
- * } ELEMType;
- * When this element is in a queue, (prevElem->next) is struct.elem.
- * We subtract linkOffset to get the correct start address of the structure.
- *
- * calls to SHMQueueNext should take these parameters:
- *
- * &(queueHead), &(queueHead), offsetof(ELEMType, elem)
- * or
- * &(queueHead), &(curElem->elem), offsetof(ELEMType, elem)
- *--------------------
- */
-Pointer
-SHMQueueNext(SHM_QUEUE *queue, SHM_QUEUE *curElem, Size linkOffset)
-{
- SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((curElem)->next);
-
- Assert(SHM_PTR_VALID(curElem));
-
- if (elemPtr == queue) /* back to the queue head? */
- return NULL;
-
- return (Pointer) (((char *) elemPtr) - linkOffset);
-}
-
-/*
- * SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise
- */
-bool
-SHMQueueEmpty(SHM_QUEUE *queue)
-{
- Assert(SHM_PTR_VALID(queue));
-
- if (queue->prev == MAKE_OFFSET(queue))
- {
- Assert(queue->next = MAKE_OFFSET(queue));
- return TRUE;
- }
- return FALSE;
-}
-
-#ifdef SHMQUEUE_DEBUG
-
-static void
-dumpQ(SHM_QUEUE *q, char *s)
-{
- char elem[NAMEDATALEN];
- char buf[1024];
- SHM_QUEUE *start = q;
- int count = 0;
-
- sprintf(buf, "q prevs: %lx", MAKE_OFFSET(q));
- q = (SHM_QUEUE *) MAKE_PTR(q->prev);
- while (q != start)
- {
- sprintf(elem, "--->%lx", MAKE_OFFSET(q));
- strcat(buf, elem);
- q = (SHM_QUEUE *) MAKE_PTR(q->prev);
- if (q->prev == MAKE_OFFSET(q))
- break;
- if (count++ > 40)
- {
- strcat(buf, "BAD PREV QUEUE!!");
- break;
- }
- }
- sprintf(elem, "--->%lx", MAKE_OFFSET(q));
- strcat(buf, elem);
- elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
-
- sprintf(buf, "q nexts: %lx", MAKE_OFFSET(q));
- count = 0;
- q = (SHM_QUEUE *) MAKE_PTR(q->next);
- while (q != start)
- {
- sprintf(elem, "--->%lx", MAKE_OFFSET(q));
- strcat(buf, elem);
- q = (SHM_QUEUE *) MAKE_PTR(q->next);
- if (q->next == MAKE_OFFSET(q))
- break;
- if (count++ > 10)
- {
- strcat(buf, "BAD NEXT QUEUE!!");
- break;
- }
- }
- sprintf(elem, "--->%lx", MAKE_OFFSET(q));
- strcat(buf, elem);
- elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
-}
-
-#endif /* SHMQUEUE_DEBUG */
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
deleted file mode 100644
index 940ab32b331..00000000000
--- a/src/backend/storage/ipc/sinval.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * sinval.c
- * POSTGRES shared cache invalidation communication code.
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.49 2002/06/20 20:29:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include <sys/types.h>
-
-#include "storage/proc.h"
-#include "storage/sinval.h"
-#include "storage/sinvaladt.h"
-#include "utils/tqual.h"
-#include "miscadmin.h"
-
-
-/****************************************************************************/
-/* CreateSharedInvalidationState() Initialize SI buffer */
-/* */
-/* should be called only by the POSTMASTER */
-/****************************************************************************/
-void
-CreateSharedInvalidationState(int maxBackends)
-{
- /* SInvalLock must be initialized already, during LWLock init */
- SIBufferInit(maxBackends);
-}
-
-/*
- * InitBackendSharedInvalidationState
- * Initialize new backend's state info in buffer segment.
- */
-void
-InitBackendSharedInvalidationState(void)
-{
- int flag;
-
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
- flag = SIBackendInit(shmInvalBuffer);
- LWLockRelease(SInvalLock);
- if (flag < 0) /* unexpected problem */
- elog(FATAL, "Backend cache invalidation initialization failed");
- if (flag == 0) /* expected problem: MaxBackends exceeded */
- elog(FATAL, "Sorry, too many clients already");
-}
-
-/*
- * SendSharedInvalidMessage
- * Add a shared-cache-invalidation message to the global SI message queue.
- */
-void
-SendSharedInvalidMessage(SharedInvalidationMessage *msg)
-{
- bool insertOK;
-
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
- insertOK = SIInsertDataEntry(shmInvalBuffer, msg);
- LWLockRelease(SInvalLock);
- if (!insertOK)
- elog(DEBUG3, "SendSharedInvalidMessage: SI buffer overflow");
-}
-
-/*
- * ReceiveSharedInvalidMessages
- * Process shared-cache-invalidation messages waiting for this backend
- */
-void
-ReceiveSharedInvalidMessages(
- void (*invalFunction) (SharedInvalidationMessage *msg),
- void (*resetFunction) (void))
-{
- SharedInvalidationMessage data;
- int getResult;
- bool gotMessage = false;
-
- for (;;)
- {
- /*
- * We can run SIGetDataEntry in parallel with other backends
- * running SIGetDataEntry for themselves, since each instance will
- * modify only fields of its own backend's ProcState, and no
- * instance will look at fields of other backends' ProcStates. We
- * express this by grabbing SInvalLock in shared mode. Note that
- * this is not exactly the normal (read-only) interpretation of a
- * shared lock! Look closely at the interactions before allowing
- * SInvalLock to be grabbed in shared mode for any other reason!
- *
- * The routines later in this file that use shared mode are okay with
- * this, because they aren't looking at the ProcState fields
- * associated with SI message transfer; they only use the
- * ProcState array as an easy way to find all the PGPROC structures.
- */
- LWLockAcquire(SInvalLock, LW_SHARED);
- getResult = SIGetDataEntry(shmInvalBuffer, MyBackendId, &data);
- LWLockRelease(SInvalLock);
-
- if (getResult == 0)
- break; /* nothing more to do */
- if (getResult < 0)
- {
- /* got a reset message */
- elog(DEBUG3, "ReceiveSharedInvalidMessages: cache state reset");
- resetFunction();
- }
- else
- {
- /* got a normal data message */
- invalFunction(&data);
- }
- gotMessage = true;
- }
-
- /* If we got any messages, try to release dead messages */
- if (gotMessage)
- {
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
- SIDelExpiredDataEntries(shmInvalBuffer);
- LWLockRelease(SInvalLock);
- }
-}
-
-
-/****************************************************************************/
-/* Functions that need to scan the PGPROC structures of all running backends. */
-/* It's a bit strange to keep these in sinval.c, since they don't have any */
-/* direct relationship to shared-cache invalidation. But the procState */
-/* array in the SI segment is the only place in the system where we have */
-/* an array of per-backend data, so it is the most convenient place to keep */
-/* pointers to the backends' PGPROC structures. We used to implement these */
-/* functions with a slow, ugly search through the ShmemIndex hash table --- */
-/* now they are simple loops over the SI ProcState array. */
-/****************************************************************************/
-
-
-/*
- * DatabaseHasActiveBackends -- are there any backends running in the given DB
- *
- * If 'ignoreMyself' is TRUE, ignore this particular backend while checking
- * for backends in the target database.
- *
- * This function is used to interlock DROP DATABASE against there being
- * any active backends in the target DB --- dropping the DB while active
- * backends remain would be a Bad Thing. Note that we cannot detect here
- * the possibility of a newly-started backend that is trying to connect
- * to the doomed database, so additional interlocking is needed during
- * backend startup.
- */
-
-bool
-DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
-{
- bool result = false;
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc->databaseId == databaseId)
- {
- if (ignoreMyself && proc == MyProc)
- continue;
-
- result = true;
- break;
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*
- * TransactionIdIsInProgress -- is given transaction running by some backend
- */
-bool
-TransactionIdIsInProgress(TransactionId xid)
-{
- bool result = false;
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId pxid = proc->xid;
-
- if (TransactionIdEquals(pxid, xid))
- {
- result = true;
- break;
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*
- * GetOldestXmin -- returns oldest transaction that was running
- * when any current transaction was started.
- *
- * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
- * then only backends running in my own database are considered.
- *
- * This is used by VACUUM to decide which deleted tuples must be preserved
- * in a table. allDbs = TRUE is needed for shared relations, but allDbs =
- * FALSE is sufficient for non-shared relations, since only backends in my
- * own database could ever see the tuples in them.
- *
- * Note: we include the currently running xids in the set of considered xids.
- * This ensures that if a just-started xact has not yet set its snapshot,
- * when it does set the snapshot it cannot set xmin less than what we compute.
- */
-TransactionId
-GetOldestXmin(bool allDbs)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- TransactionId result;
- int index;
-
- result = GetCurrentTransactionId();
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (allDbs || proc->databaseId == MyDatabaseId)
- {
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId xid = proc->xid;
-
- if (TransactionIdIsNormal(xid))
- {
- if (TransactionIdPrecedes(xid, result))
- result = xid;
- xid = proc->xmin;
- if (TransactionIdIsNormal(xid))
- if (TransactionIdPrecedes(xid, result))
- result = xid;
- }
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*----------
- * GetSnapshotData -- returns information about running transactions.
- *
- * The returned snapshot includes xmin (lowest still-running xact ID),
- * xmax (next xact ID to be assigned), and a list of running xact IDs
- * in the range xmin <= xid < xmax. It is used as follows:
- * All xact IDs < xmin are considered finished.
- * All xact IDs >= xmax are considered still running.
- * For an xact ID xmin <= xid < xmax, consult list to see whether
- * it is considered running or not.
- * This ensures that the set of transactions seen as "running" by the
- * current xact will not change after it takes the snapshot.
- *
- * Also, we compute the current global xmin (oldest xmin across all running
- * transactions) and save it in RecentGlobalXmin. This is the same
- * computation done by GetOldestXmin(TRUE).
- *----------
- */
-Snapshot
-GetSnapshotData(bool serializable)
-{
- Snapshot snapshot = (Snapshot) malloc(sizeof(SnapshotData));
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- TransactionId xmin;
- TransactionId xmax;
- TransactionId globalxmin;
- int index;
- int count = 0;
-
- if (snapshot == NULL)
- elog(ERROR, "Memory exhausted in GetSnapshotData");
-
- /*
- * Allocating space for MaxBackends xids is usually overkill;
- * lastBackend would be sufficient. But it seems better to do the
- * malloc while not holding the lock, so we can't look at lastBackend.
- */
- snapshot->xip = (TransactionId *)
- malloc(MaxBackends * sizeof(TransactionId));
- if (snapshot->xip == NULL)
- elog(ERROR, "Memory exhausted in GetSnapshotData");
-
- globalxmin = xmin = GetCurrentTransactionId();
-
- /*
- * If we are going to set MyProc->xmin then we'd better get exclusive
- * lock; if not, this is a read-only operation so it can be shared.
- */
- LWLockAcquire(SInvalLock, serializable ? LW_EXCLUSIVE : LW_SHARED);
-
- /*--------------------
- * Unfortunately, we have to call ReadNewTransactionId() after acquiring
- * SInvalLock above. It's not good because ReadNewTransactionId() does
- * LWLockAcquire(XidGenLock), but *necessary*. We need to be sure that
- * no transactions exit the set of currently-running transactions
- * between the time we fetch xmax and the time we finish building our
- * snapshot. Otherwise we could have a situation like this:
- *
- * 1. Tx Old is running (in Read Committed mode).
- * 2. Tx S reads new transaction ID into xmax, then
- * is swapped out before acquiring SInvalLock.
- * 3. Tx New gets new transaction ID (>= S' xmax),
- * makes changes and commits.
- * 4. Tx Old changes some row R changed by Tx New and commits.
- * 5. Tx S finishes getting its snapshot data. It sees Tx Old as
- * done, but sees Tx New as still running (since New >= xmax).
- *
- * Now S will see R changed by both Tx Old and Tx New, *but* does not
- * see other changes made by Tx New. If S is supposed to be in
- * Serializable mode, this is wrong.
- *
- * By locking SInvalLock before we read xmax, we ensure that TX Old
- * cannot exit the set of running transactions seen by Tx S. Therefore
- * both Old and New will be seen as still running => no inconsistency.
- *--------------------
- */
-
- xmax = ReadNewTransactionId();
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId xid = proc->xid;
-
- /*
- * Ignore my own proc (dealt with my xid above), procs not
- * running a transaction, and xacts started since we read the
- * next transaction ID. There's no need to store XIDs above
- * what we got from ReadNewTransactionId, since we'll treat
- * them as running anyway. We also assume that such xacts can't
- * compute an xmin older than ours, so they needn't be considered
- * in computing globalxmin.
- */
- if (proc == MyProc ||
- !TransactionIdIsNormal(xid) ||
- TransactionIdFollowsOrEquals(xid, xmax))
- continue;
-
- if (TransactionIdPrecedes(xid, xmin))
- xmin = xid;
- snapshot->xip[count] = xid;
- count++;
-
- /* Update globalxmin to be the smallest valid xmin */
- xid = proc->xmin;
- if (TransactionIdIsNormal(xid))
- if (TransactionIdPrecedes(xid, globalxmin))
- globalxmin = xid;
- }
- }
-
- if (serializable)
- MyProc->xmin = xmin;
-
- LWLockRelease(SInvalLock);
-
- /* Serializable snapshot must be computed before any other... */
- Assert(TransactionIdIsValid(MyProc->xmin));
-
- /*
- * Update globalxmin to include actual process xids. This is a slightly
- * different way of computing it than GetOldestXmin uses, but should give
- * the same result.
- */
- if (TransactionIdPrecedes(xmin, globalxmin))
- globalxmin = xmin;
-
- RecentGlobalXmin = globalxmin;
-
- snapshot->xmin = xmin;
- snapshot->xmax = xmax;
- snapshot->xcnt = count;
-
- snapshot->curcid = GetCurrentCommandId();
-
- return snapshot;
-}
-
-/*
- * CountActiveBackends --- count backends (other than myself) that are in
- * active transactions. This is used as a heuristic to decide if
- * a pre-XLOG-flush delay is worthwhile during commit.
- *
- * An active transaction is something that has written at least one XLOG
- * record; read-only transactions don't count. Also, do not count backends
- * that are blocked waiting for locks, since they are not going to get to
- * run until someone else commits.
- */
-int
-CountActiveBackends(void)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int count = 0;
- int index;
-
- /*
- * Note: for speed, we don't acquire SInvalLock. This is a little bit
- * bogus, but since we are only testing xrecoff for zero or nonzero,
- * it should be OK. The result is only used for heuristic purposes
- * anyway...
- */
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc == MyProc)
- continue; /* do not count myself */
- if (proc->logRec.xrecoff == 0)
- continue; /* do not count if not in a transaction */
- if (proc->waitLock != NULL)
- continue; /* do not count if blocked on a lock */
- count++;
- }
- }
-
- return count;
-}
-
-/*
- * GetUndoRecPtr -- returns oldest PGPROC->logRec.
- */
-XLogRecPtr
-GetUndoRecPtr(void)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- XLogRecPtr urec = {0, 0};
- XLogRecPtr tempr;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- tempr = proc->logRec;
- if (tempr.xrecoff == 0)
- continue;
- if (urec.xrecoff != 0 && XLByteLT(urec, tempr))
- continue;
- urec = tempr;
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return (urec);
-}
-
-/*
- * BackendIdGetProc - given a BackendId, find its PGPROC structure
- *
- * This is a trivial lookup in the ProcState array. We assume that the caller
- * knows that the backend isn't going to go away, so we do not bother with
- * locking.
- */
-struct PGPROC *
-BackendIdGetProc(BackendId procId)
-{
- SISeg *segP = shmInvalBuffer;
-
- if (procId > 0 && procId <= segP->lastBackend)
- {
- ProcState *stateP = &segP->procState[procId - 1];
- SHMEM_OFFSET pOffset = stateP->procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- return proc;
- }
- }
-
- return NULL;
-}
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
deleted file mode 100644
index c88055c07b5..00000000000
--- a/src/backend/storage/ipc/sinvaladt.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * sinvaladt.c
- * POSTGRES shared cache invalidation segment definitions.
- *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.47 2002/06/20 20:29:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "miscadmin.h"
-#include "storage/backendid.h"
-#include "storage/ipc.h"
-#include "storage/pmsignal.h"
-#include "storage/proc.h"
-#include "storage/sinvaladt.h"
-
-SISeg *shmInvalBuffer;
-
-static void CleanupInvalidationState(int status, Datum arg);
-static void SISetProcStateInvalid(SISeg *segP);
-
-
-/*
- * SInvalShmemSize --- return shared-memory space needed
- */
-int
-SInvalShmemSize(int maxBackends)
-{
- /*
- * Figure space needed. Note sizeof(SISeg) includes the first
- * ProcState entry.
- */
- return sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
-}
-
-/*
- * SIBufferInit
- * Create and initialize a new SI message buffer
- */
-void
-SIBufferInit(int maxBackends)
-{
- int segSize;
- SISeg *segP;
- int i;
-
- /* Allocate space in shared memory */
- segSize = SInvalShmemSize(maxBackends);
- shmInvalBuffer = segP = (SISeg *) ShmemAlloc(segSize);
-
- /* Clear message counters, save size of procState array */
- segP->minMsgNum = 0;
- segP->maxMsgNum = 0;
- segP->lastBackend = 0;
- segP->maxBackends = maxBackends;
-
- /* The buffer[] array is initially all unused, so we need not fill it */
-
- /* Mark all backends inactive */
- for (i = 0; i < maxBackends; i++)
- {
- segP->procState[i].nextMsgNum = -1; /* inactive */
- segP->procState[i].resetState = false;
- segP->procState[i].procStruct = INVALID_OFFSET;
- }
-}
-
-/*
- * SIBackendInit
- * Initialize a new backend to operate on the sinval buffer
- *
- * Returns:
- * >0 A-OK
- * 0 Failed to find a free procState slot (ie, MaxBackends exceeded)
- * <0 Some other failure (not currently used)
- *
- * NB: this routine, and all following ones, must be executed with the
- * SInvalLock lock held, since there may be multiple backends trying
- * to access the buffer.
- */
-int
-SIBackendInit(SISeg *segP)
-{
- int index;
- ProcState *stateP = NULL;
-
- /* Look for a free entry in the procState array */
- for (index = 0; index < segP->lastBackend; index++)
- {
- if (segP->procState[index].nextMsgNum < 0) /* inactive slot? */
- {
- stateP = &segP->procState[index];
- break;
- }
- }
-
- if (stateP == NULL)
- {
- if (segP->lastBackend < segP->maxBackends)
- {
- stateP = &segP->procState[segP->lastBackend];
- Assert(stateP->nextMsgNum < 0);
- segP->lastBackend++;
- }
- else
- {
- /* out of procState slots */
- MyBackendId = InvalidBackendId;
- return 0;
- }
- }
-
- MyBackendId = (stateP - &segP->procState[0]) + 1;
-
-#ifdef INVALIDDEBUG
- elog(DEBUG1, "SIBackendInit: backend id %d", MyBackendId);
-#endif /* INVALIDDEBUG */
-
- /* mark myself active, with all extant messages already read */
- stateP->nextMsgNum = segP->maxMsgNum;
- stateP->resetState = false;
- stateP->procStruct = MAKE_OFFSET(MyProc);
-
- /* register exit routine to mark my entry inactive at exit */
- on_shmem_exit(CleanupInvalidationState, PointerGetDatum(segP));
-
- return 1;
-}
-
-/*
- * CleanupInvalidationState
- * Mark the current backend as no longer active.
- *
- * This function is called via on_shmem_exit() during backend shutdown,
- * so the caller has NOT acquired the lock for us.
- *
- * arg is really of type "SISeg*".
- */
-static void
-CleanupInvalidationState(int status, Datum arg)
-{
- SISeg *segP = (SISeg *) DatumGetPointer(arg);
- int i;
-
- Assert(PointerIsValid(segP));
-
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
-
- /* Mark myself inactive */
- segP->procState[MyBackendId - 1].nextMsgNum = -1;
- segP->procState[MyBackendId - 1].resetState = false;
- segP->procState[MyBackendId - 1].procStruct = INVALID_OFFSET;
-
- /* Recompute index of last active backend */
- for (i = segP->lastBackend; i > 0; i--)
- {
- if (segP->procState[i - 1].nextMsgNum >= 0)
- break;
- }
- segP->lastBackend = i;
-
- LWLockRelease(SInvalLock);
-}
-
-/*
- * SIInsertDataEntry
- * Add a new invalidation message to the buffer.
- *
- * If we are unable to insert the message because the buffer is full,
- * then clear the buffer and assert the "reset" flag to each backend.
- * This will cause all the backends to discard *all* invalidatable state.
- *
- * Returns true for normal successful insertion, false if had to reset.
- */
-bool
-SIInsertDataEntry(SISeg *segP, SharedInvalidationMessage *data)
-{
- int numMsgs = segP->maxMsgNum - segP->minMsgNum;
-
- /* Is the buffer full? */
- if (numMsgs >= MAXNUMMESSAGES)
- {
- /*
- * Don't panic just yet: slowest backend might have consumed some
- * messages but not yet have done SIDelExpiredDataEntries() to
- * advance minMsgNum. So, make sure minMsgNum is up-to-date.
- */
- SIDelExpiredDataEntries(segP);
- numMsgs = segP->maxMsgNum - segP->minMsgNum;
- if (numMsgs >= MAXNUMMESSAGES)
- {
- /* Yup, it's definitely full, no choice but to reset */
- SISetProcStateInvalid(segP);
- return false;
- }
- }
-
- /*
- * Try to prevent table overflow. When the table is 70% full send a
- * WAKEN_CHILDREN request to the postmaster. The postmaster will send
- * a SIGUSR2 signal (ordinarily a NOTIFY signal) to all the backends.
- * This will force idle backends to execute a transaction to look
- * through pg_listener for NOTIFY messages, and as a byproduct of the
- * transaction start they will read SI entries.
- *
- * This should never happen if all the backends are actively executing
- * queries, but if a backend is sitting idle then it won't be starting
- * transactions and so won't be reading SI entries.
- *
- * dz - 27 Jan 1998
- */
- if (numMsgs == (MAXNUMMESSAGES * 70 / 100) &&
- IsUnderPostmaster)
- {
- elog(DEBUG3, "SIInsertDataEntry: table is 70%% full, signaling postmaster");
- SendPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN);
- }
-
- /*
- * Insert new message into proper slot of circular buffer
- */
- segP->buffer[segP->maxMsgNum % MAXNUMMESSAGES] = *data;
- segP->maxMsgNum++;
-
- return true;
-}
-
-/*
- * SISetProcStateInvalid
- * Flush pending messages from buffer, assert reset flag for each backend
- *
- * This is used only to recover from SI buffer overflow.
- */
-static void
-SISetProcStateInvalid(SISeg *segP)
-{
- int i;
-
- segP->minMsgNum = 0;
- segP->maxMsgNum = 0;
-
- for (i = 0; i < segP->lastBackend; i++)
- {
- if (segP->procState[i].nextMsgNum >= 0) /* active backend? */
- {
- segP->procState[i].resetState = true;
- segP->procState[i].nextMsgNum = 0;
- }
- }
-}
-
-/*
- * SIGetDataEntry
- * get next SI message for specified backend, if there is one
- *
- * Possible return values:
- * 0: no SI message available
- * 1: next SI message has been extracted into *data
- * (there may be more messages available after this one!)
- * -1: SI reset message extracted
- *
- * NB: this can run in parallel with other instances of SIGetDataEntry
- * executing on behalf of other backends. See comments in sinval.c in
- * ReceiveSharedInvalidMessages().
- */
-int
-SIGetDataEntry(SISeg *segP, int backendId,
- SharedInvalidationMessage *data)
-{
- ProcState *stateP = &segP->procState[backendId - 1];
-
- if (stateP->resetState)
- {
- /*
- * Force reset. We can say we have dealt with any messages added
- * since the reset, as well...
- */
- stateP->resetState = false;
- stateP->nextMsgNum = segP->maxMsgNum;
- return -1;
- }
-
- if (stateP->nextMsgNum >= segP->maxMsgNum)
- return 0; /* nothing to read */
-
- /*
- * Retrieve message and advance my counter.
- */
- *data = segP->buffer[stateP->nextMsgNum % MAXNUMMESSAGES];
- stateP->nextMsgNum++;
-
- /*
- * There may be other backends that haven't read the message, so we
- * cannot delete it here. SIDelExpiredDataEntries() should be called
- * to remove dead messages.
- */
- return 1; /* got a message */
-}
-
-/*
- * SIDelExpiredDataEntries
- * Remove messages that have been consumed by all active backends
- */
-void
-SIDelExpiredDataEntries(SISeg *segP)
-{
- int min,
- i,
- h;
-
- min = segP->maxMsgNum;
- if (min == segP->minMsgNum)
- return; /* fast path if no messages exist */
-
- /* Recompute minMsgNum = minimum of all backends' nextMsgNum */
-
- for (i = 0; i < segP->lastBackend; i++)
- {
- h = segP->procState[i].nextMsgNum;
- if (h >= 0)
- { /* backend active */
- if (h < min)
- min = h;
- }
- }
- segP->minMsgNum = min;
-
- /*
- * When minMsgNum gets really large, decrement all message counters so
- * as to forestall overflow of the counters.
- */
- if (min >= MSGNUMWRAPAROUND)
- {
- segP->minMsgNum -= MSGNUMWRAPAROUND;
- segP->maxMsgNum -= MSGNUMWRAPAROUND;
- for (i = 0; i < segP->lastBackend; i++)
- {
- if (segP->procState[i].nextMsgNum >= 0)
- segP->procState[i].nextMsgNum -= MSGNUMWRAPAROUND;
- }
- }
-}