20
20
* ===== shared segment init (postmaster startup) =====
21
21
*
22
22
* _PG_init
23
- * -> ispell_shmem_startup (registered as a hook)
23
+ * -> ispell_shmem_startup (registered as a hook)
24
24
*
25
25
* ===== dictionary init (backend) =====
26
26
*
27
27
* dispell_init
28
- * -> init_shared_dict
29
- * -> get_shared_dict
30
- * -> NIStartBuild
31
- * -> NIImportDictionary
32
- * -> NIImportAffixes
33
- * -> NISortDictionary
34
- * -> NISortAffixes
35
- * -> NIFinishBuild
36
- * -> sizeIspellDict
37
- * -> copyIspellDict
38
- * -> copySPNode
39
- * -> get_shared_stop_list
40
- * -> readstoplist
41
- * -> copyStopList
28
+ * -> init_shared_dict
29
+ * -> get_shared_dict
30
+ * -> NIStartBuild
31
+ * -> NIImportDictionary
32
+ * -> NIImportAffixes
33
+ * -> NISortDictionary
34
+ * -> NISortAffixes
35
+ * -> NIFinishBuild
36
+ * -> sizeIspellDict
37
+ * -> copyIspellDict
38
+ * -> copySPNode
39
+ * -> get_shared_stop_list
40
+ * -> readstoplist
41
+ * -> copyStopList
42
42
*
43
43
* ===== dictionary reinit after reset (backend) =====
44
44
*
45
45
* dispell_lexize
46
- * -> timestamp of lookup < last reset
47
- * -> init_shared_dict
48
- * (see dispell_init above)
49
- * -> SharedNINormalizeWord
46
+ * -> timestamp of lookup < last reset
47
+ * -> init_shared_dict
48
+ * (see dispell_init above)
49
+ * -> SharedNINormalizeWord
50
50
*/
51
51
52
52
#include "postgres.h"
@@ -166,7 +166,7 @@ _PG_fini(void)
166
166
static void
167
167
ispell_shmem_startup ()
168
168
{
169
- bool found = false ;
169
+ bool found = FALSE ;
170
170
char * segment ;
171
171
172
172
if (prev_shmem_startup_hook )
@@ -185,6 +185,12 @@ ispell_shmem_startup()
185
185
/* Was the shared memory segment already initialized? */
186
186
if (!found )
187
187
{
188
+ if (segment == NULL ) {
189
+ ereport (ERROR ,
190
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
191
+ errmsg ("Cannot acquire %d kB of shared memory" ,
192
+ max_ispell_mem_size_kb )));
193
+ }
188
194
memset (segment , 0 , max_ispell_mem_size ());
189
195
190
196
#if PG_VERSION_NUM >= 90600
@@ -288,13 +294,9 @@ static void
288
294
init_shared_dict (DictInfo * info , char * dictFile , char * affFile , char * stopFile )
289
295
{
290
296
int size ;
291
-
292
297
SharedIspellDict * shdict = NULL ;
293
298
SharedStopList * shstop = NULL ;
294
299
295
- IspellDict * dict ;
296
- StopList stoplist ;
297
-
298
300
/* DICTIONARY + AFFIXES */
299
301
300
302
/* TODO This should probably check that the filenames are not NULL, and maybe that
@@ -313,6 +315,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
313
315
/* load the dictionary (word list) if not yet defined */
314
316
if (shdict == NULL )
315
317
{
318
+ IspellDict * dict ;
319
+
316
320
dict = (IspellDict * ) palloc0 (sizeof (IspellDict ));
317
321
318
322
NIStartBuild (dict );
@@ -383,6 +387,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
383
387
/* load the stopwords if not yet defined */
384
388
if (shstop == NULL )
385
389
{
390
+ StopList stoplist ;
391
+
386
392
readstoplist (stopFile , & stoplist , lowerstr );
387
393
388
394
size = sizeStopList (& stoplist , stopFile );
@@ -407,11 +413,14 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
407
413
info -> lookup = GetCurrentTimestamp ();
408
414
409
415
memcpy (info -> dictFile , dictFile , strlen (dictFile ) + 1 );
410
- memcpy (info -> affixFile , dictFile , strlen (affFile )+ 1 );
416
+ memcpy (info -> affixFile , affFile , strlen (affFile ) + 1 );
411
417
if (stopFile != NULL )
412
- memcpy (info -> stopFile , dictFile , strlen (stopFile ) + 1 );
418
+ memcpy (info -> stopFile , stopFile , strlen (stopFile ) + 1 );
413
419
else
414
420
memset (info -> stopFile , 0 , sizeof (info -> stopFile ));
421
+
422
+ /* save current context as long-lived */
423
+ info -> saveCntx = CurrentMemoryContext ;
415
424
}
416
425
417
426
Datum dispell_init (PG_FUNCTION_ARGS );
@@ -498,6 +507,9 @@ dispell_mem_used(PG_FUNCTION_ARGS)
498
507
* The StopWords parameter is optional, the two other are required.
499
508
*
500
509
* If any of the filenames are incorrect, the call to init_shared_dict will fail.
510
+ *
511
+ * Do not call it directly - it saves current memory context as long-lived
512
+ * context.
501
513
*/
502
514
Datum
503
515
dispell_init (PG_FUNCTION_ARGS )
@@ -586,7 +598,7 @@ dispell_lexize(PG_FUNCTION_ARGS)
586
598
char * txt ;
587
599
TSLexeme * res ;
588
600
TSLexeme * ptr ,
589
- * cptr ;
601
+ * cptr ;
590
602
591
603
if (len <= 0 )
592
604
PG_RETURN_POINTER (NULL );
@@ -599,11 +611,27 @@ dispell_lexize(PG_FUNCTION_ARGS)
599
611
/* do we need to reinit the dictionary? was the dict reset since the lookup */
600
612
if (timestamp_cmp_internal (info -> lookup , segment_info -> lastReset ) < 0 )
601
613
{
614
+ DictInfo saveInfo = * info ;
615
+ MemoryContext ctx ;
616
+
602
617
/* relock in exclusive mode */
603
618
LWLockRelease (segment_info -> lock );
604
619
LWLockAcquire (segment_info -> lock , LW_EXCLUSIVE );
605
620
606
- init_shared_dict (info , info -> dictFile , info -> affixFile , info -> stopFile );
621
+ /*
622
+ * info is allocated in info->saveCntx, so that's why we use a copy of
623
+ * info here
624
+ */
625
+
626
+ MemoryContextResetAndDeleteChildren (saveInfo .saveCntx );
627
+ ctx = MemoryContextSwitchTo (saveInfo .saveCntx );
628
+
629
+ info = palloc0 (sizeof (* info ));
630
+
631
+ init_shared_dict (info , saveInfo .dictFile ,
632
+ saveInfo .affixFile , saveInfo .stopFile );
633
+
634
+ MemoryContextSwitchTo (ctx );
607
635
}
608
636
609
637
res = NINormalizeWord (& (info -> dict ), txt );
@@ -697,13 +725,13 @@ copySPNode(SPNode *node)
697
725
SPNode * copy = NULL ;
698
726
699
727
if (node == NULL )
700
- return NULL ;
728
+ return NULL ;
701
729
702
730
copy = (SPNode * ) shalloc (offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
703
731
memcpy (copy , node , offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
704
732
705
733
for (i = 0 ; i < node -> length ; i ++ )
706
- copy -> data [i ].node = copySPNode (node -> data [i ].node );
734
+ copy -> data [i ].node = copySPNode (node -> data [i ].node );
707
735
708
736
return copy ;
709
737
}
@@ -715,7 +743,7 @@ sizeSPNode(SPNode *node)
715
743
int size = 0 ;
716
744
717
745
if (node == NULL )
718
- return 0 ;
746
+ return 0 ;
719
747
720
748
size = MAXALIGN (offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
721
749
@@ -815,7 +843,7 @@ sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile)
815
843
/* copy affix data */
816
844
size += MAXALIGN (sizeof (char * ) * dict -> nAffixData );
817
845
for (i = 0 ; i < dict -> nAffixData ; i ++ )
818
- size += MAXALIGN (sizeof (char ) * strlen (dict -> AffixData [i ]) + 1 );
846
+ size += MAXALIGN (sizeof (char ) * strlen (dict -> AffixData [i ]) + 1 );
819
847
820
848
return size ;
821
849
}
@@ -842,10 +870,10 @@ dispell_list_dicts(PG_FUNCTION_ARGS)
842
870
843
871
/* Build a tuple descriptor for our result type */
844
872
if (get_call_result_type (fcinfo , NULL , & tupdesc ) != TYPEFUNC_COMPOSITE )
845
- ereport (ERROR ,
846
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
847
- errmsg ("function returning record called in context "
848
- "that cannot accept type record" )));
873
+ ereport (ERROR ,
874
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
875
+ errmsg ("function returning record called in context "
876
+ "that cannot accept type record" )));
849
877
850
878
/*
851
879
* generate attribute metadata needed later to produce tuples from raw
0 commit comments