2020 * ===== shared segment init (postmaster startup) =====
2121 *
2222 * _PG_init
23- * -> ispell_shmem_startup (registered as a hook)
23+ * -> ispell_shmem_startup (registered as a hook)
2424 *
2525 * ===== dictionary init (backend) =====
2626 *
2727 * 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
4242 *
4343 * ===== dictionary reinit after reset (backend) =====
4444 *
4545 * 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
5050*/
5151
5252#include "postgres.h"
@@ -166,7 +166,7 @@ _PG_fini(void)
166166static void
167167ispell_shmem_startup ()
168168{
169- bool found = false ;
169+ bool found = FALSE ;
170170 char * segment ;
171171
172172 if (prev_shmem_startup_hook )
@@ -185,6 +185,12 @@ ispell_shmem_startup()
185185 /* Was the shared memory segment already initialized? */
186186 if (!found )
187187 {
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+ }
188194 memset (segment , 0 , max_ispell_mem_size ());
189195
190196 #if PG_VERSION_NUM >= 90600
@@ -288,13 +294,9 @@ static void
288294init_shared_dict (DictInfo * info , char * dictFile , char * affFile , char * stopFile )
289295{
290296 int size ;
291-
292297 SharedIspellDict * shdict = NULL ;
293298 SharedStopList * shstop = NULL ;
294299
295- IspellDict * dict ;
296- StopList stoplist ;
297-
298300 /* DICTIONARY + AFFIXES */
299301
300302 /* 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)
313315 /* load the dictionary (word list) if not yet defined */
314316 if (shdict == NULL )
315317 {
318+ IspellDict * dict ;
319+
316320 dict = (IspellDict * ) palloc0 (sizeof (IspellDict ));
317321
318322 NIStartBuild (dict );
@@ -383,6 +387,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
383387 /* load the stopwords if not yet defined */
384388 if (shstop == NULL )
385389 {
390+ StopList stoplist ;
391+
386392 readstoplist (stopFile , & stoplist , lowerstr );
387393
388394 size = sizeStopList (& stoplist , stopFile );
@@ -407,11 +413,14 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile)
407413 info -> lookup = GetCurrentTimestamp ();
408414
409415 memcpy (info -> dictFile , dictFile , strlen (dictFile ) + 1 );
410- memcpy (info -> affixFile , dictFile , strlen (affFile )+ 1 );
416+ memcpy (info -> affixFile , affFile , strlen (affFile ) + 1 );
411417 if (stopFile != NULL )
412- memcpy (info -> stopFile , dictFile , strlen (stopFile ) + 1 );
418+ memcpy (info -> stopFile , stopFile , strlen (stopFile ) + 1 );
413419 else
414420 memset (info -> stopFile , 0 , sizeof (info -> stopFile ));
421+
422+ /* save current context as long-lived */
423+ info -> saveCntx = CurrentMemoryContext ;
415424}
416425
417426Datum dispell_init (PG_FUNCTION_ARGS );
@@ -498,6 +507,9 @@ dispell_mem_used(PG_FUNCTION_ARGS)
498507 * The StopWords parameter is optional, the two other are required.
499508 *
500509 * 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.
501513 */
502514Datum
503515dispell_init (PG_FUNCTION_ARGS )
@@ -586,7 +598,7 @@ dispell_lexize(PG_FUNCTION_ARGS)
586598 char * txt ;
587599 TSLexeme * res ;
588600 TSLexeme * ptr ,
589- * cptr ;
601+ * cptr ;
590602
591603 if (len <= 0 )
592604 PG_RETURN_POINTER (NULL );
@@ -599,11 +611,27 @@ dispell_lexize(PG_FUNCTION_ARGS)
599611 /* do we need to reinit the dictionary? was the dict reset since the lookup */
600612 if (timestamp_cmp_internal (info -> lookup , segment_info -> lastReset ) < 0 )
601613 {
614+ DictInfo saveInfo = * info ;
615+ MemoryContext ctx ;
616+
602617 /* relock in exclusive mode */
603618 LWLockRelease (segment_info -> lock );
604619 LWLockAcquire (segment_info -> lock , LW_EXCLUSIVE );
605620
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 );
607635 }
608636
609637 res = NINormalizeWord (& (info -> dict ), txt );
@@ -697,13 +725,13 @@ copySPNode(SPNode *node)
697725 SPNode * copy = NULL ;
698726
699727 if (node == NULL )
700- return NULL ;
728+ return NULL ;
701729
702730 copy = (SPNode * ) shalloc (offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
703731 memcpy (copy , node , offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
704732
705733 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 );
707735
708736 return copy ;
709737}
@@ -715,7 +743,7 @@ sizeSPNode(SPNode *node)
715743 int size = 0 ;
716744
717745 if (node == NULL )
718- return 0 ;
746+ return 0 ;
719747
720748 size = MAXALIGN (offsetof(SPNode , data ) + sizeof (SPNodeData ) * node -> length );
721749
@@ -815,7 +843,7 @@ sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile)
815843 /* copy affix data */
816844 size += MAXALIGN (sizeof (char * ) * dict -> nAffixData );
817845 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 );
819847
820848 return size ;
821849}
@@ -842,10 +870,10 @@ dispell_list_dicts(PG_FUNCTION_ARGS)
842870
843871 /* Build a tuple descriptor for our result type */
844872 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" )));
849877
850878 /*
851879 * generate attribute metadata needed later to produce tuples from raw
0 commit comments