pgpool2.git / summary / log / commit / refs
commit 46917d5458a82c75e98b247a74b7ee1827666159
Author: Takuma Hoshiai <hoshiai@sraoss.co.jp>
Date: Mon Feb 25 07:32:44 2019 +0000
Add new 'enable_shared_relcache' parameter.
The relation cache were stored in local cache of child processes, so all child processes executed same query to get relation cache.
If enable_shared_relcache is on, the relation cache is stored in memory cache and all child process share it.
It will expect to reduce the load that same query is executed.
doc.ja/src/sgml/misc-config.sgml | 48 ++++++
doc/src/sgml/misc-config.sgml | 29 ++++
src/config/pool_config_variables.c | 10 ++
src/include/pool_config.h | 3 +-
src/include/query_cache/pool_memqcache.h | 7 +-
src/main/pgpool_main.c | 4 +-
src/protocol/child.c | 5 +-
src/protocol/pool_process_query.c | 3 +-
src/query_cache/pool_memqcache.c | 151 +++++++++++++++--
src/sample/pgpool.conf.sample | 5 +
src/sample/pgpool.conf.sample-logical | 5 +
src/sample/pgpool.conf.sample-master-slave | 5 +
src/sample/pgpool.conf.sample-replication | 5 +
src/sample/pgpool.conf.sample-stream | 5 +
.../tests/025.enable_shared_relcache/test.sh | 69 ++++++++
src/utils/pool_process_reporting.c | 7 +-
src/utils/pool_relcache.c | 186 ++++++++++++++++++++-
17 files changed, 516 insertions(+), 31 deletions(-)
diff --git a/doc.ja/src/sgml/misc-config.sgml b/doc.ja/src/sgml/misc-config.sgml
index 43b5fdc06..39aa3412d 100644
--- a/doc.ja/src/sgml/misc-config.sgml
+++ b/doc.ja/src/sgml/misc-config.sgml
@@ -95,6 +95,54 @@
</listitem>
</varlistentry>
+ <varlistentry id="guc-enable-shared-relcache" xreflabel="enable_shared_relcache">
+ <term><varname>enable_shared_relcache</varname> (<type>boolean</type>)
+ <indexterm>
+<!--
+ <primary><varname>enable_shared_relcache</varname> configuration parameter</primary>
+-->
+ <primary><varname>enable_shared_relcache</varname> 設定パラメータ</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+<!--
+ Setting to on, relation cache shared among <productname>Pgpool-II</productname>
+ child processes using the query cache. Default is off. Each child process
+ executed same query to refer to system catalog from <productname>PostgreSQL</productname>,
+ but using query cache can expect to execute only same query once.
+ Expiration time on query cache is <xref linkend="guc-relcache-expire"> parameter.
+ This parameter enables even if <xref linkend="guc-memory-cache-enabled"> is off.
+-->
+onにするとクエリキャッシュを利用して子プロセス間でリレーションキャッシュを共有します。
+デフォルトはoffです。
+それぞれの子プロセスは<productname>PostgreSQL</productname>のシステムカタログを参照するために同じクエリを実行していましたが、クエリキャッシュにより同じクエリの実行を1回だけとすることが期待できます。
+クエリキャッシュ上の寿命は、<xref linkend="guc-relcache-expire">の値となります。
+本パラメータは、<xref linkend="guc-memory-cache-enabled">がoffの場合も有効です。
+ </para>
+ <para>
+<!--
+ <productname>Pgpool-II</productname> searh relation cache on local
+ for a cache entry first, if this is on. When it is not found on relation cache,
+ query cache is searched for it next. If it is found on query cache,
+ it is copied to relation cache on local. if a cache entry is not found
+ on anywhere, execute the query for <productname>PostgreSQL</productname>,
+ the result is registered with relation cache and local cache.
+-->
+このパラメータがonなら、<productname>Pgpool-II</productname>はローカルのリレーションキャッシュをまず検索します。
+該当するキャッシュエントリが見つからない場合は、次にクエリキャッシュを検索します。
+もしクエリキャッシュに該当エントリが見つかったら、ローカルキャッシュにコピーします。
+見つからなかった場合には、<productname>PostgreSQL</productname>にクエリを発行して問い合わせを実行し、結果をクエリキャッシュに登録するとともに、ローカルキャッシュにも登録します。
+ </para>
+ <para>
+<!--
+ This parameter can only be set at server start.
+-->
+このパラメータはサーバ起動時にのみ設定可能です
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-check-temp-table" xreflabel="check_temp_table">
<term><varname>check_temp_table</varname> (<type>boolean</type>)
<indexterm>
diff --git a/doc/src/sgml/misc-config.sgml b/doc/src/sgml/misc-config.sgml
index 2774642de..5b27f483d 100644
--- a/doc/src/sgml/misc-config.sgml
+++ b/doc/src/sgml/misc-config.sgml
@@ -65,6 +65,35 @@
</listitem>
</varlistentry>
+ <varlistentry id="guc-enable-shared-relcache" xreflabel="enable_shared_relcache">
+ <term><varname>enable_shared_relcache</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>enable_shared_relcache</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Setting to on, relation cache shared among <productname>Pgpool-II</productname>
+ child processes using the query cache. Default is off. Each child process
+ executed same query to refer to system catalog from <productname>PostgreSQL</productname>,
+ but using query cache can expect to execute only same query once.
+ Expiration time on query cache is <xref linkend="guc-relcache-expire"> parameter.
+ This parameter enables even if <xref linkend="guc-memory-cache-enabled"> is off.
+ </para>
+ <para>
+ <productname>Pgpool-II</productname> searh relation cache on local
+ for a cache entry first, if this is on. When it is not found on relation cache,
+ query cache is searched for it next. If it is found on query cache,
+ it is copied to relation cache on local. if a cache entry is not found
+ on anywhere, execute the query for <productname>PostgreSQL</productname>,
+ the result is registered with relation cache and local cache.
+ </para>
+ <para>
+ This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-check-temp-table" xreflabel="check_temp_table">
<term><varname>check_temp_table</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/config/pool_config_variables.c b/src/config/pool_config_variables.c
index 4e0fffe63..63dd46d40 100644
--- a/src/config/pool_config_variables.c
+++ b/src/config/pool_config_variables.c
@@ -508,6 +508,16 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
+ {
+ {"enable_shared_relcache", CFGCXT_INIT, CACHE_CONFIG,
+ "relation cache stored in memory cache.",
+ CONFIG_VAR_TYPE_BOOL, false, 0
+ },
+ &g_pool_config.enable_shared_relcache,
+ false,
+ NULL, NULL, NULL
+ },
+
{
{"memqcache_auto_cache_invalidation", CFGCXT_RELOAD, CACHE_CONFIG,
"Automatically deletes the cache related to the updated tables.",
diff --git a/src/include/pool_config.h b/src/include/pool_config.h
index f98e0cf2f..dd6626985 100644
--- a/src/include/pool_config.h
+++ b/src/include/pool_config.h
@@ -6,7 +6,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2018 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -338,6 +338,7 @@ typedef struct
int relcache_size; /* number of relation cache life entry */
bool check_temp_table; /* enable temporary table check */
bool check_unlogged_table; /* enable unlogged table check */
+ bool enable_shared_relcache; /* If true, relation cache stored in memory cache */
/*
* followings are for regex support and do not exist in the configuration
diff --git a/src/include/query_cache/pool_memqcache.h b/src/include/query_cache/pool_memqcache.h
index ee0d23bac..e93536204 100644
--- a/src/include/query_cache/pool_memqcache.h
+++ b/src/include/query_cache/pool_memqcache.h
@@ -6,7 +6,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2012 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -103,6 +103,7 @@ typedef struct
{
unsigned int total_length; /* total length in bytes including myself */
time_t timestamp; /* cache creation time */
+ int expire; /* cache expire */
} POOL_CACHE_ITEM_HEADER;
typedef struct
@@ -237,6 +238,9 @@ extern POOL_STATUS pool_fetch_from_memory_cache(POOL_CONNECTION * frontend,
POOL_CONNECTION_POOL * backend,
char *contents, bool *foundp);
+extern int pool_fetch_cache(POOL_CONNECTION_POOL * backend, const char *query, char **buf, size_t *len);
+extern int pool_catalog_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_t datalen);
+
extern bool pool_is_likely_select(char *query);
extern bool pool_is_table_in_black_list(const char *table_name);
extern bool pool_is_table_in_white_list(const char *table_name);
@@ -276,5 +280,6 @@ extern void pool_discard_temp_query_cache(POOL_TEMP_QUERY_CACHE * temp_cache);
extern void pool_shmem_lock(void);
extern void pool_shmem_unlock(void);
+extern bool pool_is_shmem_lock(void);
#endif /* POOL_MEMQCACHE_H */
diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c
index 718f4d459..4668d3830 100644
--- a/src/main/pgpool_main.c
+++ b/src/main/pgpool_main.c
@@ -5,7 +5,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2018 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -3598,7 +3598,7 @@ initialize_shared_mem_objects(bool clear_memcache_oidmaps)
/*
* Initialize shared memory cache
*/
- if (pool_config->memory_cache_enabled)
+ if (pool_config->memory_cache_enabled || pool_config->enable_shared_relcache)
{
if (pool_is_shmem_cache())
{
diff --git a/src/protocol/child.c b/src/protocol/child.c
index 7dba3e9fa..75a2545b5 100644
--- a/src/protocol/child.c
+++ b/src/protocol/child.c
@@ -5,7 +5,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2018 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -1276,7 +1276,8 @@ child_will_go_down(int code, Datum arg)
if (accepted)
connection_count_down();
- if (pool_config->memory_cache_enabled && !pool_is_shmem_cache())
+ if ((pool_config->memory_cache_enabled || pool_config->enable_shared_relcache)
+ && !pool_is_shmem_cache())
{
memcached_disconnect();
}
diff --git a/src/protocol/pool_process_query.c b/src/protocol/pool_process_query.c
index c64dcae25..cfa0e2103 100644
--- a/src/protocol/pool_process_query.c
+++ b/src/protocol/pool_process_query.c
@@ -120,7 +120,8 @@ pool_process_query(POOL_CONNECTION * frontend,
/* Try to connect memcached */
- if (pool_config->memory_cache_enabled && !pool_is_shmem_cache())
+ if ((pool_config->memory_cache_enabled || pool_config->enable_shared_relcache)
+ && !pool_is_shmem_cache())
{
memcached_connect();
}
diff --git a/src/query_cache/pool_memqcache.c b/src/query_cache/pool_memqcache.c
index a96c90657..a13e8f073 100644
--- a/src/query_cache/pool_memqcache.c
+++ b/src/query_cache/pool_memqcache.c
@@ -3,7 +3,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2018 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -55,7 +55,6 @@
#include "utils/palloc.h"
#include "utils/memutils.h"
-
#ifdef USE_MEMCACHED
memcached_st *memc;
#endif
@@ -65,7 +64,6 @@ static char *encode_key(const char *s, char *buf, POOL_CONNECTION_POOL * backend
static void dump_cache_data(const char *data, size_t len);
#endif
static int pool_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_t datalen, int num_oids, int *oids);
-static int pool_fetch_cache(POOL_CONNECTION_POOL * backend, const char *query, char **buf, size_t *len);
static int send_cached_messages(POOL_CONNECTION * frontend, const char *qcache, int qcachelen);
static void send_message(POOL_CONNECTION * conn, char kind, int len, const char *data);
#ifdef USE_MEMCACHED
@@ -78,7 +76,7 @@ static void pool_invalidate_query_cache(int num_table_oids, int *table_oid, bool
static int pool_get_database_oid(void);
static void pool_add_table_oid_map(POOL_CACHEKEY * cachkey, int num_table_oids, int *table_oids);
static void pool_reset_memqcache_buffer(bool reset_dml_oids);
-static POOL_CACHEID * pool_add_item_shmem_cache(POOL_QUERY_HASH * query_hash, char *data, int size);
+static POOL_CACHEID * pool_add_item_shmem_cache(POOL_QUERY_HASH * query_hash, char *data, int size, time_t expire);
static POOL_CACHEID * pool_find_item_on_shmem_cache(POOL_QUERY_HASH * query_hash);
static char *pool_get_item_shmem_cache(POOL_QUERY_HASH * query_hash, int *size, int *sts);
static POOL_QUERY_CACHE_ARRAY * pool_add_query_cache_array(POOL_QUERY_CACHE_ARRAY * cache_array, POOL_TEMP_QUERY_CACHE * cache);
@@ -124,6 +122,11 @@ static void put_back_hash_element(volatile POOL_HASH_ELEMENT * element);
static bool is_free_hash_element(void);
static void inject_cached_message(POOL_CONNECTION * backend, char *qcache, int qcachelen);
+/*
+ * if true, shared memory is locked in this process now.
+ */
+static int is_shmem_locked;
+
/*
* Connect to Memcached
*/
@@ -253,11 +256,11 @@ pool_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_
ereport(DEBUG1,
(errmsg("commiting SELECT results to cache storage"),
errdetail("Query=\"%s\"", query)));
-
#ifdef DEBUG
dump_cache_data(data, datalen);
#endif
+
/* encode md5key for memcached */
encode_key(query, tmpkey, backend);
ereport(DEBUG2,
@@ -290,7 +293,7 @@ pool_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_
}
else
{
- cacheid = pool_add_item_shmem_cache(&query_hash, data, datalen);
+ cacheid = pool_add_item_shmem_cache(&query_hash, data, datalen,memqcache_expire);
if (cacheid == NULL)
{
ereport(LOG,
@@ -326,21 +329,126 @@ pool_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_
}
#endif
+/*
+ * Register cache id to oid map
+ */
+ pool_add_table_oid_map(&cachekey, num_oids, oids);
+
+ return 0;
+}
+
+/*
+ * Commit SELECT system catalog results to cache storage.
+ */
+int
+pool_catalog_commit_cache(POOL_CONNECTION_POOL * backend, char *query, char *data, size_t datalen)
+{
+#ifdef USE_MEMCACHED
+ memcached_return rc;
+#endif
+ POOL_CACHEKEY cachekey;
+ char tmpkey[MAX_KEY];
+ time_t memqcache_expire;
+
/*
- * Register cache id to oid map
+ * get_buflen() will return -1 if query result exceeds memqcache_maxcache
*/
- pool_add_table_oid_map(&cachekey, num_oids, oids);
+ if (datalen == -1)
+ {
+ return -1;
+ }
+
+ /* query disabled */
+ if (strlen(query) <= 0)
+ {
+ return -1;
+ }
+ ereport(DEBUG1,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("Query=\"%s\"", query)));
+
+#ifdef DEBUG
+ dump_cache_data(data, datalen);
+#endif
+
+ /* encode md5key for memcached */
+ encode_key(query, tmpkey, backend);
+ ereport(DEBUG2,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("search key : \"%s\"", tmpkey)));
+
+ memcpy(cachekey.hashkey, tmpkey, 32);
+
+ memqcache_expire = pool_config->relcache_expire;
+ ereport(DEBUG1,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("memqcache_expire = %ld", memqcache_expire)));
+
+ if (pool_is_shmem_cache())
+ {
+ POOL_CACHEID *cacheid;
+ POOL_QUERY_HASH query_hash;
+ memcpy(query_hash.query_hash, tmpkey, sizeof(query_hash.query_hash));
+
+ cacheid = pool_hash_search(&query_hash);
+
+ if (cacheid != NULL)
+ {
+ ereport(DEBUG1,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("item already exists")));
+
+ return 0;
+ }
+ else
+ {
+ cacheid = pool_add_item_shmem_cache(&query_hash, data, datalen, memqcache_expire);
+ if (cacheid == NULL)
+ {
+ ereport(LOG,
+ (errmsg("failed to add item to shmem cache")));
+ return -1;
+ }
+ else
+ {
+ ereport(DEBUG2,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("blockid: %d itemid: %d",
+ cacheid->blockid, cacheid->itemid)));
+ }
+ cachekey.cacheid.blockid = cacheid->blockid;
+ cachekey.cacheid.itemid = cacheid->itemid;
+ }
+ }
+
+#ifdef USE_MEMCACHED
+ else
+ {
+ rc = memcached_set(memc, tmpkey, 32,
+ data, datalen, (time_t) memqcache_expire, 0);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ ereport(WARNING,
+ (errmsg("cache commit failed with error:\"%s\"", memcached_strerror(memc, rc))));
+ return -1;
+ }
+ ereport(DEBUG1,
+ (errmsg("commiting relation cache to cache storage"),
+ errdetail("set cache succeeded")));
+ }
+#endif
return 0;
}
+
/*
* Fetch from memory cache.
* Return:
* 0: fetch success,
* 1: not found
*/
-static int
+int
pool_fetch_cache(POOL_CONNECTION_POOL * backend, const char *query, char **buf, size_t *len)
{
char *ptr;
@@ -2115,7 +2223,7 @@ pool_update_fsmm(POOL_CACHE_BLOCKID blockid, size_t free_space)
* The cache id is overwritten by the subsequent call to this function.
* On error returns NULL.
*/
-static POOL_CACHEID * pool_add_item_shmem_cache(POOL_QUERY_HASH * query_hash, char *data, int size)
+static POOL_CACHEID * pool_add_item_shmem_cache(POOL_QUERY_HASH * query_hash, char *data, int size, time_t expire)
{
static POOL_CACHEID cacheid;
POOL_CACHE_BLOCKID blockid;
@@ -2320,6 +2428,7 @@ static POOL_CACHEID * pool_add_item_shmem_cache(POOL_QUERY_HASH * query_hash, ch
/* Fill in cache item header */
ci.header.timestamp = time(NULL);
+ ci.header.expire = expire;
ci.header.total_length = sizeof(POOL_CACHE_ITEM_HEADER) + size;
/* Calculate item body address */
@@ -2464,15 +2573,15 @@ static POOL_CACHEID * pool_find_item_on_shmem_cache(POOL_QUERY_HASH * query_hash
cih = item_header(block_address(c->blockid), c->itemid);
/* Check cache expiration */
- if (pool_config->memqcache_expire > 0)
+ if (cih->expire > 0)
{
now = time(NULL);
- if (now > (cih->timestamp + pool_config->memqcache_expire))
+ if (now > (cih->timestamp + cih->expire))
{
ereport(DEBUG1,
(errmsg("memcache finding item"),
errdetail("cache expired: now: %ld timestamp: %ld",
- now, cih->timestamp + pool_config->memqcache_expire)));
+ now, cih->timestamp + cih->expire)));
pool_delete_item_shmem_cache(c);
return NULL;
}
@@ -2696,10 +2805,10 @@ pool_wipe_out_cache_block(POOL_CACHE_BLOCKID blockid)
void
pool_shmem_lock(void)
{
- if (pool_is_shmem_cache())
+ if (pool_is_shmem_cache() && !is_shmem_locked)
{
pool_semaphore_lock(SHM_CACHE_SEM);
-
+ is_shmem_locked = true;
}
}
@@ -2709,12 +2818,22 @@ pool_shmem_lock(void)
void
pool_shmem_unlock(void)
{
- if (pool_is_shmem_cache())
+ if (pool_is_shmem_cache() && is_shmem_locked)
{
pool_semaphore_unlock(SHM_CACHE_SEM);
+ is_shmem_locked = false;
}
}
+/*
+ * check lock
+ */
+bool
+pool_is_shmem_lock(void)
+{
+ return is_shmem_locked;
+}
+
/*
* Returns cache block address specified by block id
*/
diff --git a/src/sample/pgpool.conf.sample b/src/sample/pgpool.conf.sample
index 7c6b763a6..20e734377 100644
--- a/src/sample/pgpool.conf.sample
+++ b/src/sample/pgpool.conf.sample
@@ -741,6 +741,11 @@ check_unlogged_table = on
# If you are absolutely sure that your system never uses unlogged tables
# and you want to save access to primary/master, you could turn this off.
# Default is on.
+enable_shared_relcache = off
+ # If on, relation cache stored in memory cache,
+ # the cache is shared among child process.
+ # Default is off.
+ # (change requires restart)
#------------------------------------------------------------------------------
# IN MEMORY QUERY MEMORY CACHE
diff --git a/src/sample/pgpool.conf.sample-logical b/src/sample/pgpool.conf.sample-logical
index 7dc4ed286..fde99245b 100644
--- a/src/sample/pgpool.conf.sample-logical
+++ b/src/sample/pgpool.conf.sample-logical
@@ -719,6 +719,11 @@ check_unlogged_table = on
# If you are absolutely sure that your system never uses unlogged tables
# and you want to save access to primary/master, you could turn this off.
# Default is on.
+enable_shared_relcache = off
+ # If on, relation cache stored in memory cache,
+ # the cache is shared among child process.
+ # Default is off.
+ # (change requires restart)
#------------------------------------------------------------------------------
# IN MEMORY QUERY MEMORY CACHE
diff --git a/src/sample/pgpool.conf.sample-master-slave b/src/sample/pgpool.conf.sample-master-slave
index a0195f778..5603a1117 100644
--- a/src/sample/pgpool.conf.sample-master-slave
+++ b/src/sample/pgpool.conf.sample-master-slave
@@ -739,6 +739,11 @@ check_unlogged_table = on
# If you are absolutely sure that your system never uses unlogged tables
# and you want to save access to primary/master, you could turn this off.
# Default is on.
+enable_shared_relcache = off
+ # If on, relation cache stored in memory cache,
+ # the cache is shared among child process.
+ # Default is off.
+ # (change requires restart)
#------------------------------------------------------------------------------
# IN MEMORY QUERY MEMORY CACHE
diff --git a/src/sample/pgpool.conf.sample-replication b/src/sample/pgpool.conf.sample-replication
index 6fef5d806..2544a834e 100644
--- a/src/sample/pgpool.conf.sample-replication
+++ b/src/sample/pgpool.conf.sample-replication
@@ -738,6 +738,11 @@ check_unlogged_table = on
# If you are absolutely sure that your system never uses unlogged tables
# and you want to save access to primary/master, you could turn this off.
# Default is on.
+enable_shared_relcache = off
+ # If on, relation cache stored in memory cache,
+ # the cache is shared among child process.
+ # Default is off.
+ # (change requires restart)
#------------------------------------------------------------------------------
# IN MEMORY QUERY MEMORY CACHE
diff --git a/src/sample/pgpool.conf.sample-stream b/src/sample/pgpool.conf.sample-stream
index b45147383..f0c760c26 100644
--- a/src/sample/pgpool.conf.sample-stream
+++ b/src/sample/pgpool.conf.sample-stream
@@ -738,6 +738,11 @@ check_unlogged_table = on
# If you are absolutely sure that your system never uses unlogged tables
# and you want to save access to primary/master, you could turn this off.
# Default is on.
+enable_shared_relcache = off
+ # If on, relation cache stored in memory cache,
+ # the cache is shared among child process.
+ # Default is off.
+ # (change requires restart)
#------------------------------------------------------------------------------
# IN MEMORY QUERY MEMORY CACHE
diff --git a/src/test/regression/tests/025.enable_shared_relcache/test.sh b/src/test/regression/tests/025.enable_shared_relcache/test.sh
new file mode 100755
index 000000000..f5c4d52ef
--- /dev/null
+++ b/src/test/regression/tests/025.enable_shared_relcache/test.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# test script for memqcache with memcached.
+# need to configure --with-memcached=/usr.
+# requires Java PostgreSQL JDBC driver.
+PGBENCH=$PGBENCH_PATH
+
+WHOAMI=`whoami`
+source $TESTLIBS
+TESTDIR=testdir
+PSQL=$PGBIN/psql
+
+
+rm -fr $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR
+
+# create test environment
+echo -n "creating test environment..."
+$PGPOOL_SETUP -n 2 || exit 1
+echo "done."
+
+#echo "memory_cache_enabled = off" >> etc/pgpool.conf
+echo "log_min_messages = debug1" >> etc/pgpool.conf
+echo "enable_shared_relcache = on" >> etc/pgpool.conf
+echo "relcache_expire = 60" >> etc/pgpool.conf
+
+for mode in shmem memcached
+do
+ if [ $mode = "shmem" ];then
+ echo "memqcache_method = 'shmem'" >> etc/pgpool.conf
+ elif [ $mode = "memcached" ];then
+ echo "memqcache_method = 'memcached'" >> etc/pgpool.conf
+ fi
+
+ source ./bashrc.ports
+
+ export PGPORT=$PGPOOL_PORT
+
+ ./startall
+ wait_for_pgpool_startup
+
+ # initialize tables
+ $PGBENCH -i test
+
+ $PGBENCH -C -S -c 2 -t 10 test
+
+ ./shutdownall
+
+ echo "SELECT query don not use query cache"
+ grep "commiting SELECT results to cache storage" log/pgpool.log > /dev/null 2>&1
+ if [ $? != 0 ];then
+ echo "... ok."
+ else
+ echo "... failed."
+ exit 1
+ fi
+
+ echo "relation cache use query cache"
+ grep "commiting relation cache to cache storage" log/pgpool.log > /dev/null 2>&1
+ if [ $? = 0 ];then
+ echo "... ok."
+ else
+ echo "... failed."
+ exit 1
+ fi
+done
+
+exit 0
diff --git a/src/utils/pool_process_reporting.c b/src/utils/pool_process_reporting.c
index df93e66b1..bb079fc13 100644
--- a/src/utils/pool_process_reporting.c
+++ b/src/utils/pool_process_reporting.c
@@ -5,7 +5,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2018 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -674,6 +674,11 @@ get_config(int *nrows)
StrNCpy(status[i].desc, "enable unlogged table check", POOLCONFIG_MAXDESCLEN);
i++;
+ StrNCpy(status[i].name, "enable_shared_relcache", POOLCONFIG_MAXNAMELEN);
+ snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_shared_relcache);
+ StrNCpy(status[i].desc, "If true, relation cache stored in memory cache", POOLCONFIG_MAXDESCLEN);
+ i++;
+
/*
* add for watchdog
*/
diff --git a/src/utils/pool_relcache.c b/src/utils/pool_relcache.c
index 7d857f0dc..38cf82612 100644
--- a/src/utils/pool_relcache.c
+++ b/src/utils/pool_relcache.c
@@ -5,7 +5,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2017 PgPool Global Development Group
+ * Copyright (c) 2003-2019 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -28,12 +28,16 @@
#include "pool.h"
#include "utils/pool_relcache.h"
#include "context/pool_session_context.h"
+#include "query_cache/pool_memqcache.h"
#include "pool_config.h"
#include "utils/palloc.h"
#include "utils/memutils.h"
#include "utils/elog.h"
static void SearchRelCacheErrorCb(void *arg);
+static POOL_SELECT_RESULT *query_cache_to_relation_cache(char *data, size_t size);
+static char *relation_cache_to_query_cache(POOL_SELECT_RESULT *res,size_t *size);
+
/*
* Create relation cache
@@ -107,8 +111,13 @@ pool_search_relcache(POOL_RELCACHE * relcache, POOL_CONNECTION_POOL * backend, c
int index = 0;
int local_session_id;
time_t now;
- void *result;
+ void *result;
ErrorContextCallback callback;
+ pool_sigset_t oldmask;
+ bool locked;
+ int query_cache_not_found = 1;
+ char *query_cache_data = NULL;
+ size_t query_cache_len;
local_session_id = pool_get_local_session_id();
if (local_session_id < 0)
@@ -151,6 +160,10 @@ pool_search_relcache(POOL_RELCACHE * relcache, POOL_CONNECTION_POOL * backend, c
if (relcache->cache[i].refcnt < INT_MAX)
relcache->cache[i].refcnt++;
+ ereport(DEBUG1,
+ (errmsg("hit local relation cache"),
+ errdetail("query:%s", relcache->sql)));
+
return relcache->cache[i].data;
}
}
@@ -168,7 +181,64 @@ pool_search_relcache(POOL_RELCACHE * relcache, POOL_CONNECTION_POOL * backend, c
callback.previous = error_context_stack;
error_context_stack = &callback;
- do_query(MASTER(backend), query, &res, MAJOR(backend));
+ locked = pool_is_shmem_lock();
+ /*
+ * if enable_shared_relcache is true, search query cache.
+ */
+ if (pool_config->enable_shared_relcache)
+ {
+ /* if shmem is not locked by this process, get the lock */
+ if (!locked)
+ {
+ POOL_SETMASK2(&BlockSig, &oldmask);
+ pool_shmem_lock();
+ }
+ PG_TRY();
+ {
+ /* search catalog cache in query cache */
+ query_cache_not_found = pool_fetch_cache(backend, query, &query_cache_data, &query_cache_len);
+ }
+ PG_CATCH();
+ {
+ pool_shmem_unlock();
+ POOL_SETMASK(&oldmask);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+ }
+ /* If not in query cache or not used, send query for backend. */
+ if (query_cache_not_found)
+ {
+ ereport(DEBUG1,
+ (errmsg("not hit local relation cache and query cache"),
+ errdetail("query:%s", query)));
+
+ do_query(MASTER(backend), query, &res, MAJOR(backend));
+ /* Register cache */
+ result = (*relcache->register_func) (res);
+ /* save local catalog cache in query cache */
+ if (pool_config->enable_shared_relcache)
+ {
+ query_cache_data = relation_cache_to_query_cache(res, &query_cache_len);
+ pool_catalog_commit_cache(backend, query, query_cache_data, query_cache_len);
+ }
+ }
+ else
+ {
+ ereport(DEBUG1,
+ (errmsg("hit query cache"),
+ errdetail("query:%s", query)));
+
+ /* catalog cache found in query_cache, copy local relation cache */
+ res = query_cache_to_relation_cache(query_cache_data,query_cache_len);
+ result = (*relcache->register_func) (res);
+ }
+ /* if shmem is locked by this function, unlock it */
+ if (pool_config->enable_shared_relcache && !locked)
+ {
+ pool_shmem_unlock();
+ POOL_SETMASK(&oldmask);
+ }
error_context_stack = callback.previous;
@@ -210,9 +280,6 @@ pool_search_relcache(POOL_RELCACHE * relcache, POOL_CONNECTION_POOL * backend, c
}
- /* Register cache */
- result = (*relcache->register_func) (res);
-
if (!pool_is_ignore_till_sync() && (!relcache->no_cache_if_zero || result))
{
strlcpy(relcache->cache[index].dbname, dbname, MAX_ITEM_LENGTH);
@@ -235,7 +302,8 @@ pool_search_relcache(POOL_RELCACHE * relcache, POOL_CONNECTION_POOL * backend, c
relcache->cache[index].data = result;
}
free_select_result(res);
-
+ if (query_cache_data)
+ pfree(query_cache_data);
return result;
}
@@ -301,3 +369,107 @@ string_unregister_func(void *data)
free(data);
return (void *) 0;
}
+
+static POOL_SELECT_RESULT *
+query_cache_to_relation_cache(char *data, size_t size)
+{
+ POOL_SELECT_RESULT *res;
+ char *p;
+ int i;
+ int len;
+
+ p = data;
+
+ res = palloc0(sizeof(*res));
+ res->rowdesc = palloc0(sizeof(RowDesc));
+
+ /* rowdesc */
+ res->rowdesc->num_attrs = *((int *)p);
+ p += sizeof(int);
+
+ /* numrows */
+ res->numrows = *((int *)p);
+ p += sizeof(int);
+
+ len = res->rowdesc->num_attrs * res->numrows;
+
+ res->nullflags = palloc(len * sizeof(int));
+ res->data = palloc0(len * sizeof(char *));
+
+ /* nullflags */
+ for (i = 0; i < len; i++)
+ {
+ res->nullflags[i] = *((int *)p);
+ p += sizeof(int);
+ }
+ /* data */
+ for (i = 0; i < len; i++)
+ {
+ if ( res->nullflags[i] > 0)
+ {
+ res->data[i] = palloc(res->nullflags[i] + 1);
+ memcpy(res->data[i], p, res->nullflags[i]);
+ *(res->data[i] + res->nullflags[i]) = '\0';
+ p += res->nullflags[i];
+ }
+ }
+
+ return res;
+}
+
+static char *
+relation_cache_to_query_cache(POOL_SELECT_RESULT *res,size_t *size)
+{
+ char * data;
+ char * p;
+
+ int i;
+ int array_size;
+ int mysize;
+
+ mysize = 0;
+
+ /* RoeDesc *rowdesc */
+ /* int res->rowdesc->num_attrs;*/
+ mysize += sizeof(int); /* only rodesc->num_attrs */
+ /* int numrows */
+ mysize += sizeof(int);
+ /* int *nullflags */
+ mysize += sizeof(int) * res->rowdesc->num_attrs * res->numrows;
+ /* char **data */
+ /* res->rowdesc->num_attrs * res->numrows */
+ for (i = 0; i < res->rowdesc->num_attrs * res->numrows; i++)
+ {
+ if(res->nullflags[i] > 0)
+ {
+ mysize += res->nullflags[i];
+ }
+ }
+
+ /* init array */
+ *size = mysize;
+ data = palloc(mysize + 1);
+
+ /* data copy */
+ p = data;
+ memcpy(p, &res->rowdesc->num_attrs, sizeof(int));
+ p += sizeof(int);
+ memcpy(p, &res->numrows, sizeof(int));
+ p += sizeof(int);
+
+ array_size = res->rowdesc->num_attrs * res->numrows;
+
+ memcpy(p, res->nullflags, sizeof(int) * array_size);
+ p += sizeof(int) * array_size;
+
+ for (i = 0; i < array_size; i++)
+ {
+ if( res->nullflags[i] > 0) /* NOT NULL? */
+ {
+ memcpy(p, res->data[i], res->nullflags[i]);
+ p += res->nullflags[i];
+ }
+ }
+
+ return data;
+}
[parent: 9c236d08deda]