HAWQ-1748. Idle executors keep exist instead of quit even when gp_vmem_idle_resource_timeout specified timer expires
diff --git a/src/backend/cdb/executormgr.c b/src/backend/cdb/executormgr.c
index 5a1c15d..62473d7 100644
--- a/src/backend/cdb/executormgr.c
+++ b/src/backend/cdb/executormgr.c
@@ -1096,3 +1096,27 @@
 	pfree(desc);
 }
 
+bool executormgr_has_cached_executor()
+{
+    return executor_cache.cached_num > 0;
+}
+
+bool executormgr_clean_cached_executor_filter(PoolItem item)
+{
+    SegmentDatabaseDescriptor *desc = (SegmentDatabaseDescriptor *)item;
+    return desc->conn->asyncStatus == PGASYNC_IDLE;
+}
+
+void executormgr_clean_cached_executor()
+{
+    /* go through each cached executor */
+    int cleaned = 0;
+    if (!executor_cache.init)
+    {
+        return;
+    }
+
+    cleaned = poolmgr_clean(executor_cache.pool, (PoolMgrIterateFilter) executormgr_clean_cached_executor_filter);
+    elog(DEBUG5, "cleaned %d idle executors", cleaned);
+}
+
diff --git a/src/backend/cdb/poolmgr.c b/src/backend/cdb/poolmgr.c
index eae0f04..f7194f6 100644
--- a/src/backend/cdb/poolmgr.c
+++ b/src/backend/cdb/poolmgr.c
@@ -184,3 +184,45 @@
 	return;
 }
 
+int poolmgr_clean(struct PoolMgrState *pool, PoolMgrIterateFilter filter)
+{
+    int res = 0;
+    HASH_SEQ_STATUS hash_seq;
+    PoolItemEntry *entry;
+
+    if (!pool)
+        return res;
+
+    hash_seq_init(&hash_seq, pool->hashtable);
+    while ((entry = hash_seq_search(&hash_seq)))
+    {
+        ListCell *curr = list_head(entry->list);
+        ListCell *prev = NULL;
+        while (curr != NULL)
+        {
+            PoolItem  item = lfirst(curr);
+            if (filter && !filter(item))
+            {
+                /* try next */
+                prev = curr;
+                curr = lnext(prev);
+                continue;
+            }
+
+            /* clean now */
+            res++;
+            pool->callback(item);
+            entry->list = list_delete_cell(entry->list, curr, prev);
+            if (prev != NULL)
+            {
+                curr = lnext(prev);
+            }
+            else
+            {
+                curr = list_head(entry->list);
+            }
+        }
+    }
+    return res;
+}
+
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 2d3097f..4fef10c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1399,9 +1399,9 @@
 	/*
 	 * Free gangs to free up resources on the segDBs.
 	 */
-	if (gangsExist())
+	if (executormgr_has_cached_executor())
 	{
-		cleanupAllIdleGangs();
+		executormgr_clean_cached_executor();
 	}
 
 }
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cf0123e..c122280 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4804,9 +4804,17 @@
 			 * This means giving the end user enough time to type in the next SQL statement
 			 *
 			 */
-			if (IdleSessionGangTimeout > 0 && gangsExist())
+			if (IdleSessionGangTimeout > 0 && executormgr_has_cached_executor())
+            {
 				if (!enable_sig_alarm( IdleSessionGangTimeout /* ms */, false))
+                {
 					elog(FATAL, "could not set timer for client wait timeout");
+                }
+            }
+            else if (IdleSessionGangTimeout == 0)
+            {
+                executormgr_clean_cached_executor();
+            }
 		}
 
 		IdleTracker_DeactivateProcess();
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0cf51df..b90f1ec 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5067,7 +5067,7 @@
 	{
 		{"gp_vmem_idle_resource_timeout", PGC_USERSET, CLIENT_CONN_OTHER,
 			gettext_noop("Sets the time a session can be idle (in milliseconds) before we release gangs on the segment DBs to free resources."),
-			gettext_noop("A value of 0 turns off the timeout."),
+			gettext_noop("A value of 0 closes idle gangs at once."),
 			GUC_UNIT_MS | GUC_GPDB_ADDOPT
 		},
 		&IdleSessionGangTimeout,
diff --git a/src/include/cdb/executormgr.h b/src/include/cdb/executormgr.h
index 31d44fa..ce4442d 100644
--- a/src/include/cdb/executormgr.h
+++ b/src/include/cdb/executormgr.h
@@ -98,5 +98,8 @@
 							bool is_writer, bool is_superuser);
 extern void executormgr_free_executor(struct SegmentDatabaseDescriptor *desc);
 
+extern bool executormgr_has_cached_executor();
+extern void executormgr_clean_cached_executor();
+
 #endif	/* EXECUTORMGR_H */
 
diff --git a/src/include/cdb/poolmgr.h b/src/include/cdb/poolmgr.h
index 2821dd9..8408c25 100644
--- a/src/include/cdb/poolmgr.h
+++ b/src/include/cdb/poolmgr.h
@@ -32,6 +32,8 @@
 
 extern struct PoolMgrState *poolmgr_create_pool(MemoryContext ctx, PoolMgrCleanCallback callback);
 extern bool poolmgr_drop_pool(struct PoolMgrState *pool);
+extern int poolmgr_clean(struct PoolMgrState *pool, PoolMgrIterateFilter filter);
+
 extern PoolItem poolmgr_get_item_by_name(struct PoolMgrState *pool, const char *name);
 extern PoolItem poolmgr_get_random_item(struct PoolMgrState *pool);
 extern void poolmgr_put_item(struct PoolMgrState *pool, const char *name, PoolItem item);