You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

session.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*-------------------------------------------------------------------------
  2. *
  3. * session.c
  4. * Encapsulation of user session.
  5. *
  6. * This is intended to contain data that needs to be shared between backends
  7. * performing work for a client session. In particular such a session is
  8. * shared between the leader and worker processes for parallel queries. At
  9. * some later point it might also become useful infrastructure for separating
  10. * backends from client connections, e.g. for the purpose of pooling.
  11. *
  12. * Currently this infrastructure is used to share:
  13. * - typemod registry for ephemeral row-types, i.e. BlessTupleDesc etc.
  14. *
  15. * Portions Copyright (c) 2017-2019, PostgreSQL Global Development Group
  16. *
  17. * src/backend/access/common/session.c
  18. *
  19. *-------------------------------------------------------------------------
  20. */
  21. #include "postgres.h"
  22. #include "access/session.h"
  23. #include "storage/lwlock.h"
  24. #include "storage/shm_toc.h"
  25. #include "utils/memutils.h"
  26. #include "utils/typcache.h"
  27. /* Magic number for per-session DSM TOC. */
  28. #define SESSION_MAGIC 0xabb0fbc9
  29. /*
  30. * We want to create a DSA area to store shared state that has the same
  31. * lifetime as a session. So far, it's only used to hold the shared record
  32. * type registry. We don't want it to have to create any DSM segments just
  33. * yet in common cases, so we'll give it enough space to hold a very small
  34. * SharedRecordTypmodRegistry.
  35. */
  36. #define SESSION_DSA_SIZE 0x30000
  37. /*
  38. * Magic numbers for state sharing in the per-session DSM area.
  39. */
  40. #define SESSION_KEY_DSA UINT64CONST(0xFFFFFFFFFFFF0001)
  41. #define SESSION_KEY_RECORD_TYPMOD_REGISTRY UINT64CONST(0xFFFFFFFFFFFF0002)
  42. /* This backend's current session. */
  43. Session *CurrentSession = NULL;
  44. /*
  45. * Set up CurrentSession to point to an empty Session object.
  46. */
  47. void
  48. InitializeSession(void)
  49. {
  50. CurrentSession = MemoryContextAllocZero(TopMemoryContext, sizeof(Session));
  51. }
  52. /*
  53. * Initialize the per-session DSM segment if it isn't already initialized, and
  54. * return its handle so that worker processes can attach to it.
  55. *
  56. * Unlike the per-context DSM segment, this segment and its contents are
  57. * reused for future parallel queries.
  58. *
  59. * Return DSM_HANDLE_INVALID if a segment can't be allocated due to lack of
  60. * resources.
  61. */
  62. dsm_handle
  63. GetSessionDsmHandle(void)
  64. {
  65. shm_toc_estimator estimator;
  66. shm_toc *toc;
  67. dsm_segment *seg;
  68. size_t typmod_registry_size;
  69. size_t size;
  70. void *dsa_space;
  71. void *typmod_registry_space;
  72. dsa_area *dsa;
  73. MemoryContext old_context;
  74. /*
  75. * If we have already created a session-scope DSM segment in this backend,
  76. * return its handle. The same segment will be used for the rest of this
  77. * backend's lifetime.
  78. */
  79. if (CurrentSession->segment != NULL)
  80. return dsm_segment_handle(CurrentSession->segment);
  81. /* Otherwise, prepare to set one up. */
  82. old_context = MemoryContextSwitchTo(TopMemoryContext);
  83. shm_toc_initialize_estimator(&estimator);
  84. /* Estimate space for the per-session DSA area. */
  85. shm_toc_estimate_keys(&estimator, 1);
  86. shm_toc_estimate_chunk(&estimator, SESSION_DSA_SIZE);
  87. /* Estimate space for the per-session record typmod registry. */
  88. typmod_registry_size = SharedRecordTypmodRegistryEstimate();
  89. shm_toc_estimate_keys(&estimator, 1);
  90. shm_toc_estimate_chunk(&estimator, typmod_registry_size);
  91. /* Set up segment and TOC. */
  92. size = shm_toc_estimate(&estimator);
  93. seg = dsm_create(size, DSM_CREATE_NULL_IF_MAXSEGMENTS);
  94. if (seg == NULL)
  95. {
  96. MemoryContextSwitchTo(old_context);
  97. return DSM_HANDLE_INVALID;
  98. }
  99. toc = shm_toc_create(SESSION_MAGIC,
  100. dsm_segment_address(seg),
  101. size);
  102. /* Create per-session DSA area. */
  103. dsa_space = shm_toc_allocate(toc, SESSION_DSA_SIZE);
  104. dsa = dsa_create_in_place(dsa_space,
  105. SESSION_DSA_SIZE,
  106. LWTRANCHE_SESSION_DSA,
  107. seg);
  108. shm_toc_insert(toc, SESSION_KEY_DSA, dsa_space);
  109. /* Create session-scoped shared record typmod registry. */
  110. typmod_registry_space = shm_toc_allocate(toc, typmod_registry_size);
  111. SharedRecordTypmodRegistryInit((SharedRecordTypmodRegistry *)
  112. typmod_registry_space, seg, dsa);
  113. shm_toc_insert(toc, SESSION_KEY_RECORD_TYPMOD_REGISTRY,
  114. typmod_registry_space);
  115. /*
  116. * If we got this far, we can pin the shared memory so it stays mapped for
  117. * the rest of this backend's life. If we don't make it this far, cleanup
  118. * callbacks for anything we installed above (ie currently
  119. * SharedRecordTypemodRegistry) will run when the DSM segment is detached
  120. * by CurrentResourceOwner so we aren't left with a broken CurrentSession.
  121. */
  122. dsm_pin_mapping(seg);
  123. dsa_pin_mapping(dsa);
  124. /* Make segment and area available via CurrentSession. */
  125. CurrentSession->segment = seg;
  126. CurrentSession->area = dsa;
  127. MemoryContextSwitchTo(old_context);
  128. return dsm_segment_handle(seg);
  129. }
  130. /*
  131. * Attach to a per-session DSM segment provided by a parallel leader.
  132. */
  133. void
  134. AttachSession(dsm_handle handle)
  135. {
  136. dsm_segment *seg;
  137. shm_toc *toc;
  138. void *dsa_space;
  139. void *typmod_registry_space;
  140. dsa_area *dsa;
  141. MemoryContext old_context;
  142. old_context = MemoryContextSwitchTo(TopMemoryContext);
  143. /* Attach to the DSM segment. */
  144. seg = dsm_attach(handle);
  145. if (seg == NULL)
  146. elog(ERROR, "could not attach to per-session DSM segment");
  147. toc = shm_toc_attach(SESSION_MAGIC, dsm_segment_address(seg));
  148. /* Attach to the DSA area. */
  149. dsa_space = shm_toc_lookup(toc, SESSION_KEY_DSA, false);
  150. dsa = dsa_attach_in_place(dsa_space, seg);
  151. /* Make them available via the current session. */
  152. CurrentSession->segment = seg;
  153. CurrentSession->area = dsa;
  154. /* Attach to the shared record typmod registry. */
  155. typmod_registry_space =
  156. shm_toc_lookup(toc, SESSION_KEY_RECORD_TYPMOD_REGISTRY, false);
  157. SharedRecordTypmodRegistryAttach((SharedRecordTypmodRegistry *)
  158. typmod_registry_space);
  159. /* Remain attached until end of backend or DetachSession(). */
  160. dsm_pin_mapping(seg);
  161. dsa_pin_mapping(dsa);
  162. MemoryContextSwitchTo(old_context);
  163. }
  164. /*
  165. * Detach from the current session DSM segment. It's not strictly necessary
  166. * to do this explicitly since we'll detach automatically at backend exit, but
  167. * if we ever reuse parallel workers it will become important for workers to
  168. * detach from one session before attaching to another. Note that this runs
  169. * detach hooks.
  170. */
  171. void
  172. DetachSession(void)
  173. {
  174. /* Runs detach hooks. */
  175. dsm_detach(CurrentSession->segment);
  176. CurrentSession->segment = NULL;
  177. dsa_detach(CurrentSession->area);
  178. CurrentSession->area = NULL;
  179. }