shmem.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:20k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * shmem.c
  4.  *   create shared memory and initialize shared memory data structures.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.42 1999/06/06 20:19:35 vadim Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15.  * POSTGRES processes share one or more regions of shared memory.
  16.  * The shared memory is created by a postmaster and is inherited
  17.  * by each backends via fork().  The routines in this file are used for
  18.  * allocating and binding to shared memory data structures.
  19.  *
  20.  * NOTES:
  21.  * (a) There are three kinds of shared memory data structures
  22.  * available to POSTGRES: fixed-size structures, queues and hash
  23.  * tables.  Fixed-size structures contain things like global variables
  24.  * for a module and should never be allocated after the process
  25.  * initialization phase.  Hash tables have a fixed maximum size, but
  26.  * their actual size can vary dynamically.  When entries are added
  27.  * to the table, more space is allocated. Queues link data structures
  28.  * that have been allocated either as fixed size structures or as hash
  29.  * buckets.  Each shared data structure has a string name to identify
  30.  * it (assigned in the module that declares it).
  31.  *
  32.  * (b) During initialization, each module looks for its
  33.  * shared data structures in a hash table called the "Shmem Index".
  34.  * If the data structure is not present, the caller can allocate
  35.  * a new one and initialize it.  If the data structure is present,
  36.  * the caller "attaches" to the structure by initializing a pointer
  37.  * in the local address space.
  38.  * The shmem index has two purposes: first, it gives us
  39.  * a simple model of how the world looks when a backend process
  40.  * initializes.  If something is present in the shmem index,
  41.  * it is initialized. If it is not, it is uninitialized. Second,
  42.  * the shmem index allows us to allocate shared memory on demand
  43.  * instead of trying to preallocate structures and hard-wire the
  44.  * sizes and locations in header files.  If you are using a lot
  45.  * of shared memory in a lot of different places (and changing
  46.  * things during development), this is important.
  47.  *
  48.  * (c) memory allocation model: shared memory can never be
  49.  * freed, once allocated.  Each hash table has its own free list,
  50.  * so hash buckets can be reused when an item is deleted. However,
  51.  * if one hash table grows very large and then shrinks, its space
  52.  * cannot be redistributed to other tables.  We could build a simple
  53.  * hash bucket garbage collector if need be.  Right now, it seems
  54.  * unnecessary.
  55.  *
  56.  * See InitSem() in sem.c for an example of how to use the
  57.  * shmem index.
  58.  *
  59.  */
  60. #include <stdio.h>
  61. #include <string.h>
  62. #include "postgres.h"
  63. #include "storage/ipc.h"
  64. #include "storage/shmem.h"
  65. #include "storage/spin.h"
  66. #include "storage/proc.h"
  67. #include "utils/hsearch.h"
  68. #include "utils/memutils.h"
  69. #include "access/xact.h"
  70. #include "utils/tqual.h"
  71. /* shared memory global variables */
  72. unsigned long ShmemBase = 0; /* start and end address of shared memory */
  73. static unsigned long ShmemEnd = 0;
  74. static unsigned long ShmemSize = 0; /* current size (and default) */
  75. extern VariableCache ShmemVariableCache; /* varsup.c */
  76. SPINLOCK ShmemLock; /* lock for shared memory allocation */
  77. SPINLOCK ShmemIndexLock; /* lock for shmem index access */
  78. static unsigned long *ShmemFreeStart = NULL; /* pointer to the OFFSET
  79.  * of first free shared
  80.  * memory */
  81. static unsigned long *ShmemIndexOffset = NULL; /* start of the shmem
  82.  * index table (for
  83.  * bootstrap) */
  84. static int ShmemBootstrap = FALSE; /* flag becomes true when shared
  85.  * mem is created by POSTMASTER */
  86. static HTAB *ShmemIndex = NULL;
  87. /* ---------------------
  88.  * ShmemIndexReset() - Resets the shmem index to NULL....
  89.  * useful when the postmaster destroys existing shared memory
  90.  * and creates all new segments after a backend crash.
  91.  * ----------------------
  92.  */
  93. void
  94. ShmemIndexReset(void)
  95. {
  96. ShmemIndex = (HTAB *) NULL;
  97. }
  98. /*
  99.  * CreateSharedRegion()
  100.  *
  101.  * This routine is called once by the postmaster to
  102.  * initialize the shared buffer pool. Assume there is
  103.  * only one postmaster so no synchronization is necessary
  104.  * until after this routine completes successfully.
  105.  *
  106.  * key is a unique identifier for the shmem region.
  107.  * size is the size of the region.
  108.  */
  109. static IpcMemoryId ShmemId;
  110. void
  111. ShmemCreate(unsigned int key, unsigned int size)
  112. {
  113. if (size)
  114. ShmemSize = size;
  115. /* create shared mem region */
  116. if ((ShmemId = IpcMemoryCreate(key, ShmemSize, IPCProtection))
  117. == IpcMemCreationFailed)
  118. {
  119. elog(FATAL, "ShmemCreate: cannot create region");
  120. exit(1);
  121. }
  122. /*
  123.  * ShmemBootstrap is true if shared memory has been created, but not
  124.  * yet initialized.  Only the postmaster/creator-of-all-things should
  125.  * have this flag set.
  126.  */
  127. ShmemBootstrap = TRUE;
  128. }
  129. /*
  130.  * InitShmem() -- map region into process address space
  131.  * and initialize shared data structures.
  132.  *
  133.  */
  134. int
  135. InitShmem(unsigned int key, unsigned int size)
  136. {
  137. Pointer sharedRegion;
  138. unsigned long currFreeSpace;
  139. HASHCTL info;
  140. int hash_flags;
  141. ShmemIndexEnt *result,
  142. item;
  143. bool found;
  144. IpcMemoryId shmid;
  145. /* if zero key, use default memory size */
  146. if (size)
  147. ShmemSize = size;
  148. /* default key is 0 */
  149. /* attach to shared memory region (SysV or BSD OS specific) */
  150. if (ShmemBootstrap && key == PrivateIPCKey)
  151. /* if we are running backend alone */
  152. shmid = ShmemId;
  153. else
  154. shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
  155. sharedRegion = IpcMemoryAttach(shmid);
  156. if (sharedRegion == NULL)
  157. {
  158. elog(FATAL, "AttachSharedRegion: couldn't attach to shmemn");
  159. return FALSE;
  160. }
  161. /* get pointers to the dimensions of shared memory */
  162. ShmemBase = (unsigned long) sharedRegion;
  163. ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
  164. currFreeSpace = 0;
  165. /* First long in shared memory is the count of available space */
  166. ShmemFreeStart = (unsigned long *) ShmemBase;
  167. /* next is a shmem pointer to the shmem index */
  168. ShmemIndexOffset = ShmemFreeStart + 1;
  169. /* next is ShmemVariableCache */
  170. ShmemVariableCache = (VariableCache) (ShmemIndexOffset + 1);
  171. currFreeSpace += sizeof(ShmemFreeStart) + sizeof(ShmemIndexOffset) +
  172. LONGALIGN(sizeof(VariableCacheData));
  173. /*
  174.  * bootstrap initialize spin locks so we can start to use the
  175.  * allocator and shmem index.
  176.  */
  177. if (!InitSpinLocks(ShmemBootstrap, IPCKeyGetSpinLockSemaphoreKey(key)))
  178. return FALSE;
  179. /*
  180.  * We have just allocated additional space for two spinlocks. Now
  181.  * setup the global free space count
  182.  */
  183. if (ShmemBootstrap)
  184. {
  185. *ShmemFreeStart = currFreeSpace;
  186. memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
  187. }
  188. /* if ShmemFreeStart is NULL, then the allocator won't work */
  189. Assert(*ShmemFreeStart);
  190. /* create OR attach to the shared memory shmem index */
  191. info.keysize = SHMEM_INDEX_KEYSIZE;
  192. info.datasize = SHMEM_INDEX_DATASIZE;
  193. hash_flags = HASH_ELEM;
  194. /* This will acquire the shmem index lock, but not release it. */
  195. ShmemIndex = ShmemInitHash("ShmemIndex",
  196.    SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
  197.    &info, hash_flags);
  198. if (!ShmemIndex)
  199. {
  200. elog(FATAL, "InitShmem: couldn't initialize Shmem Index");
  201. return FALSE;
  202. }
  203. /*
  204.  * Now, check the shmem index for an entry to the shmem index. If
  205.  * there is an entry there, someone else created the table. Otherwise,
  206.  * we did and we have to initialize it.
  207.  */
  208. MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
  209. strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE);
  210. result = (ShmemIndexEnt *)
  211. hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
  212. if (!result)
  213. {
  214. elog(FATAL, "InitShmem: corrupted shmem index");
  215. return FALSE;
  216. }
  217. if (!found)
  218. {
  219. /*
  220.  * bootstrapping shmem: we have to initialize the shmem index now.
  221.  */
  222. Assert(ShmemBootstrap);
  223. result->location = MAKE_OFFSET(ShmemIndex->hctl);
  224. *ShmemIndexOffset = result->location;
  225. result->size = SHMEM_INDEX_SIZE;
  226. ShmemBootstrap = FALSE;
  227. }
  228. else
  229. Assert(!ShmemBootstrap);
  230. /* now release the lock acquired in ShmemHashInit */
  231. SpinRelease(ShmemIndexLock);
  232. Assert(result->location == MAKE_OFFSET(ShmemIndex->hctl));
  233. return TRUE;
  234. }
  235. /*
  236.  * ShmemAlloc -- allocate word-aligned byte string from
  237.  * shared memory
  238.  *
  239.  * Assumes ShmemLock and ShmemFreeStart are initialized.
  240.  * Returns: real pointer to memory or NULL if we are out
  241.  * of space.  Has to return a real pointer in order
  242.  * to be compatable with malloc().
  243.  */
  244. long *
  245. ShmemAlloc(unsigned long size)
  246. {
  247. unsigned long tmpFree;
  248. long    *newSpace;
  249. /*
  250.  * ensure space is word aligned.
  251.  *
  252.  * Word-alignment is not good enough. We have to be more conservative:
  253.  * doubles need 8-byte alignment. (We probably only need this on RISC
  254.  * platforms but this is not a big waste of space.) - ay 12/94
  255.  */
  256. if (size % sizeof(double))
  257. size += sizeof(double) - (size % sizeof(double));
  258. Assert(*ShmemFreeStart);
  259. SpinAcquire(ShmemLock);
  260. tmpFree = *ShmemFreeStart + size;
  261. if (tmpFree <= ShmemSize)
  262. {
  263. newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
  264. *ShmemFreeStart += size;
  265. }
  266. else
  267. newSpace = NULL;
  268. SpinRelease(ShmemLock);
  269. if (!newSpace)
  270. elog(NOTICE, "ShmemAlloc: out of memory ");
  271. return newSpace;
  272. }
  273. /*
  274.  * ShmemIsValid -- test if an offset refers to valid shared memory
  275.  *
  276.  * Returns TRUE if the pointer is valid.
  277.  */
  278. int
  279. ShmemIsValid(unsigned long addr)
  280. {
  281. return (addr < ShmemEnd) && (addr >= ShmemBase);
  282. }
  283. /*
  284.  * ShmemInitHash -- Create/Attach to and initialize
  285.  * shared memory hash table.
  286.  *
  287.  * Notes:
  288.  *
  289.  * assume caller is doing some kind of synchronization
  290.  * so that two people dont try to create/initialize the
  291.  * table at once.  Use SpinAlloc() to create a spinlock
  292.  * for the structure before creating the structure itself.
  293.  */
  294. HTAB *
  295. ShmemInitHash(char *name, /* table string name for shmem index */
  296.   long init_size, /* initial table size */
  297.   long max_size, /* max size of the table (NOT USED) */
  298.   HASHCTL *infoP, /* info about key and bucket size */
  299.   int hash_flags) /* info about infoP */
  300. {
  301. bool found;
  302. long    *location;
  303. /*
  304.  * Hash tables allocated in shared memory have a fixed directory; it
  305.  * can't grow or other backends wouldn't be able to find it. The
  306.  * segbase is for calculating pointer values. The shared memory
  307.  * allocator must be specified too.
  308.  */
  309. infoP->dsize = infoP->max_dsize = DEF_DIRSIZE;
  310. infoP->segbase = (long *) ShmemBase;
  311. infoP->alloc = ShmemAlloc;
  312. hash_flags |= HASH_SHARED_MEM | HASH_DIRSIZE;
  313. /* look it up in the shmem index */
  314. location = ShmemInitStruct(name,
  315.  sizeof(HHDR) + DEF_DIRSIZE * sizeof(SEG_OFFSET),
  316.    &found);
  317. /*
  318.  * shmem index is corrupted. Let someone else give the error
  319.  * message since they have more information
  320.  */
  321. if (location == NULL)
  322. return 0;
  323. /*
  324.  * it already exists, attach to it rather than allocate and initialize
  325.  * new space
  326.  */
  327. if (found)
  328. hash_flags |= HASH_ATTACH;
  329. /* Now provide the header and directory pointers */
  330. infoP->hctl = (long *) location;
  331. infoP->dir = (long *) (((char *) location) + sizeof(HHDR));
  332. return hash_create(init_size, infoP, hash_flags);
  333. }
  334. /*
  335.  * ShmemPIDLookup -- lookup process data structure using process id
  336.  *
  337.  * Returns: TRUE if no error.  locationPtr is initialized if PID is
  338.  * found in the shmem index.
  339.  *
  340.  * NOTES:
  341.  * only information about success or failure is the value of
  342.  * locationPtr.
  343.  */
  344. bool
  345. ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr)
  346. {
  347. ShmemIndexEnt *result,
  348. item;
  349. bool found;
  350. Assert(ShmemIndex);
  351. MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
  352. sprintf(item.key, "PID %d", pid);
  353. SpinAcquire(ShmemIndexLock);
  354. result = (ShmemIndexEnt *)
  355. hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found);
  356. if (!result)
  357. {
  358. SpinRelease(ShmemIndexLock);
  359. elog(ERROR, "ShmemInitPID: ShmemIndex corrupted");
  360. return FALSE;
  361. }
  362. if (found)
  363. *locationPtr = result->location;
  364. else
  365. result->location = *locationPtr;
  366. SpinRelease(ShmemIndexLock);
  367. return TRUE;
  368. }
  369. /*
  370.  * ShmemPIDDestroy -- destroy shmem index entry for process
  371.  * using process id
  372.  *
  373.  * Returns: offset of the process struct in shared memory or
  374.  * INVALID_OFFSET if not found.
  375.  *
  376.  * Side Effect: removes the entry from the shmem index
  377.  */
  378. SHMEM_OFFSET
  379. ShmemPIDDestroy(int pid)
  380. {
  381. ShmemIndexEnt *result,
  382. item;
  383. bool found;
  384. SHMEM_OFFSET location = 0;
  385. Assert(ShmemIndex);
  386. MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE);
  387. sprintf(item.key, "PID %d", pid);
  388. SpinAcquire(ShmemIndexLock);
  389. result = (ShmemIndexEnt *)
  390. hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, &found);
  391. if (found)
  392. location = result->location;
  393. SpinRelease(ShmemIndexLock);
  394. if (!result)
  395. {
  396. elog(ERROR, "ShmemPIDDestroy: PID table corrupted");
  397. return INVALID_OFFSET;
  398. }
  399. if (found)
  400. return location;
  401. else
  402. return INVALID_OFFSET;
  403. }
  404. /*
  405.  * ShmemInitStruct -- Create/attach to a structure in shared
  406.  * memory.
  407.  *
  408.  * This is called during initialization to find or allocate
  409.  * a data structure in shared memory. If no other processes
  410.  * have created the structure, this routine allocates space
  411.  * for it.  If it exists already, a pointer to the existing
  412.  * table is returned.
  413.  *
  414.  * Returns: real pointer to the object.  FoundPtr is TRUE if
  415.  * the object is already in the shmem index (hence, already
  416.  * initialized).
  417.  */
  418. long *
  419. ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
  420. {
  421. ShmemIndexEnt *result,
  422. item;
  423. long    *structPtr;
  424. strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
  425. item.location = BAD_LOCATION;
  426. SpinAcquire(ShmemIndexLock);
  427. if (!ShmemIndex)
  428. {
  429. #ifdef USE_ASSERT_CHECKING
  430. char    *strname = "ShmemIndex";
  431. #endif
  432. /*
  433.  * If the shmem index doesnt exist, we fake it.
  434.  *
  435.  * If we are creating the first shmem index, then let shmemalloc()
  436.  * allocate the space for a new HTAB.  Otherwise, find the old one
  437.  * and return that.  Notice that the ShmemIndexLock is held until
  438.  * the shmem index has been completely initialized.
  439.  */
  440. Assert(!strcmp(name, strname));
  441. if (ShmemBootstrap)
  442. {
  443. /* in POSTMASTER/Single process */
  444. *foundPtr = FALSE;
  445. return (long *) ShmemAlloc(size);
  446. }
  447. else
  448. {
  449. Assert(ShmemIndexOffset);
  450. *foundPtr = TRUE;
  451. return (long *) MAKE_PTR(*ShmemIndexOffset);
  452. }
  453. }
  454. else
  455. {
  456. /* look it up in the shmem index */
  457. result = (ShmemIndexEnt *)
  458. hash_search(ShmemIndex, (char *) &item, HASH_ENTER, foundPtr);
  459. }
  460. if (!result)
  461. {
  462. SpinRelease(ShmemIndexLock);
  463. elog(ERROR, "ShmemInitStruct: Shmem Index corrupted");
  464. return NULL;
  465. }
  466. else if (*foundPtr)
  467. {
  468. /*
  469.  * Structure is in the shmem index so someone else has allocated
  470.  * it already. The size better be the same as the size we are
  471.  * trying to initialize to or there is a name conflict (or worse).
  472.  */
  473. if (result->size != size)
  474. {
  475. SpinRelease(ShmemIndexLock);
  476. elog(NOTICE, "ShmemInitStruct: ShmemIndex entry size is wrong");
  477. /* let caller print its message too */
  478. return NULL;
  479. }
  480. structPtr = (long *) MAKE_PTR(result->location);
  481. }
  482. else
  483. {
  484. /* It isn't in the table yet. allocate and initialize it */
  485. structPtr = ShmemAlloc((long) size);
  486. if (!structPtr)
  487. {
  488. /* out of memory */
  489. Assert(ShmemIndex);
  490. hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, foundPtr);
  491. SpinRelease(ShmemIndexLock);
  492. *foundPtr = FALSE;
  493. elog(NOTICE, "ShmemInitStruct: cannot allocate '%s'",
  494.  name);
  495. return NULL;
  496. }
  497. result->size = size;
  498. result->location = MAKE_OFFSET(structPtr);
  499. }
  500. Assert(ShmemIsValid((unsigned long) structPtr));
  501. SpinRelease(ShmemIndexLock);
  502. return structPtr;
  503. }
  504. /*
  505.  * TransactionIdIsInProgress -- is given transaction running by some backend
  506.  *
  507.  * Strange place for this func, but we have to lookup process data structures
  508.  * for all running backends. - vadim 11/26/96
  509.  *
  510.  * We should keep all PROC structs not in ShmemIndex - this is too
  511.  * general hash table...
  512.  *
  513.  */
  514. bool
  515. TransactionIdIsInProgress(TransactionId xid)
  516. {
  517. ShmemIndexEnt *result;
  518. PROC    *proc;
  519. Assert(ShmemIndex);
  520. SpinAcquire(ShmemIndexLock);
  521. hash_seq((HTAB *) NULL);
  522. while ((result = (ShmemIndexEnt *) hash_seq(ShmemIndex)) != NULL)
  523. {
  524. if (result == (ShmemIndexEnt *) TRUE)
  525. {
  526. SpinRelease(ShmemIndexLock);
  527. return false;
  528. }
  529. if (result->location == INVALID_OFFSET ||
  530. strncmp(result->key, "PID ", 4) != 0)
  531. continue;
  532. proc = (PROC *) MAKE_PTR(result->location);
  533. if (proc->xid == xid)
  534. {
  535. SpinRelease(ShmemIndexLock);
  536. return true;
  537. }
  538. }
  539. SpinRelease(ShmemIndexLock);
  540. elog(ERROR, "TransactionIdIsInProgress: ShmemIndex corrupted");
  541. return false;
  542. }
  543. /*
  544.  * GetSnapshotData -- returns information about running transactions.
  545.  *
  546.  * Yet another strange func for this place... - vadim 07/21/98
  547.  */
  548. Snapshot
  549. GetSnapshotData(bool serializable)
  550. {
  551. Snapshot snapshot = (Snapshot) malloc(sizeof(SnapshotData));
  552. ShmemIndexEnt *result;
  553. PROC    *proc;
  554. TransactionId cid = GetCurrentTransactionId();
  555. TransactionId xid;
  556. uint32 count = 0;
  557. uint32 have = 32;
  558. Assert(ShmemIndex);
  559. snapshot->xip = (TransactionId *) malloc(have * sizeof(TransactionId));
  560. snapshot->xmin = cid;
  561. SpinAcquire(ShmemIndexLock);
  562. /*
  563.  * Unfortunately, we have to call ReadNewTransactionId()
  564.  * after acquiring ShmemIndexLock above. It's not good because of
  565.  * ReadNewTransactionId() does SpinAcquire(OidGenLockId) but
  566.  * _necessary_.
  567.  */
  568. ReadNewTransactionId(&(snapshot->xmax));
  569. hash_seq((HTAB *) NULL);
  570. while ((result = (ShmemIndexEnt *) hash_seq(ShmemIndex)) != NULL)
  571. {
  572. if (result == (ShmemIndexEnt *) TRUE)
  573. {
  574. if (serializable)
  575. MyProc->xmin = snapshot->xmin;
  576. /* Serializable snapshot must be computed before any other... */
  577. Assert(MyProc->xmin != InvalidTransactionId);
  578. SpinRelease(ShmemIndexLock);
  579. snapshot->xcnt = count;
  580. return snapshot;
  581. }
  582. if (result->location == INVALID_OFFSET ||
  583. strncmp(result->key, "PID ", 4) != 0)
  584. continue;
  585. proc = (PROC *) MAKE_PTR(result->location);
  586. /* 
  587.  * We don't use spin-locking when changing proc->xid 
  588.  * in GetNewTransactionId() and in AbortTransaction() !..
  589.  */
  590. xid = proc->xid;
  591. if (proc == MyProc || 
  592. xid < FirstTransactionId || xid >= snapshot->xmax)
  593. {
  594. /*
  595.  * Seems that there is no sense to store xid >= snapshot->xmax
  596.  * (what we got from ReadNewTransactionId above) in snapshot->xip 
  597.  * - we just assume that all xacts with such xid-s are running 
  598.  * and may be ignored.
  599.  */
  600. continue;
  601. }
  602. if (xid < snapshot->xmin)
  603. snapshot->xmin = xid;
  604. if (have == 0)
  605. {
  606. snapshot->xip = (TransactionId *) realloc(snapshot->xip,
  607.    (count + 32) * sizeof(TransactionId));
  608. have = 32;
  609. }
  610. snapshot->xip[count] = xid;
  611. have--;
  612. count++;
  613. }
  614. SpinRelease(ShmemIndexLock);
  615. free(snapshot->xip);
  616. free(snapshot);
  617. elog(ERROR, "GetSnapshotData: ShmemIndex corrupted");
  618. return NULL;
  619. }
  620. /*
  621.  * GetXmaxRecent -- returns oldest transaction that was running
  622.  * when all current transaction was started.
  623.  * It's used by vacuum to decide what deleted
  624.  * tuples must be preserved in a table.
  625.  *
  626.  * And yet another strange func for this place... - vadim 03/18/99
  627.  */
  628. void
  629. GetXmaxRecent(TransactionId *XmaxRecent)
  630. {
  631. ShmemIndexEnt *result;
  632. PROC    *proc;
  633. TransactionId xmin;
  634. Assert(ShmemIndex);
  635. *XmaxRecent = GetCurrentTransactionId();
  636. SpinAcquire(ShmemIndexLock);
  637. hash_seq((HTAB *) NULL);
  638. while ((result = (ShmemIndexEnt *) hash_seq(ShmemIndex)) != NULL)
  639. {
  640. if (result == (ShmemIndexEnt *) TRUE)
  641. {
  642. SpinRelease(ShmemIndexLock);
  643. return;
  644. }
  645. if (result->location == INVALID_OFFSET ||
  646. strncmp(result->key, "PID ", 4) != 0)
  647. continue;
  648. proc = (PROC *) MAKE_PTR(result->location);
  649. xmin = proc->xmin; /* we don't use spin-locking in AbortTransaction() ! */
  650. if (proc == MyProc || xmin < FirstTransactionId)
  651. continue;
  652. if (xmin < *XmaxRecent)
  653. *XmaxRecent = xmin;
  654. }
  655. SpinRelease(ShmemIndexLock);
  656. elog(ERROR, "GetXmaxRecent: ShmemIndex corrupted");
  657. }