Fix query cache invalidation bug.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Mon, 5 Nov 2018 12:14:58 +0000 (21:14 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Mon, 5 Nov 2018 12:14:58 +0000 (21:14 +0900)
When a DML is executed in an explicit transaction, the table oid
buffer is wiped out by pool_reset_memqcache_buffer() and query cache
is not invalidated at the commit time because there's no DML oid
exists to invalidate query cache any more. To fix this, add new bool
parameter to pool_reset_memqcache_buffer() to specify whether to reset
table oid buffer or not. When a DML is executed in an explicit
transaction, call pool_reset_memqcache_buffer(false) to preserve the
table oid buffer.

Issue reported at https://github.com/pgpool/pgpool2/issues/19.

src/query_cache/pool_memqcache.c

index d73d98ab783ff2e7b64ec6b2447d4dec9d89e671..a96c906573d19dd53b9f89faf040804417622315 100644 (file)
@@ -77,7 +77,7 @@ static void pool_discard_dml_table_oid(void);
 static void pool_invalidate_query_cache(int num_table_oids, int *table_oid, bool unlink, int dboid);
 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(void);
+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_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);
@@ -1698,10 +1698,11 @@ pool_invalidate_query_cache(int num_table_oids, int *table_oid, bool unlinkp, in
 }
 
 /*
- * Reset SELECT data buffers
+ * Reset SELECT data buffers.  If reset_dml_oids is true, call
+ * pool_discard_dml_table_oid() to reset table oids used in DML statements.
  */
 static void
-pool_reset_memqcache_buffer(void)
+pool_reset_memqcache_buffer(bool reset_dml_oids)
 {
        POOL_SESSION_CONTEXT *session_context;
 
@@ -1744,7 +1745,10 @@ pool_reset_memqcache_buffer(void)
                        session_context->query_context->temp_cache = NULL;
                }
        }
-       pool_discard_dml_table_oid();
+
+       if (reset_dml_oids)
+               pool_discard_dml_table_oid();
+
        pool_tmp_stats_reset_num_selects();
 }
 
@@ -3280,7 +3284,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                        pool_stats_count_up_num_selects(1);
 
                        /* Reset temp buffer */
-                       pool_reset_memqcache_buffer();
+                       pool_reset_memqcache_buffer(true);
                }
                else
                {
@@ -3334,7 +3338,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
        else if (is_rollback_query(node))       /* Rollback? */
        {
                /* Discard buffered data */
-               pool_reset_memqcache_buffer();
+               pool_reset_memqcache_buffer(true);
        }
        else if (is_commit_query(node)) /* Commit? */
        {
@@ -3386,7 +3390,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                /* Count up number of SELECT stats */
                pool_stats_count_up_num_selects(pool_tmp_stats_get_num_selects());
 
-               pool_reset_memqcache_buffer();
+               pool_reset_memqcache_buffer(true);
        }
        else                                            /* Non cache safe queries */
        {
@@ -3397,7 +3401,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                        {
                                /* Count up SELECT stats */
                                pool_stats_count_up_num_selects(1);
-                               pool_reset_memqcache_buffer();
+                               pool_reset_memqcache_buffer(true);
                        }
                        else
                        {
@@ -3422,7 +3426,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                                pool_invalidate_query_cache(num_oids, oids, true, dboid);
                                pool_discard_oid_maps_by_db(dboid);
                                pool_shmem_unlock();
-                               pool_reset_memqcache_buffer();
+                               pool_reset_memqcache_buffer(true);
 
                                pfree(oids);
                                ereport(DEBUG2,
@@ -3451,7 +3455,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                                        pool_invalidate_query_cache(num_oids, oids, true, 0);
                                        pool_shmem_unlock();
                                        POOL_SETMASK(&oldmask);
-                                       pool_reset_memqcache_buffer();
+                                       pool_reset_memqcache_buffer(true);
                                }
                                else
                                {
@@ -3461,7 +3465,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                                         * DML/DDL modifies the TABLE which SELECT uses.
                                         */
                                        pool_check_and_discard_cache_buffer(num_oids, oids);
-                                       pool_reset_memqcache_buffer();
+                                       pool_reset_memqcache_buffer(false);
                                }
                        }
                        else if (num_oids == 0)
@@ -3470,7 +3474,7 @@ pool_handle_query_cache(POOL_CONNECTION_POOL * backend, char *query, Node *node,
                                 * It is also necessary to clear cache buffers in case of no
                                 * oid queries (like BEGIN, CHECKPOINT, VACUUM, etc) too.
                                 */
-                               pool_reset_memqcache_buffer();
+                               pool_reset_memqcache_buffer(true);
                        }
                }
        }