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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * sinvaladt.c
  4.  *   POSTGRES shared cache invalidation segment definitions.
  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/sinvaladt.c,v 1.20 1999/05/28 17:03:28 tgl Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <stdio.h>
  15. #include <signal.h>
  16. #include <unistd.h>
  17. #include "postgres.h"
  18. #include "storage/ipc.h"
  19. #include "storage/backendid.h"
  20. #include "storage/sinvaladt.h"
  21. #include "storage/lmgr.h"
  22. #include "utils/memutils.h"
  23. #include "utils/palloc.h"
  24. #include "utils/trace.h"
  25. /* ----------------
  26.  * global variable notes
  27.  *
  28.  * SharedInvalidationSemaphore
  29.  *
  30.  * shmInvalBuffer
  31.  * the shared buffer segment, set by SISegmentAttach()
  32.  *
  33.  * MyBackendId
  34.  * might be removed later, used only for
  35.  * debugging in debug routines (end of file)
  36.  *
  37.  * SIDbId
  38.  * identification of buffer (disappears)
  39.  *
  40.  * SIRelId
  41.  * SIDummyOid   identification of buffer
  42.  * SIXidData  /
  43.  * SIXid /
  44.  *
  45.  * XXX This file really needs to be cleaned up.  We switched to using
  46.  * spinlocks to protect critical sections (as opposed to using fake
  47.  * relations and going through the lock manager) and some of the old
  48.  * cruft was 'ifdef'ed out, while other parts (now unused) are still
  49.  * compiled into the system. -mer 5/24/92
  50.  * ----------------
  51.  */
  52. #ifdef HAS_TEST_AND_SET
  53. int SharedInvalidationLockId;
  54. #else
  55. IpcSemaphoreId SharedInvalidationSemaphore;
  56. #endif
  57. SISeg    *shmInvalBuffer;
  58. extern BackendId MyBackendId;
  59. static void CleanupInvalidationState(int status, SISeg *segInOutP);
  60. static BackendId SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag);
  61. static int SIGetNumEntries(SISeg *segP);
  62. /************************************************************************/
  63. /* SISetActiveProcess(segP, backendId) set the backend status active */
  64. /* should be called only by the postmaster when creating a backend */
  65. /************************************************************************/
  66. /* XXX I suspect that the segP parameter is extraneous. -hirohama */
  67. static void
  68. SISetActiveProcess(SISeg *segInOutP, BackendId backendId)
  69. {
  70. /* mark all messages as read */
  71. /* Assert(segP->procState[backendId - 1].tag == MyBackendTag); */
  72. segInOutP->procState[backendId - 1].resetState = false;
  73. segInOutP->procState[backendId - 1].limit = SIGetNumEntries(segInOutP);
  74. }
  75. /****************************************************************************/
  76. /* SIBackendInit() initializes a backend to operate on the buffer */
  77. /****************************************************************************/
  78. int
  79. SIBackendInit(SISeg *segInOutP)
  80. {
  81. LockRelId LtCreateRelId();
  82. TransactionId LMITransactionIdCopy();
  83. Assert(MyBackendTag > 0);
  84. MyBackendId = SIAssignBackendId(segInOutP, MyBackendTag);
  85. if (MyBackendId == InvalidBackendTag)
  86. return 0;
  87. #ifdef INVALIDDEBUG
  88. elog(DEBUG, "SIBackendInit: backend tag %d; backend id %d.",
  89.  MyBackendTag, MyBackendId);
  90. #endif  /* INVALIDDEBUG */
  91. SISetActiveProcess(segInOutP, MyBackendId);
  92. on_shmem_exit(CleanupInvalidationState, (caddr_t) segInOutP);
  93. return 1;
  94. }
  95. /* ----------------
  96.  * SIAssignBackendId
  97.  * ----------------
  98.  */
  99. static BackendId
  100. SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag)
  101. {
  102. Index index;
  103. ProcState  *stateP = NULL;
  104. for (index = 0; index < segInOutP->maxBackends; index++)
  105. {
  106. if (segInOutP->procState[index].tag == InvalidBackendTag ||
  107. segInOutP->procState[index].tag == backendTag)
  108. {
  109. stateP = &segInOutP->procState[index];
  110. break;
  111. }
  112. if (!PointerIsValid(stateP) ||
  113. (segInOutP->procState[index].resetState &&
  114.  (!stateP->resetState ||
  115.   stateP->tag < backendTag)) ||
  116. (!stateP->resetState &&
  117.  (segInOutP->procState[index].limit <
  118.   stateP->limit ||
  119.   stateP->tag < backendTag)))
  120. stateP = &segInOutP->procState[index];
  121. }
  122. /* verify that all "procState" entries checked for matching tags */
  123. for (index++; index < segInOutP->maxBackends; index++)
  124. {
  125. if (segInOutP->procState[index].tag == backendTag)
  126. elog(FATAL, "SIAssignBackendId: tag %d found twice", backendTag);
  127. }
  128. Assert(stateP);
  129. if (stateP->tag != InvalidBackendTag)
  130. {
  131. if (stateP->tag == backendTag)
  132. elog(NOTICE, "SIAssignBackendId: reusing tag %d", backendTag);
  133. else
  134. {
  135. elog(NOTICE, "SIAssignBackendId: discarding tag %d", stateP->tag);
  136. return InvalidBackendTag;
  137. }
  138. }
  139. stateP->tag = backendTag;
  140. return 1 + stateP - &segInOutP->procState[0];
  141. }
  142. /************************************************************************/
  143. /* The following function should be called only by the postmaster !! */
  144. /************************************************************************/
  145. /************************************************************************/
  146. /* SISetDeadProcess(segP, backendId)  set the backend status DEAD */
  147. /* should be called only by the postmaster when a backend died */
  148. /************************************************************************/
  149. static void
  150. SISetDeadProcess(SISeg *segP, int backendId)
  151. {
  152. /* XXX call me.... */
  153. segP->procState[backendId - 1].resetState = false;
  154. segP->procState[backendId - 1].limit = -1;
  155. segP->procState[backendId - 1].tag = InvalidBackendTag;
  156. }
  157. /*
  158.  * CleanupInvalidationState
  159.  * Note:
  160.  * This is a temporary hack.  ExitBackend should call this instead
  161.  * of exit (via on_shmem_exit).
  162.  */
  163. static void
  164. CleanupInvalidationState(int status, /* XXX */
  165.  SISeg *segInOutP) /* XXX style */
  166. {
  167. Assert(PointerIsValid(segInOutP));
  168. SISetDeadProcess(segInOutP, MyBackendId);
  169. }
  170. /************************************************************************/
  171. /* SIComputeSize() - compute size and offsets for SI segment */
  172. /************************************************************************/
  173. static void
  174. SIComputeSize(SISegOffsets *oP, int maxBackends)
  175. {
  176. int A,
  177. B,
  178. a,
  179. b,
  180. totalSize;
  181. A = 0;
  182. /* sizeof(SISeg) includes the first ProcState entry */
  183. a = sizeof(SISeg) + sizeof(ProcState) * (maxBackends - 1);
  184. a = MAXALIGN(a); /* offset to first data entry */
  185. b = sizeof(SISegEntry) * MAXNUMMESSAGES;
  186. B = A + a + b;
  187. B = MAXALIGN(B);
  188. totalSize = B - A;
  189. oP->startSegment = A;
  190. oP->offsetToFirstEntry = a; /* relative to A */
  191. oP->offsetToEndOfSegment = totalSize; /* relative to A */
  192. }
  193. /************************************************************************/
  194. /* SISetStartEntrySection(segP, offset) - sets the offset */
  195. /************************************************************************/
  196. static void
  197. SISetStartEntrySection(SISeg *segP, Offset offset)
  198. {
  199. segP->startEntrySection = offset;
  200. }
  201. /************************************************************************/
  202. /* SIGetStartEntrySection(segP) - returnss the offset */
  203. /************************************************************************/
  204. static Offset
  205. SIGetStartEntrySection(SISeg *segP)
  206. {
  207. return segP->startEntrySection;
  208. }
  209. /************************************************************************/
  210. /* SISetEndEntrySection(segP, offset) - sets the offset */
  211. /************************************************************************/
  212. static void
  213. SISetEndEntrySection(SISeg *segP, Offset offset)
  214. {
  215. segP->endEntrySection = offset;
  216. }
  217. /************************************************************************/
  218. /* SISetEndEntryChain(segP, offset) - sets the offset */
  219. /************************************************************************/
  220. static void
  221. SISetEndEntryChain(SISeg *segP, Offset offset)
  222. {
  223. segP->endEntryChain = offset;
  224. }
  225. /************************************************************************/
  226. /* SIGetEndEntryChain(segP) - returnss the offset */
  227. /************************************************************************/
  228. static Offset
  229. SIGetEndEntryChain(SISeg *segP)
  230. {
  231. return segP->endEntryChain;
  232. }
  233. /************************************************************************/
  234. /* SISetStartEntryChain(segP, offset) - sets the offset */
  235. /************************************************************************/
  236. static void
  237. SISetStartEntryChain(SISeg *segP, Offset offset)
  238. {
  239. segP->startEntryChain = offset;
  240. }
  241. /************************************************************************/
  242. /* SIGetStartEntryChain(segP) - returns  the offset */
  243. /************************************************************************/
  244. static Offset
  245. SIGetStartEntryChain(SISeg *segP)
  246. {
  247. return segP->startEntryChain;
  248. }
  249. /************************************************************************/
  250. /* SISetNumEntries(segP, num) sets the current nuber of entries */
  251. /************************************************************************/
  252. static bool
  253. SISetNumEntries(SISeg *segP, int num)
  254. {
  255. if (num <= MAXNUMMESSAGES)
  256. {
  257. segP->numEntries = num;
  258. return true;
  259. }
  260. else
  261. {
  262. return false; /* table full */
  263. }
  264. }
  265. /************************************************************************/
  266. /* SIGetNumEntries(segP) - returns the current nuber of entries */
  267. /************************************************************************/
  268. static int
  269. SIGetNumEntries(SISeg *segP)
  270. {
  271. return segP->numEntries;
  272. }
  273. /************************************************************************/
  274. /* SISetMaxNumEntries(segP, num) sets the maximal number of entries */
  275. /************************************************************************/
  276. static bool
  277. SISetMaxNumEntries(SISeg *segP, int num)
  278. {
  279. if (num <= MAXNUMMESSAGES)
  280. {
  281. segP->maxNumEntries = num;
  282. return true;
  283. }
  284. else
  285. {
  286. return false; /* wrong number */
  287. }
  288. }
  289. /************************************************************************/
  290. /* SIGetProcStateLimit(segP, i) returns the limit of read messages */
  291. /************************************************************************/
  292. #define SIGetProcStateLimit(segP,i) 
  293. ((segP)->procState[i].limit)
  294. /************************************************************************/
  295. /* SIIncNumEntries(segP, num) increments the current nuber of entries */
  296. /************************************************************************/
  297. static bool
  298. SIIncNumEntries(SISeg *segP, int num)
  299. {
  300. /*
  301.  * Try to prevent table overflow. When the table is 70% full send a
  302.  * SIGUSR2 to the postmaster which will send it back to all the
  303.  * backends. This will be handled by Async_NotifyHandler() with a
  304.  * StartTransactionCommand() which will flush unread SI entries for
  305.  * each backend. dz - 27 Jan 1998
  306.  */
  307. if (segP->numEntries == (MAXNUMMESSAGES * 70 / 100))
  308. {
  309. TPRINTF(TRACE_VERBOSE,
  310. "SIIncNumEntries: table is 70%% full, signaling postmaster");
  311. kill(getppid(), SIGUSR2);
  312. }
  313. if ((segP->numEntries + num) <= MAXNUMMESSAGES)
  314. {
  315. segP->numEntries = segP->numEntries + num;
  316. return true;
  317. }
  318. else
  319. {
  320. return false; /* table full */
  321. }
  322. }
  323. /************************************************************************/
  324. /* SIDecNumEntries(segP, num) decrements the current nuber of entries */
  325. /************************************************************************/
  326. static bool
  327. SIDecNumEntries(SISeg *segP, int num)
  328. {
  329. if ((segP->numEntries - num) >= 0)
  330. {
  331. segP->numEntries = segP->numEntries - num;
  332. return true;
  333. }
  334. else
  335. {
  336. return false; /* not enough entries in table */
  337. }
  338. }
  339. /************************************************************************/
  340. /* SISetStartFreeSpace(segP, offset)  - sets the offset */
  341. /************************************************************************/
  342. static void
  343. SISetStartFreeSpace(SISeg *segP, Offset offset)
  344. {
  345. segP->startFreeSpace = offset;
  346. }
  347. /************************************************************************/
  348. /* SIGetStartFreeSpace(segP)  - returns the offset */
  349. /************************************************************************/
  350. static Offset
  351. SIGetStartFreeSpace(SISeg *segP)
  352. {
  353. return segP->startFreeSpace;
  354. }
  355. /************************************************************************/
  356. /* SIGetFirstDataEntry(segP)  returns first data entry */
  357. /************************************************************************/
  358. static SISegEntry *
  359. SIGetFirstDataEntry(SISeg *segP)
  360. {
  361. SISegEntry *eP;
  362. Offset startChain;
  363. startChain = SIGetStartEntryChain(segP);
  364. if (startChain == InvalidOffset)
  365. return NULL;
  366. eP = (SISegEntry *) ((Pointer) segP +
  367.  SIGetStartEntrySection(segP) +
  368.  startChain);
  369. return eP;
  370. }
  371. /************************************************************************/
  372. /* SIGetLastDataEntry(segP)  returns last data entry in the chain */
  373. /************************************************************************/
  374. static SISegEntry *
  375. SIGetLastDataEntry(SISeg *segP)
  376. {
  377. SISegEntry *eP;
  378. Offset endChain;
  379. endChain = SIGetEndEntryChain(segP);
  380. if (endChain == InvalidOffset)
  381. return NULL;
  382. eP = (SISegEntry *) ((Pointer) segP +
  383.  SIGetStartEntrySection(segP) +
  384.  endChain);
  385. return eP;
  386. }
  387. /************************************************************************/
  388. /* SIGetNextDataEntry(segP, offset)  returns next data entry */
  389. /************************************************************************/
  390. static SISegEntry *
  391. SIGetNextDataEntry(SISeg *segP, Offset offset)
  392. {
  393. SISegEntry *eP;
  394. if (offset == InvalidOffset)
  395. return NULL;
  396. eP = (SISegEntry *) ((Pointer) segP +
  397.  SIGetStartEntrySection(segP) +
  398.  offset);
  399. return eP;
  400. }
  401. /************************************************************************/
  402. /* SIGetNthDataEntry(segP, n) returns the n-th data entry in chain */
  403. /************************************************************************/
  404. static SISegEntry *
  405. SIGetNthDataEntry(SISeg *segP,
  406.   int n) /* must range from 1 to MaxMessages */
  407. {
  408. SISegEntry *eP;
  409. int i;
  410. if (n <= 0)
  411. return NULL;
  412. eP = SIGetFirstDataEntry(segP);
  413. for (i = 1; i < n; i++)
  414. {
  415. /* skip one and get the next */
  416. eP = SIGetNextDataEntry(segP, eP->next);
  417. }
  418. return eP;
  419. }
  420. /************************************************************************/
  421. /* SIEntryOffset(segP, entryP)  returns the offset for an pointer */
  422. /************************************************************************/
  423. static Offset
  424. SIEntryOffset(SISeg *segP, SISegEntry *entryP)
  425. {
  426. /* relative to B !! */
  427. return ((Offset) ((Pointer) entryP -
  428.   (Pointer) segP -
  429.   SIGetStartEntrySection(segP)));
  430. }
  431. /************************************************************************/
  432. /* SISetDataEntry(segP, data)  - sets a message in the segemnt */
  433. /************************************************************************/
  434. bool
  435. SISetDataEntry(SISeg *segP, SharedInvalidData *data)
  436. {
  437. Offset offsetToNewData;
  438. SISegEntry *eP,
  439.    *lastP;
  440. if (!SIIncNumEntries(segP, 1))
  441. return false; /* no space */
  442. /* get a free entry */
  443. offsetToNewData = SIGetStartFreeSpace(segP);
  444. eP = SIGetNextDataEntry(segP, offsetToNewData); /* it's a free one */
  445. SISetStartFreeSpace(segP, eP->next);
  446. /* fill it up */
  447. eP->entryData = *data;
  448. eP->isfree = false;
  449. eP->next = InvalidOffset;
  450. /* handle insertion point at the end of the chain !! */
  451. lastP = SIGetLastDataEntry(segP);
  452. if (lastP == NULL)
  453. {
  454. /* there is no chain, insert the first entry */
  455. SISetStartEntryChain(segP, SIEntryOffset(segP, eP));
  456. }
  457. else
  458. {
  459. /* there is a last entry in the chain */
  460. lastP->next = SIEntryOffset(segP, eP);
  461. }
  462. SISetEndEntryChain(segP, SIEntryOffset(segP, eP));
  463. return true;
  464. }
  465. /************************************************************************/
  466. /* SIDecProcLimit(segP, num)  decrements all process limits */
  467. /************************************************************************/
  468. static void
  469. SIDecProcLimit(SISeg *segP, int num)
  470. {
  471. int i;
  472. for (i = 0; i < segP->maxBackends; i++)
  473. {
  474. /* decrement only, if there is a limit > 0 */
  475. if (segP->procState[i].limit > 0)
  476. {
  477. segP->procState[i].limit = segP->procState[i].limit - num;
  478. if (segP->procState[i].limit < 0)
  479. {
  480. /* limit was not high enough, reset to zero */
  481. /* negative means it's a dead backend     */
  482. segP->procState[i].limit = 0;
  483. }
  484. }
  485. }
  486. }
  487. /************************************************************************/
  488. /* SIDelDataEntry(segP) - free the FIRST entry */
  489. /************************************************************************/
  490. bool
  491. SIDelDataEntry(SISeg *segP)
  492. {
  493. SISegEntry *e1P;
  494. if (!SIDecNumEntries(segP, 1))
  495. {
  496. /* no entries in buffer */
  497. return false;
  498. }
  499. e1P = SIGetFirstDataEntry(segP);
  500. SISetStartEntryChain(segP, e1P->next);
  501. if (SIGetStartEntryChain(segP) == InvalidOffset)
  502. {
  503. /* it was the last entry */
  504. SISetEndEntryChain(segP, InvalidOffset);
  505. }
  506. /* free the entry */
  507. e1P->isfree = true;
  508. e1P->next = SIGetStartFreeSpace(segP);
  509. SISetStartFreeSpace(segP, SIEntryOffset(segP, e1P));
  510. SIDecProcLimit(segP, 1);
  511. return true;
  512. }
  513. /************************************************************************/
  514. /* SISetProcStateInvalid(segP) checks and marks a backends state as */
  515. /* invalid */
  516. /************************************************************************/
  517. void
  518. SISetProcStateInvalid(SISeg *segP)
  519. {
  520. int i;
  521. for (i = 0; i < segP->maxBackends; i++)
  522. {
  523. if (segP->procState[i].limit == 0)
  524. {
  525. /* backend i didn't read any message                */
  526. segP->procState[i].resetState = true;
  527. /*
  528.  * XXX signal backend that it has to reset its internal cache
  529.  * ?
  530.  */
  531. }
  532. }
  533. }
  534. /************************************************************************/
  535. /* SIReadEntryData(segP, backendId, function) */
  536. /* - marks messages to be read by id */
  537. /*   and executes function */
  538. /************************************************************************/
  539. void
  540. SIReadEntryData(SISeg *segP,
  541. int backendId,
  542. void (*invalFunction) (),
  543. void (*resetFunction) ())
  544. {
  545. int i = 0;
  546. SISegEntry *data;
  547. Assert(segP->procState[backendId - 1].tag == MyBackendTag);
  548. if (!segP->procState[backendId - 1].resetState)
  549. {
  550. /* invalidate data, but only those, you have not seen yet !! */
  551. /* therefore skip read messages */
  552. data = SIGetNthDataEntry(segP,
  553.    SIGetProcStateLimit(segP, backendId - 1) + 1);
  554. while (data != NULL)
  555. {
  556. i++;
  557. segP->procState[backendId - 1].limit++; /* one more message read */
  558. invalFunction(data->entryData.cacheId,
  559.   data->entryData.hashIndex,
  560.   &data->entryData.pointerData);
  561. data = SIGetNextDataEntry(segP, data->next);
  562. }
  563. /* SIDelExpiredDataEntries(segP); */
  564. }
  565. else
  566. {
  567. /* backend must not read messages, its own state has to be reset  */
  568. elog(NOTICE, "SIReadEntryData: cache state reset");
  569. resetFunction(); /* XXXX call it here, parameters? */
  570. /* new valid state--mark all messages "read" */
  571. segP->procState[backendId - 1].resetState = false;
  572. segP->procState[backendId - 1].limit = SIGetNumEntries(segP);
  573. }
  574. /* check whether we can remove dead messages */
  575. if (i > MAXNUMMESSAGES)
  576. elog(FATAL, "SIReadEntryData: Invalid segment state");
  577. }
  578. /************************************************************************/
  579. /* SIDelExpiredDataEntries (segP) - removes irrelevant messages */
  580. /************************************************************************/
  581. void
  582. SIDelExpiredDataEntries(SISeg *segP)
  583. {
  584. int min,
  585. i,
  586. h;
  587. min = 9999999;
  588. for (i = 0; i < segP->maxBackends; i++)
  589. {
  590. h = SIGetProcStateLimit(segP, i);
  591. if (h >= 0)
  592. { /* backend active */
  593. if (h < min)
  594. min = h;
  595. }
  596. }
  597. if (min != 9999999)
  598. {
  599. /* we can remove min messages */
  600. for (i = 1; i <= min; i++)
  601. {
  602. /* this  adjusts also the state limits! */
  603. if (!SIDelDataEntry(segP))
  604. elog(FATAL, "SIDelExpiredDataEntries: Invalid segment state");
  605. }
  606. }
  607. }
  608. /************************************************************************/
  609. /* SISegInit(segP) - initializes the segment */
  610. /************************************************************************/
  611. static void
  612. SISegInit(SISeg *segP, SISegOffsets *oP, int maxBackends)
  613. {
  614. int i;
  615. SISegEntry *eP;
  616. /* set semaphore ids in the segment */
  617. /* XXX */
  618. SISetStartEntrySection(segP, oP->offsetToFirstEntry);
  619. SISetEndEntrySection(segP, oP->offsetToEndOfSegment);
  620. SISetStartFreeSpace(segP, 0);
  621. SISetStartEntryChain(segP, InvalidOffset);
  622. SISetEndEntryChain(segP, InvalidOffset);
  623. SISetNumEntries(segP, 0);
  624. SISetMaxNumEntries(segP, MAXNUMMESSAGES);
  625. segP->maxBackends = maxBackends;
  626. for (i = 0; i < segP->maxBackends; i++)
  627. {
  628. segP->procState[i].limit = -1; /* no backend active  !! */
  629. segP->procState[i].resetState = false;
  630. segP->procState[i].tag = InvalidBackendTag;
  631. }
  632. /* construct a chain of free entries */
  633. for (i = 1; i < MAXNUMMESSAGES; i++)
  634. {
  635. eP = (SISegEntry *) ((Pointer) segP +
  636.  SIGetStartEntrySection(segP) +
  637.  (i - 1) * sizeof(SISegEntry));
  638. eP->isfree = true;
  639. eP->next = i * sizeof(SISegEntry); /* relative to B */
  640. }
  641. /* handle the last free entry separate */
  642. eP = (SISegEntry *) ((Pointer) segP +
  643.  SIGetStartEntrySection(segP) +
  644.  (MAXNUMMESSAGES - 1) * sizeof(SISegEntry));
  645. eP->isfree = true;
  646. eP->next = InvalidOffset; /* it's the end of the chain !! */
  647. }
  648. /************************************************************************/
  649. /* SISegmentKill(key) - kill any segment */
  650. /************************************************************************/
  651. static void
  652. SISegmentKill(int key) /* the corresponding key for the segment */
  653. {
  654. IpcMemoryKill(key);
  655. }
  656. /************************************************************************/
  657. /* SISegmentGet(key, size) - get a shared segment of size <size> */
  658. /*   returns a segment id */
  659. /************************************************************************/
  660. static IpcMemoryId
  661. SISegmentGet(int key, /* the corresponding key for the segment */
  662.  int size, /* size of segment in bytes  */
  663.  bool create)
  664. {
  665. IpcMemoryId shmid;
  666. if (create)
  667. shmid = IpcMemoryCreate(key, size, IPCProtection);
  668. else
  669. shmid = IpcMemoryIdGet(key, size);
  670. return shmid;
  671. }
  672. /************************************************************************/
  673. /* SISegmentAttach(shmid) - attach a shared segment with id shmid */
  674. /************************************************************************/
  675. static void
  676. SISegmentAttach(IpcMemoryId shmid)
  677. {
  678. shmInvalBuffer = (struct SISeg *) IpcMemoryAttach(shmid);
  679. if (shmInvalBuffer == IpcMemAttachFailed)
  680. {
  681. /* XXX use validity function */
  682. elog(NOTICE, "SISegmentAttach: Could not attach segment");
  683. elog(FATAL, "SISegmentAttach: %m");
  684. }
  685. }
  686. /************************************************************************/
  687. /* SISegmentInit() initialize SI segment */
  688. /* */
  689. /* NB: maxBackends param is only valid when killExistingSegment is true */
  690. /************************************************************************/
  691. int
  692. SISegmentInit(bool killExistingSegment, IPCKey key, int maxBackends)
  693. {
  694. SISegOffsets offsets;
  695. IpcMemoryId shmId;
  696. bool create;
  697. if (killExistingSegment)
  698. {
  699. /* Kill existing segment */
  700. /* set semaphore */
  701. SISegmentKill(key);
  702. /* Get a shared segment */
  703. SIComputeSize(&offsets, maxBackends);
  704. create = true;
  705. shmId = SISegmentGet(key, offsets.offsetToEndOfSegment, create);
  706. if (shmId < 0)
  707. {
  708. perror("SISegmentGet: failed");
  709. return -1; /* an error */
  710. }
  711. /* Attach the shared cache invalidation  segment */
  712. /* sets the global variable shmInvalBuffer */
  713. SISegmentAttach(shmId);
  714. /* Init shared memory table */
  715. SISegInit(shmInvalBuffer, &offsets, maxBackends);
  716. }
  717. else
  718. {
  719. /* use an existing segment */
  720. create = false;
  721. shmId = SISegmentGet(key, 0, create);
  722. if (shmId < 0)
  723. {
  724. perror("SISegmentGet: getting an existent segment failed");
  725. return -1; /* an error */
  726. }
  727. /* Attach the shared cache invalidation segment */
  728. SISegmentAttach(shmId);
  729. }
  730. return 1;
  731. }