invalidate plan cache in master_update_node

If a plan is cached by postgres but a user uses master_update_node, then
when the plan cache is used for the updated node, they will get the old
nodename/nodepost in the plan. This is because the plan cache doesn't
know about the master_update_node. This could be a problem in prepared
statements or anything that goes into plancache. As a solution the plan
cache is invalidated inside master_update_node.
copy/fix/clearPrepareCache
SaitTalhaNisanci 2020-04-15 10:06:28 +03:00 committed by Sait Talha Nisanci
parent 2d50f63841
commit 8d8bc974ef
3 changed files with 117 additions and 0 deletions

View File

@ -7,6 +7,7 @@
#include "postgres.h" #include "postgres.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "funcapi.h" #include "funcapi.h"
#include "utils/plancache.h"
#include "access/genam.h" #include "access/genam.h"
@ -749,6 +750,12 @@ master_update_node(PG_FUNCTION_ARGS)
LockShardsInPlacementListMetadata(placementList, AccessExclusiveLock); LockShardsInPlacementListMetadata(placementList, AccessExclusiveLock);
} }
/*
* if we have planned statements such as prepared statements, we should clear the cache so that
* the planned cache doesn't return the old nodename/nodepost.
*/
ResetPlanCache();
UpdateNodeLocation(nodeId, newNodeNameString, newNodePort); UpdateNodeLocation(nodeId, newNodeNameString, newNodePort);
/* we should be able to find the new node from the metadata */ /* we should be able to find the new node from the metadata */

View File

@ -311,6 +311,92 @@ SELECT verify_metadata('localhost', :worker_1_port),
t | t t | t
(1 row) (1 row)
---------------------------------------------------------------------
-- Test that master_update_node invalidates the plan cache
---------------------------------------------------------------------
PREPARE foo AS SELECT COUNT(*) FROM dist_table_1 WHERE a = 1;
SET citus.log_remote_commands = ON;
-- trigger caching for prepared statements
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
SELECT master_update_node(:nodeid_1, '127.0.0.1', :worker_1_port);
master_update_node
---------------------------------------------------------------------
(1 row)
SELECT wait_until_metadata_sync(30000);
NOTICE: issuing LISTEN metadata_sync
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
wait_until_metadata_sync
---------------------------------------------------------------------
(1 row)
-- make sure the nodename changed.
EXECUTE foo;
NOTICE: issuing SELECT count(*) AS count FROM public.dist_table_1_102010 dist_table_1 WHERE (a OPERATOR(pg_catalog.=) 1)
DETAIL: on server postgres@127.0.0.1:57637 connectionId: xxxxxxx
count
---------------------------------------------------------------------
0
(1 row)
SET citus.log_remote_commands TO OFF;
--------------------------------------------------------------------- ---------------------------------------------------------------------
-- Test that master_update_node can appear in a prepared transaction. -- Test that master_update_node can appear in a prepared transaction.
--------------------------------------------------------------------- ---------------------------------------------------------------------

View File

@ -139,6 +139,30 @@ ROLLBACK;
SELECT verify_metadata('localhost', :worker_1_port), SELECT verify_metadata('localhost', :worker_1_port),
verify_metadata('localhost', :worker_2_port); verify_metadata('localhost', :worker_2_port);
--------------------------------------------------------------------------
-- Test that master_update_node invalidates the plan cache
--------------------------------------------------------------------------
PREPARE foo AS SELECT COUNT(*) FROM dist_table_1 WHERE a = 1;
SET citus.log_remote_commands = ON;
-- trigger caching for prepared statements
EXECUTE foo;
EXECUTE foo;
EXECUTE foo;
EXECUTE foo;
EXECUTE foo;
EXECUTE foo;
EXECUTE foo;
SELECT master_update_node(:nodeid_1, '127.0.0.1', :worker_1_port);
SELECT wait_until_metadata_sync(30000);
-- make sure the nodename changed.
EXECUTE foo;
SET citus.log_remote_commands TO OFF;
-------------------------------------------------------------------------- --------------------------------------------------------------------------
-- Test that master_update_node can appear in a prepared transaction. -- Test that master_update_node can appear in a prepared transaction.
-------------------------------------------------------------------------- --------------------------------------------------------------------------