diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e4a01699e4..858423354e 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1355,6 +1355,36 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-shared-dictionaries" xreflabel="shared_dictionaries">
+      <term><varname>shared_dictionaries</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>shared_dictionaries</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Sets the maximum number of text search dictionaries loaded into shared
+        memory.  The default is 10 dictionaries.
+       </para>
+
+       <para>
+        Currently controls only loading of <application>Ispell</application>
+        dictionaries (see <xref linkend="textsearch-ispell-dictionary"/>).
+        After compiling the dictionary it will be copied into shared memory.
+        Another backends on first use of the dictionary will use it from shared
+        memory, so it doesn't need to compile the dictionary second time.
+        <literal>DictFile</literal> and <literal>AffFile</literal> are used to
+        search the dictionary in shared memory.
+       </para>
+
+       <para>
+        If the number of simultaneously loaded dictionaries reaches the maximum
+        allowed number then a new dictionary will be loaded into local memory of
+        a backend.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-huge-pages" xreflabel="huge_pages">
       <term><varname>huge_pages</varname> (<type>enum</type>)
       <indexterm>
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 0c86a581c0..c7dce8cac5 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -44,6 +44,7 @@
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
 #include "storage/spin.h"
+#include "tsearch/ts_shared.h"
 #include "utils/backend_random.h"
 #include "utils/snapmgr.h"
 
@@ -150,6 +151,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		size = add_size(size, SyncScanShmemSize());
 		size = add_size(size, AsyncShmemSize());
 		size = add_size(size, BackendRandomShmemSize());
+		size = add_size(size, TsearchShmemSize());
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -271,6 +273,11 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	AsyncShmemInit();
 	BackendRandomShmemInit();
 
+	/*
+	 * Set up shared memory to tsearch
+	 */
+	TsearchShmemInit();
+
 #ifdef EXEC_BACKEND
 
 	/*
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 71caac1a1f..2446db7266 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -520,6 +520,7 @@ RegisterLWLockTranches(void)
 						  "shared_tuplestore");
 	LWLockRegisterTranche(LWTRANCHE_TBM, "tbm");
 	LWLockRegisterTranche(LWTRANCHE_PARALLEL_APPEND, "parallel_append");
+	LWLockRegisterTranche(LWTRANCHE_TSEARCH_DSA, "tsearch_dsa");
 
 	/* Register named tranches. */
 	for (i = 0; i < NamedLWLockTrancheRequests; i++)
diff --git a/src/backend/tsearch/Makefile b/src/backend/tsearch/Makefile
index 227468ae9e..860cd196e9 100644
--- a/src/backend/tsearch/Makefile
+++ b/src/backend/tsearch/Makefile
@@ -26,7 +26,7 @@ DICTFILES_PATH=$(addprefix dicts/,$(DICTFILES))
 OBJS = ts_locale.o ts_parse.o wparser.o wparser_def.o dict.o \
 	dict_simple.o dict_synonym.o dict_thesaurus.o \
 	dict_ispell.o regis.o spell.o \
-	to_tsany.o ts_selfuncs.o ts_typanalyze.o ts_utils.o
+	to_tsany.o ts_selfuncs.o ts_shared.o ts_typanalyze.o ts_utils.o
 
 include $(top_srcdir)/src/backend/common.mk
 
