35
35
36
36
#include "lib/ilist.h"
37
37
#include "miscadmin.h"
38
+ #include "port/pg_bitutils.h"
38
39
#include "storage/dsm.h"
39
40
#include "storage/ipc.h"
40
41
#include "storage/lwlock.h"
41
42
#include "storage/pg_shmem.h"
43
+ #include "utils/freepage.h"
42
44
#include "utils/guc.h"
43
45
#include "utils/memutils.h"
44
46
#include "utils/resowner_private.h"
@@ -76,6 +78,8 @@ typedef struct dsm_control_item
76
78
{
77
79
dsm_handle handle ;
78
80
uint32 refcnt ; /* 2+ = active, 1 = moribund, 0 = gone */
81
+ size_t first_page ;
82
+ size_t npages ;
79
83
void * impl_private_pm_handle ; /* only needed on Windows */
80
84
bool pinned ;
81
85
} dsm_control_item ;
@@ -95,10 +99,15 @@ static dsm_segment *dsm_create_descriptor(void);
95
99
static bool dsm_control_segment_sane (dsm_control_header * control ,
96
100
Size mapped_size );
97
101
static uint64 dsm_control_bytes_needed (uint32 nitems );
102
+ static inline dsm_handle make_main_region_dsm_handle (int slot );
103
+ static inline bool is_main_region_dsm_handle (dsm_handle handle );
98
104
99
105
/* Has this backend initialized the dynamic shared memory system yet? */
100
106
static bool dsm_init_done = false;
101
107
108
+ /* Preallocated DSM space in the main shared memory region. */
109
+ static void * dsm_main_space_begin = NULL ;
110
+
102
111
/*
103
112
* List of dynamic shared memory segments used by this backend.
104
113
*
@@ -171,7 +180,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
171
180
{
172
181
Assert (dsm_control_address == NULL );
173
182
Assert (dsm_control_mapped_size == 0 );
174
- dsm_control_handle = random ();
183
+ dsm_control_handle = random () << 1 ; /* Even numbers only */
175
184
if (dsm_control_handle == DSM_HANDLE_INVALID )
176
185
continue ;
177
186
if (dsm_impl_op (DSM_OP_CREATE , dsm_control_handle , segsize ,
@@ -247,8 +256,12 @@ dsm_cleanup_using_control_segment(dsm_handle old_control_handle)
247
256
if (refcnt == 0 )
248
257
continue ;
249
258
250
- /* Log debugging information . */
259
+ /* If it was using the main shmem area, there is nothing to do . */
251
260
handle = old_control -> item [i ].handle ;
261
+ if (is_main_region_dsm_handle (handle ))
262
+ continue ;
263
+
264
+ /* Log debugging information. */
252
265
elog (DEBUG2 , "cleaning up orphaned dynamic shared memory with ID %u (reference count %u)" ,
253
266
handle , refcnt );
254
267
@@ -348,8 +361,11 @@ dsm_postmaster_shutdown(int code, Datum arg)
348
361
if (dsm_control -> item [i ].refcnt == 0 )
349
362
continue ;
350
363
351
- /* Log debugging information. */
352
364
handle = dsm_control -> item [i ].handle ;
365
+ if (is_main_region_dsm_handle (handle ))
366
+ continue ;
367
+
368
+ /* Log debugging information. */
353
369
elog (DEBUG2 , "cleaning up orphaned dynamic shared memory with ID %u" ,
354
370
handle );
355
371
@@ -418,6 +434,45 @@ dsm_set_control_handle(dsm_handle h)
418
434
}
419
435
#endif
420
436
437
+ /*
438
+ * Reserve some space in the main shared memory segment for DSM segments.
439
+ */
440
+ size_t
441
+ dsm_estimate_size (void )
442
+ {
443
+ return 1024 * 1024 * (size_t ) min_dynamic_shared_memory ;
444
+ }
445
+
446
+ /*
447
+ * Initialize space in the main shared memory segment for DSM segments.
448
+ */
449
+ void
450
+ dsm_shmem_init (void )
451
+ {
452
+ size_t size = dsm_estimate_size ();
453
+ bool found ;
454
+
455
+ if (size == 0 )
456
+ return ;
457
+
458
+ dsm_main_space_begin = ShmemInitStruct ("Preallocated DSM" , size , & found );
459
+ if (!found )
460
+ {
461
+ FreePageManager * fpm = (FreePageManager * ) dsm_main_space_begin ;
462
+ size_t first_page = 0 ;
463
+ size_t pages ;
464
+
465
+ /* Reserve space for the FreePageManager. */
466
+ while (first_page * FPM_PAGE_SIZE < sizeof (FreePageManager ))
467
+ ++ first_page ;
468
+
469
+ /* Initialize it and give it all the rest of the space. */
470
+ FreePageManagerInitialize (fpm , dsm_main_space_begin );
471
+ pages = (size / FPM_PAGE_SIZE ) - first_page ;
472
+ FreePageManagerPut (fpm , first_page , pages );
473
+ }
474
+ }
475
+
421
476
/*
422
477
* Create a new dynamic shared memory segment.
423
478
*
@@ -434,6 +489,10 @@ dsm_create(Size size, int flags)
434
489
dsm_segment * seg ;
435
490
uint32 i ;
436
491
uint32 nitems ;
492
+ size_t npages = 0 ;
493
+ size_t first_page = 0 ;
494
+ FreePageManager * dsm_main_space_fpm = dsm_main_space_begin ;
495
+ bool using_main_dsm_region = false;
437
496
438
497
/* Unsafe in postmaster (and pointless in a stand-alone backend). */
439
498
Assert (IsUnderPostmaster );
@@ -444,27 +503,63 @@ dsm_create(Size size, int flags)
444
503
/* Create a new segment descriptor. */
445
504
seg = dsm_create_descriptor ();
446
505
447
- /* Loop until we find an unused segment identifier. */
448
- for (;;)
506
+ /*
507
+ * Lock the control segment while we try to allocate from the main shared
508
+ * memory area, if configured.
509
+ */
510
+ if (dsm_main_space_fpm )
449
511
{
450
- Assert (seg -> mapped_address == NULL && seg -> mapped_size == 0 );
451
- seg -> handle = random ();
452
- if (seg -> handle == DSM_HANDLE_INVALID ) /* Reserve sentinel */
453
- continue ;
454
- if (dsm_impl_op (DSM_OP_CREATE , seg -> handle , size , & seg -> impl_private ,
455
- & seg -> mapped_address , & seg -> mapped_size , ERROR ))
456
- break ;
512
+ npages = size / FPM_PAGE_SIZE ;
513
+ if (size % FPM_PAGE_SIZE > 0 )
514
+ ++ npages ;
515
+
516
+ LWLockAcquire (DynamicSharedMemoryControlLock , LW_EXCLUSIVE );
517
+ if (FreePageManagerGet (dsm_main_space_fpm , npages , & first_page ))
518
+ {
519
+ /* We can carve out a piece of the main shared memory segment. */
520
+ seg -> mapped_address = (char * ) dsm_main_space_begin +
521
+ first_page * FPM_PAGE_SIZE ;
522
+ seg -> mapped_size = npages * FPM_PAGE_SIZE ;
523
+ using_main_dsm_region = true;
524
+ /* We'll choose a handle below. */
525
+ }
457
526
}
458
527
459
- /* Lock the control segment so we can register the new segment. */
460
- LWLockAcquire (DynamicSharedMemoryControlLock , LW_EXCLUSIVE );
528
+ if (!using_main_dsm_region )
529
+ {
530
+ /*
531
+ * We need to create a new memory segment. Loop until we find an
532
+ * unused segment identifier.
533
+ */
534
+ if (dsm_main_space_fpm )
535
+ LWLockRelease (DynamicSharedMemoryControlLock );
536
+ for (;;)
537
+ {
538
+ Assert (seg -> mapped_address == NULL && seg -> mapped_size == 0 );
539
+ seg -> handle = random () << 1 ; /* Even numbers only */
540
+ if (seg -> handle == DSM_HANDLE_INVALID ) /* Reserve sentinel */
541
+ continue ;
542
+ if (dsm_impl_op (DSM_OP_CREATE , seg -> handle , size , & seg -> impl_private ,
543
+ & seg -> mapped_address , & seg -> mapped_size , ERROR ))
544
+ break ;
545
+ }
546
+ LWLockAcquire (DynamicSharedMemoryControlLock , LW_EXCLUSIVE );
547
+ }
461
548
462
549
/* Search the control segment for an unused slot. */
463
550
nitems = dsm_control -> nitems ;
464
551
for (i = 0 ; i < nitems ; ++ i )
465
552
{
466
553
if (dsm_control -> item [i ].refcnt == 0 )
467
554
{
555
+ if (using_main_dsm_region )
556
+ {
557
+ seg -> handle = make_main_region_dsm_handle (i );
558
+ dsm_control -> item [i ].first_page = first_page ;
559
+ dsm_control -> item [i ].npages = npages ;
560
+ }
561
+ else
562
+ Assert (!is_main_region_dsm_handle (seg -> handle ));
468
563
dsm_control -> item [i ].handle = seg -> handle ;
469
564
/* refcnt of 1 triggers destruction, so start at 2 */
470
565
dsm_control -> item [i ].refcnt = 2 ;
@@ -479,9 +574,12 @@ dsm_create(Size size, int flags)
479
574
/* Verify that we can support an additional mapping. */
480
575
if (nitems >= dsm_control -> maxitems )
481
576
{
577
+ if (using_main_dsm_region )
578
+ FreePageManagerPut (dsm_main_space_fpm , first_page , npages );
482
579
LWLockRelease (DynamicSharedMemoryControlLock );
483
- dsm_impl_op (DSM_OP_DESTROY , seg -> handle , 0 , & seg -> impl_private ,
484
- & seg -> mapped_address , & seg -> mapped_size , WARNING );
580
+ if (!using_main_dsm_region )
581
+ dsm_impl_op (DSM_OP_DESTROY , seg -> handle , 0 , & seg -> impl_private ,
582
+ & seg -> mapped_address , & seg -> mapped_size , WARNING );
485
583
if (seg -> resowner != NULL )
486
584
ResourceOwnerForgetDSM (seg -> resowner , seg );
487
585
dlist_delete (& seg -> node );
@@ -495,6 +593,12 @@ dsm_create(Size size, int flags)
495
593
}
496
594
497
595
/* Enter the handle into a new array slot. */
596
+ if (using_main_dsm_region )
597
+ {
598
+ seg -> handle = make_main_region_dsm_handle (nitems );
599
+ dsm_control -> item [i ].first_page = first_page ;
600
+ dsm_control -> item [i ].npages = npages ;
601
+ }
498
602
dsm_control -> item [nitems ].handle = seg -> handle ;
499
603
/* refcnt of 1 triggers destruction, so start at 2 */
500
604
dsm_control -> item [nitems ].refcnt = 2 ;
@@ -580,6 +684,12 @@ dsm_attach(dsm_handle h)
580
684
/* Otherwise we've found a match. */
581
685
dsm_control -> item [i ].refcnt ++ ;
582
686
seg -> control_slot = i ;
687
+ if (is_main_region_dsm_handle (seg -> handle ))
688
+ {
689
+ seg -> mapped_address = (char * ) dsm_main_space_begin +
690
+ dsm_control -> item [i ].first_page * FPM_PAGE_SIZE ;
691
+ seg -> mapped_size = dsm_control -> item [i ].npages * FPM_PAGE_SIZE ;
692
+ }
583
693
break ;
584
694
}
585
695
LWLockRelease (DynamicSharedMemoryControlLock );
@@ -597,8 +707,9 @@ dsm_attach(dsm_handle h)
597
707
}
598
708
599
709
/* Here's where we actually try to map the segment. */
600
- dsm_impl_op (DSM_OP_ATTACH , seg -> handle , 0 , & seg -> impl_private ,
601
- & seg -> mapped_address , & seg -> mapped_size , ERROR );
710
+ if (!is_main_region_dsm_handle (seg -> handle ))
711
+ dsm_impl_op (DSM_OP_ATTACH , seg -> handle , 0 , & seg -> impl_private ,
712
+ & seg -> mapped_address , & seg -> mapped_size , ERROR );
602
713
603
714
return seg ;
604
715
}
@@ -688,8 +799,9 @@ dsm_detach(dsm_segment *seg)
688
799
*/
689
800
if (seg -> mapped_address != NULL )
690
801
{
691
- dsm_impl_op (DSM_OP_DETACH , seg -> handle , 0 , & seg -> impl_private ,
692
- & seg -> mapped_address , & seg -> mapped_size , WARNING );
802
+ if (!is_main_region_dsm_handle (seg -> handle ))
803
+ dsm_impl_op (DSM_OP_DETACH , seg -> handle , 0 , & seg -> impl_private ,
804
+ & seg -> mapped_address , & seg -> mapped_size , WARNING );
693
805
seg -> impl_private = NULL ;
694
806
seg -> mapped_address = NULL ;
695
807
seg -> mapped_size = 0 ;
@@ -729,10 +841,15 @@ dsm_detach(dsm_segment *seg)
729
841
* other reason, the postmaster may not have any better luck than
730
842
* we did. There's not much we can do about that, though.
731
843
*/
732
- if (dsm_impl_op (DSM_OP_DESTROY , seg -> handle , 0 , & seg -> impl_private ,
844
+ if (is_main_region_dsm_handle (seg -> handle ) ||
845
+ dsm_impl_op (DSM_OP_DESTROY , seg -> handle , 0 , & seg -> impl_private ,
733
846
& seg -> mapped_address , & seg -> mapped_size , WARNING ))
734
847
{
735
848
LWLockAcquire (DynamicSharedMemoryControlLock , LW_EXCLUSIVE );
849
+ if (is_main_region_dsm_handle (seg -> handle ))
850
+ FreePageManagerPut ((FreePageManager * ) dsm_main_space_begin ,
851
+ dsm_control -> item [control_slot ].first_page ,
852
+ dsm_control -> item [control_slot ].npages );
736
853
Assert (dsm_control -> item [control_slot ].handle == seg -> handle );
737
854
Assert (dsm_control -> item [control_slot ].refcnt == 1 );
738
855
dsm_control -> item [control_slot ].refcnt = 0 ;
@@ -894,10 +1011,15 @@ dsm_unpin_segment(dsm_handle handle)
894
1011
* pass the mapped size, mapped address, and private data as NULL
895
1012
* here.
896
1013
*/
897
- if (dsm_impl_op (DSM_OP_DESTROY , handle , 0 , & junk_impl_private ,
1014
+ if (is_main_region_dsm_handle (handle ) ||
1015
+ dsm_impl_op (DSM_OP_DESTROY , handle , 0 , & junk_impl_private ,
898
1016
& junk_mapped_address , & junk_mapped_size , WARNING ))
899
1017
{
900
1018
LWLockAcquire (DynamicSharedMemoryControlLock , LW_EXCLUSIVE );
1019
+ if (is_main_region_dsm_handle (handle ))
1020
+ FreePageManagerPut ((FreePageManager * ) dsm_main_space_begin ,
1021
+ dsm_control -> item [control_slot ].first_page ,
1022
+ dsm_control -> item [control_slot ].npages );
901
1023
Assert (dsm_control -> item [control_slot ].handle == handle );
902
1024
Assert (dsm_control -> item [control_slot ].refcnt == 1 );
903
1025
dsm_control -> item [control_slot ].refcnt = 0 ;
@@ -1094,3 +1216,28 @@ dsm_control_bytes_needed(uint32 nitems)
1094
1216
return offsetof(dsm_control_header , item )
1095
1217
+ sizeof (dsm_control_item ) * (uint64 ) nitems ;
1096
1218
}
1219
+
1220
+ static inline dsm_handle
1221
+ make_main_region_dsm_handle (int slot )
1222
+ {
1223
+ dsm_handle handle ;
1224
+
1225
+ /*
1226
+ * We need to create a handle that doesn't collide with any existing extra
1227
+ * segment created by dsm_impl_op(), so we'll make it odd. It also
1228
+ * mustn't collide with any other main area pseudo-segment, so we'll
1229
+ * include the slot number in some of the bits. We also want to make an
1230
+ * effort to avoid newly created and recently destroyed handles from being
1231
+ * confused, so we'll make the rest of the bits random.
1232
+ */
1233
+ handle = 1 ;
1234
+ handle |= slot << 1 ;
1235
+ handle |= random () << (pg_leftmost_one_pos32 (dsm_control -> maxitems ) + 1 );
1236
+ return handle ;
1237
+ }
1238
+
1239
+ static inline bool
1240
+ is_main_region_dsm_handle (dsm_handle handle )
1241
+ {
1242
+ return handle & 1 ;
1243
+ }
0 commit comments