Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0fda682

Browse files
committed
Extend dsm API with a new function dsm_unpin_segment.
If you have previously pinned a segment and decide that you don'tactually want to keep it around until shutdown, this new API lets youremove the pin. This is pretty trivial except on Windows, where itrequires closing the duplicate handle that was used to implement thepin.Thomas Munro and Amit Kapila, reviewed by Amit Kapila and by me.
1 parent1999873 commit0fda682

File tree

4 files changed

+169
-10
lines changed

4 files changed

+169
-10
lines changed

‎src/backend/storage/ipc/dsm.c

Lines changed: 111 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ typedef struct dsm_control_item
8282
{
8383
dsm_handlehandle;
8484
uint32refcnt;/* 2+ = active, 1 = moribund, 0 = gone */
85+
void*impl_private_pm_handle;/* only needed on Windows */
86+
boolpinned;
8587
}dsm_control_item;
8688

8789
/* Layout of the dynamic shared memory control segment. */
@@ -491,6 +493,8 @@ dsm_create(Size size, int flags)
491493
dsm_control->item[i].handle=seg->handle;
492494
/* refcnt of 1 triggers destruction, so start at 2 */
493495
dsm_control->item[i].refcnt=2;
496+
dsm_control->item[i].impl_private_pm_handle=NULL;
497+
dsm_control->item[i].pinned= false;
494498
seg->control_slot=i;
495499
LWLockRelease(DynamicSharedMemoryControlLock);
496500
returnseg;
@@ -520,6 +524,8 @@ dsm_create(Size size, int flags)
520524
dsm_control->item[nitems].handle=seg->handle;
521525
/* refcnt of 1 triggers destruction, so start at 2 */
522526
dsm_control->item[nitems].refcnt=2;
527+
dsm_control->item[nitems].impl_private_pm_handle=NULL;
528+
dsm_control->item[nitems].pinned= false;
523529
seg->control_slot=nitems;
524530
dsm_control->nitems++;
525531
LWLockRelease(DynamicSharedMemoryControlLock);
@@ -760,6 +766,9 @@ dsm_detach(dsm_segment *seg)
760766
/* If new reference count is 1, try to destroy the segment. */
761767
if (refcnt==1)
762768
{
769+
/* A pinned segment should never reach 1. */
770+
Assert(!dsm_control->item[control_slot].pinned);
771+
763772
/*
764773
* If we fail to destroy the segment here, or are killed before we
765774
* finish doing so, the reference count will remain at 1, which
@@ -830,11 +839,11 @@ dsm_unpin_mapping(dsm_segment *seg)
830839
}
831840

832841
/*
833-
* Keep a dynamic shared memory segment until postmaster shutdown.
842+
* Keep a dynamic shared memory segment until postmaster shutdown, or until
843+
* dsm_unpin_segment is called.
834844
*
835-
* This function should not be called more than once per segment;
836-
* on Windows, doing so will create unnecessary handles which will
837-
* consume system resources to no benefit.
845+
* This function should not be called more than once per segment, unless the
846+
* segment is explicitly unpinned with dsm_unpin_segment in between calls.
838847
*
839848
* Note that this function does not arrange for the current process to
840849
* keep the segment mapped indefinitely; if that behavior is desired,
@@ -844,16 +853,112 @@ dsm_unpin_mapping(dsm_segment *seg)
844853
void
845854
dsm_pin_segment(dsm_segment*seg)
846855
{
856+
void*handle;
857+
847858
/*
848859
* Bump reference count for this segment in shared memory. This will
849860
* ensure that even if there is no session which is attached to this
850-
* segment, it will remain until postmaster shutdown.
861+
* segment, it will remain until postmaster shutdown or an explicit call
862+
* to unpin.
851863
*/
852864
LWLockAcquire(DynamicSharedMemoryControlLock,LW_EXCLUSIVE);
865+
if (dsm_control->item[seg->control_slot].pinned)
866+
elog(ERROR,"cannot pin a segment that is already pinned");
867+
dsm_impl_pin_segment(seg->handle,seg->impl_private,&handle);
868+
dsm_control->item[seg->control_slot].pinned= true;
853869
dsm_control->item[seg->control_slot].refcnt++;
870+
dsm_control->item[seg->control_slot].impl_private_pm_handle=handle;
854871
LWLockRelease(DynamicSharedMemoryControlLock);
872+
}
873+
874+
/*
875+
* Unpin a dynamic shared memory segment that was previously pinned with
876+
* dsm_pin_segment. This function should not be called unless dsm_pin_segment
877+
* was previously called for this segment.
878+
*
879+
* The argument is a dsm_handle rather than a dsm_segment in case you want
880+
* to unpin a segment to which you haven't attached. This turns out to be
881+
* useful if, for example, a reference to one shared memory segment is stored
882+
* within another shared memory segment. You might want to unpin the
883+
* referenced segment before destroying the referencing segment.
884+
*/
885+
void
886+
dsm_unpin_segment(dsm_handlehandle)
887+
{
888+
uint32control_slot=INVALID_CONTROL_SLOT;
889+
booldestroy= false;
890+
uint32i;
855891

856-
dsm_impl_pin_segment(seg->handle,seg->impl_private);
892+
/* Find the control slot for the given handle. */
893+
LWLockAcquire(DynamicSharedMemoryControlLock,LW_EXCLUSIVE);
894+
for (i=0;i<dsm_control->nitems;++i)
895+
{
896+
/* Skip unused slots. */
897+
if (dsm_control->item[i].refcnt==0)
898+
continue;
899+
900+
/* If we've found our handle, we can stop searching. */
901+
if (dsm_control->item[i].handle==handle)
902+
{
903+
control_slot=i;
904+
break;
905+
}
906+
}
907+
908+
/*
909+
* We should definitely have found the slot, and it should not already be
910+
* in the process of going away, because this function should only be
911+
* called on a segment which is pinned.
912+
*/
913+
if (control_slot==INVALID_CONTROL_SLOT)
914+
elog(ERROR,"cannot unpin unknown segment handle");
915+
if (!dsm_control->item[control_slot].pinned)
916+
elog(ERROR,"cannot unpin a segment that is not pinned");
917+
Assert(dsm_control->item[control_slot].refcnt>1);
918+
919+
/*
920+
* Allow implementation-specific code to run. We have to do this before
921+
* releasing the lock, because impl_private_pm_handle may get modified by
922+
* dsm_impl_unpin_segment.
923+
*/
924+
dsm_impl_unpin_segment(handle,
925+
&dsm_control->item[control_slot].impl_private_pm_handle);
926+
927+
/* Note that 1 means no references (0 means unused slot). */
928+
if (--dsm_control->item[control_slot].refcnt==1)
929+
destroy= true;
930+
dsm_control->item[control_slot].pinned= false;
931+
932+
/* Now we can release the lock. */
933+
LWLockRelease(DynamicSharedMemoryControlLock);
934+
935+
/* Clean up resources if that was the last reference. */
936+
if (destroy)
937+
{
938+
void*junk_impl_private=NULL;
939+
void*junk_mapped_address=NULL;
940+
Sizejunk_mapped_size=0;
941+
942+
/*
943+
* For an explanation of how error handling works in this case, see
944+
* comments in dsm_detach. Note that if we reach this point, the
945+
* current process certainly does not have the segment mapped, because
946+
* if it did, the reference count would have still been greater than 1
947+
* even after releasing the reference count held by the pin. The fact
948+
* that there can't be a dsm_segment for this handle makes it OK to
949+
* pass the mapped size, mapped address, and private data as NULL
950+
* here.
951+
*/
952+
if (dsm_impl_op(DSM_OP_DESTROY,handle,0,&junk_impl_private,
953+
&junk_mapped_address,&junk_mapped_size,WARNING))
954+
{
955+
LWLockAcquire(DynamicSharedMemoryControlLock,LW_EXCLUSIVE);
956+
Assert(dsm_control->item[control_slot].handle==handle);
957+
Assert(dsm_control->item[control_slot].refcnt==1);
958+
dsm_control->item[control_slot].refcnt=0;
959+
LWLockRelease(DynamicSharedMemoryControlLock);
960+
}
961+
}
857962
}
858963