diff --git a/src/backend/tsearch/ts_shared.c b/src/backend/tsearch/ts_shared.c
new file mode 100644
index 0000000000..4682eab506
--- /dev/null
+++ b/src/backend/tsearch/ts_shared.c
@@ -0,0 +1,179 @@
+/*-------------------------------------------------------------------------
+ *
+ * ts_shared.c
+ *	  tsearch shared memory management
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/tsearch/ts_shared.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
+#include "tsearch/ts_shared.h"
+
+
+/*
+ * Hash table structures
+ */
+
+typedef struct
+{
+	char		dictfile[MAXPGPATH];
+	char		afffile[MAXPGPATH];
+} TsearchDictKey;
+
+typedef struct
+{
+	TsearchDictKey key;
+	dsm_handle	dict_dsm;
+} TsearchDictEntry;
+
+static HTAB *dict_table;
+
+/*
+ * Shared struct for locking
+ */
+typedef struct
+{
+	LWLock		lock;
+} TsearchCtlData;
+
+static TsearchCtlData *tsearch_ctl;
+
+/*
+ * GUC variable for maximum number of shared dictionaries
+ */
+int			shared_dictionaries = 10;
+
+/*
+ * Return handle to a dynamic shared memory using hash table. If shared memory
+ * for dictfile and afffile doesn't allocated yet, do it.
+ *
+ * dictbuild: building structure for the dictionary.
+ * dictfile: .dict file of the dictionary.
+ * afffile: .aff file of the dictionary.
+ * allocate_cb: function to build the dictionary, if it wasn't found in DSM.
+ */
+dsm_handle
+ispell_shmem_location(void *dictbuild,
+					  const char *dictfile, const char *afffile,
+					  ispell_build_callback allocate_cb)
+{
+	TsearchDictKey key;
+	TsearchDictEntry *entry;
+	bool		found;
+	dsm_segment *seg;
+	dsm_handle	res;
+
+	StrNCpy(key.dictfile, dictfile, MAXPGPATH);
+	StrNCpy(key.afffile, afffile, MAXPGPATH);
+
+refind_entry:
+	LWLockAcquire(&tsearch_ctl->lock, LW_SHARED);
+
+	entry = (TsearchDictEntry *) hash_search(dict_table, &key, HASH_FIND,
+											 &found);
+
+	/* Dictionary wasn't load into memory */
+	if (!found)
+	{
+		void	   *ispell_dict,
+				   *dict_location;
+		Size		ispell_size;
+
+		/* Try to get exclusive lock */
+		LWLockRelease(&tsearch_ctl->lock);
+		if (!LWLockAcquireOrWait(&tsearch_ctl->lock, LW_EXCLUSIVE))
+		{
+			/*
+			 * The lock was released by another backend, try to refind an entry.
+			 */
+			goto refind_entry;
+		}
+
+		entry = (TsearchDictEntry *) hash_search(dict_table, &key,
+												 HASH_ENTER_NULL,
+												 &found);
+
+		/*
+		 * There is no space in shared hash table, let backend to build the
+		 * dictionary within its memory context.
+		 */
+		if (entry == NULL)
+			return DSM_HANDLE_INVALID;
+
+		/* The lock was free so add new entry */
+		ispell_dict = allocate_cb(dictbuild, dictfile, afffile, &ispell_size);
+
+		seg = dsm_create(ispell_size, 0);
+		dict_location = dsm_segment_address(seg);
+		memcpy(dict_location, ispell_dict, ispell_size);
+
+		pfree(ispell_dict);
+
+		entry->dict_dsm = dsm_segment_handle(seg);
+		res = entry->dict_dsm;
+
+		/* Remain attached until end of postmaster */
+		dsm_pin_segment(seg);
+
+		dsm_detach(seg);
+	}
+	else
+	{
+		res = entry->dict_dsm;
+	}
+
+	LWLockRelease(&tsearch_ctl->lock);
+
+	return res;
+}
+
+/*
+ * Allocate and initialize tsearch-related shared memory.
+ */
+void
+TsearchShmemInit(void)
+{
+	HASHCTL		ctl;
+	bool		found;
+
+	tsearch_ctl = (TsearchCtlData *)
+		ShmemInitStruct("Full Text Search Ctl", sizeof(TsearchCtlData), &found);
+
+	if (!found)
+		LWLockInitialize(&tsearch_ctl->lock, LWTRANCHE_TSEARCH_DSA);
+
+	memset(&ctl, 0, sizeof(ctl));
+	ctl.keysize = sizeof(TsearchDictKey);
+	ctl.entrysize = sizeof(TsearchDictEntry);
+
+	dict_table = ShmemInitHash("Shared Tsearch Lookup Table",
+							   shared_dictionaries, shared_dictionaries,
+							   &ctl,
+							   HASH_ELEM | HASH_BLOBS);
+}
+
+/*
+ * Report shared memory space needed by TsearchShmemInit.
+ */
+Size
+TsearchShmemSize(void)
+{
+	Size		size = 0;
+
+	/* size of service structure */
+	size = add_size(size, MAXALIGN(sizeof(TsearchCtlData)));
+
+	/* size of lookup hash table */
+	size = add_size(size, hash_estimate_size(shared_dictionaries,
+											 sizeof(TsearchDictEntry)));
+
+	return size;
+}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 72f6be329e..dbc9bf93f0 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -76,6 +76,7 @@
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
+#include "tsearch/ts_shared.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
@@ -2910,6 +2911,19 @@ static struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"shared_dictionaries", PGC_POSTMASTER, RESOURCES_MEM,
+			gettext_noop("Sets the maximum number of text search dictionaries loaded into shared memory."),
+			gettext_noop("Currently controls only loading of Ispell dictionaries. "
+						 "If the number of simultaneously loaded dictionaries "
+						 "reaches the maximum allowed number then a new dictionary "
+						 "will be loaded into local memory of a backend.")
+		},
+		&shared_dictionaries,
+		10, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 69f40f04b0..b83ffe6a39 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -131,6 +131,7 @@
 					#   mmap
 					# use none to disable dynamic shared memory
 					# (change requires restart)
+#shared_dictionaries = 10		# (change requires restart)
 
 # - Disk -
 
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index c21bfe2f66..2bb80cdd26 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -219,6 +219,7 @@ typedef enum BuiltinTrancheIds
 	LWTRANCHE_SHARED_TUPLESTORE,
 	LWTRANCHE_TBM,
 	LWTRANCHE_PARALLEL_APPEND,
+	LWTRANCHE_TSEARCH_DSA,
 	LWTRANCHE_FIRST_USER_DEFINED
 }			BuiltinTrancheIds;
 
diff --git a/src/include/tsearch/ts_shared.h b/src/include/tsearch/ts_shared.h
new file mode 100644
index 0000000000..4bcfb437ef
--- /dev/null
+++ b/src/include/tsearch/ts_shared.h
@@ -0,0 +1,35 @@
+/*-------------------------------------------------------------------------
+ *
+ * ts_shared.h
+ *	  tsearch shared memory management
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ *
+ * src/include/tsearch/ts_shared.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TS_SHARED_H
+#define TS_SHARED_H
+
+#include "c.h"
+#include "storage/dsm.h"
+
+/*
+ * GUC variable for maximum number of shared dictionaries
+ */
+extern int shared_dictionaries;
+
+typedef void *(*ispell_build_callback) (void *dictbuild,
+										const char *dictfile,
+										const char *afffile,
+										Size *size);
+
+extern dsm_handle ispell_shmem_location(void *dictbuild,
+									  const char *dictfile, const char *afffile,
+									  ispell_build_callback allocate_cb);
+
+extern void TsearchShmemInit(void);
+extern Size TsearchShmemSize(void);
+
+#endif							/* TS_SHARED_H */
