diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2d1ed143e0..86a6df131b 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 eab98b0760..d8c8cc8cc3 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 34fe4c5b3c..1c8c9c5ed7 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..03fe615b1c
--- /dev/null
+++ b/src/backend/tsearch/ts_shared.c
@@ -0,0 +1,163 @@
+/*-------------------------------------------------------------------------
+ *
+ * ts_shared.c
+ *	  tsearch shared memory management
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/backend/tsearch/ts_shared.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "storage/dsm.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
+#include "tsearch/ts_shared.h"
+
+/* XXX should it be a GUC-variable? */
+#define NUM_DICTIONARIES	20
+
+typedef struct
+{
+	char		dictfile[MAXPGPATH];
+	char		afffile[MAXPGPATH];
+} TsearchDictKey;
+
+typedef struct
+{
+	TsearchDictKey key;
+	dsm_handle	dict_dsm;
+} TsearchDictEntry;
+
+typedef struct
+{
+	LWLock		lock;
+} TsearchCtlData;
+
+static TsearchCtlData *tsearch_ctl;
+static HTAB *dict_table;
+
+/*
+ * Return handle to a dynamic shared memory.
+ *
+ * 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.
+ */
+void *
+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;
+	void	   *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;
+		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,
+												 &found);
+
+		Assert(!found);
+
+		/* The lock was free so add new entry */
+		ispell_dict = allocate_cb(dictbuild, dictfile, afffile, &ispell_size);
+
+		seg = dsm_create(ispell_size, 0);
+		res = dsm_segment_address(seg);
+		memcpy(res, ispell_dict, ispell_size);
+
+		pfree(ispell_dict);
+
+		entry->dict_dsm = dsm_segment_handle(seg);
+
+		/* Remain attached until end of postmaster */
+		dsm_pin_segment(seg);
+
+		dsm_detach(seg);
+	}
+	else
+	{
+		seg = dsm_attach(entry->dict_dsm);
+		res = dsm_segment_address(seg);
+
+		dsm_detach(seg);
+	}
+
+	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", TsearchShmemSize(), &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",
+							   NUM_DICTIONARIES, NUM_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(NUM_DICTIONARIES,
+											 sizeof(TsearchDictEntry)));
+
+	return size;
+}
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 97e4a0bbbd..3d41073b60 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..ded3a7c2ec
--- /dev/null
+++ b/src/include/tsearch/ts_shared.h
@@ -0,0 +1,30 @@
+/*-------------------------------------------------------------------------
+ *
+ * ts_shared.h
+ *	  tsearch shared memory management
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/tsearch/ts_shared.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TS_SHARED_H
+#define TS_SHARED_H
+
+#include "c.h"
+
+typedef void *(*ispell_build_callback) (void *dictbuild,
+										const char *dictfile,
+										const char *afffile,
+										Size *size);
+
+extern void *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 */