859964
/*

‎src/backend/storage/ipc/dsm_impl.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -987,16 +987,17 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
987987
#endif
988988

989989
/*
990-
* Implementation-specific actions that must be performed when a segment
991-
*is tobe preserveduntil postmaster shutdown.
990+
* Implementation-specific actions that must be performed when a segment is to
991+
* be preservedeven when no backend has it attached.
992992
*
993993
* Except on Windows, we don't need to do anything at all. But since Windows
994994
* cleans up segments automatically when no references remain, we duplicate
995995
* the segment handle into the postmaster process. The postmaster needn't
996996
* do anything to receive the handle; Windows transfers it automatically.
997997
*/
998998
void
999-
dsm_impl_pin_segment(dsm_handlehandle,void*impl_private)
999+
dsm_impl_pin_segment(dsm_handlehandle,void*impl_private,
1000+
void**impl_private_pm_handle)
10001001
{
10011002
switch (dynamic_shared_memory_type)
10021003
{
@@ -1018,6 +1019,56 @@ dsm_impl_pin_segment(dsm_handle handle, void *impl_private)
10181019
errmsg("could not duplicate handle for \"%s\": %m",
10191020
name)));
10201021
}
1022+
1023+
/*
1024+
* Here, we remember the handle that we created in the
1025+
* postmaster process. This handle isn't actually usable in
1026+
* any process other than the postmaster, but that doesn't
1027+
* matter. We're just holding onto it so that, if the segment
1028+
* is unpinned, dsm_impl_unpin_segment can close it.
1029+
*/
1030+
*impl_private_pm_handle=hmap;
1031+
break;
1032+
}
1033+
#endif
1034+
default:
1035+
break;
1036+
}
1037+
}
1038+
1039+
/*
1040+
* Implementation-specific actions that must be performed when a segment is no
1041+
* longer to be preserved, so that it will be cleaned up when all backends
1042+
* have detached from it.
1043+
*
1044+
* Except on Windows, we don't need to do anything at all. For Windows, we
1045+
* close the extra handle that dsm_impl_pin_segment created in the
1046+
* postmaster's process space.
1047+
*/
1048+
void
1049+
dsm_impl_unpin_segment(dsm_handlehandle,void**impl_private)
1050+
{
1051+
switch (dynamic_shared_memory_type)
1052+
{
1053+
#ifdefUSE_DSM_WINDOWS
1054+
caseDSM_IMPL_WINDOWS:
1055+
{
1056+
if (*impl_private&&
1057+
!DuplicateHandle(PostmasterHandle,*impl_private,
1058+
NULL,NULL,0, FALSE,
1059+
DUPLICATE_CLOSE_SOURCE))
1060+
{
1061+
charname[64];
1062+
1063+
snprintf(name,64,"%s.%u",SEGMENT_NAME_PREFIX,handle);
1064+
_dosmaperr(GetLastError());
1065+
ereport(ERROR,
1066+
(errcode_for_dynamic_shared_memory(),
1067+
errmsg("could not duplicate handle for \"%s\": %m",
1068+
name)));
1069+
}
1070+
1071+
*impl_private=NULL;
10211072
break;
10221073
}
10231074
#endif

‎src/include/storage/dsm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern void dsm_detach(dsm_segment *seg);
4141
externvoiddsm_pin_mapping(dsm_segment*seg);
4242
externvoiddsm_unpin_mapping(dsm_segment*seg);
4343
externvoiddsm_pin_segment(dsm_segment*seg);
44+
externvoiddsm_unpin_segment(dsm_handleh);
4445
externdsm_segment*dsm_find_mapping(dsm_handleh);
4546

4647
/* Informational functions. */

‎src/include/storage/dsm_impl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ extern bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size,
7373
externbooldsm_impl_can_resize(void);
7474

7575
/* Implementation-dependent actions required to keep segment until shutdown. */
76-
externvoiddsm_impl_pin_segment(dsm_handlehandle,void*impl_private);
76+
externvoiddsm_impl_pin_segment(dsm_handlehandle,void*impl_private,
77+
void**impl_private_pm_handle);
78+
externvoiddsm_impl_unpin_segment(dsm_handlehandle,void**impl_private);
7779

7880
#endif/* DSM_IMPL_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp