Skip to content

Commit 09d4e59

Browse files
committed
Feature: Add new PCP command to invalidate query cache.
Previously it was not possible to invalidate query cache without restarting pgpool. This commit adds new PCP command "pcp_invalidate_query_cache" to invalidate query cache without restarting pgpool. Note this command only places a query cache invalidate request on shared the shared memory. The actual invalidation is performed by pgpool child process. The reasons for the PCP process cannot remove cache directly are: 1) the connection handle to memcached server is not managed by PCP process. 2) removing shared memory query cache needs an interlock using pool_shmem_ock() which may not work well on PCP process. Also a function used here (pool_clear_memory_cache()) uses PG_TRY, which is only usable in pgpool child process. If pgpool child process finds such a request, the process invalidates all query cache on the shared memory. If the query cache storage is memcached, then pgpool issues memcached_flush() so that all query cache on memcached are flushed immediately. Note that the timing for pgpool child process to check the invalidation request is after processing current query or response from backend. This means that if all pgpool child process sit idle, the request will not be processed until any of them receives a messages from either frontend or backend. Another note is, about query cache statistics shown by "show pool_cache" command. Since the cache invalidation does not clear the statistics, some of them (num_cache_hits and num_selects) continue to increase even after the cache invalidation. Initializing the statistics at the same could be possible but I am not sure if all users want to do it. Discussion:https://www.pgpool.net/pipermail/pgpool-hackers/2024-October/004525.html
1 parent c4a53cc commit 09d4e59

File tree

15 files changed

+290
-165
lines changed

15 files changed

+290
-165
lines changed

doc.ja/src/sgml/ref/allfiles.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Complete list of usable sgml source files in this directory.
1919
<!ENTITY pcpRecoveryNode SYSTEM "pcp_recovery_node.sgml">
2020
<!ENTITY pcpReloadConfig SYSTEM "pcp_reload_config.sgml">
2121
<!ENTITY pcpLogRotate SYSTEM "pcp_log_rotate.sgml">
22+
<!ENTITY pcpInvalidateCache SYSTEM "pcp_invalidate_query_cache.sgml">
2223
<!ENTITY pgMd5 SYSTEM "pg_md5.sgml">
2324
<!ENTITY pgEnc SYSTEM "pg_enc.sgml">
2425
<!ENTITY wdCli SYSTEM "wd_cli.sgml">

doc.ja/src/sgml/reference.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
&pcpReloadConfig;
163163
&pcpRecoveryNode;
164164
&pcpLogRotate;
165+
&pcpInvalidateCache;
165166

166167
</reference>
167168

doc/src/sgml/ref/allfiles.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Complete list of usable sgml source files in this directory.
1919
<!ENTITY pcpRecoveryNode SYSTEM "pcp_recovery_node.sgml">
2020
<!ENTITY pcpReloadConfig SYSTEM "pcp_reload_config.sgml">
2121
<!ENTITY pcpLogRotate SYSTEM "pcp_log_rotate.sgml">
22+
<!ENTITY pcpInvalidateCache SYSTEM "pcp_invalidate_query_cache.sgml">
2223
<!ENTITY pgMd5 SYSTEM "pg_md5.sgml">
2324
<!ENTITY pgEnc SYSTEM "pg_enc.sgml">
2425
<!ENTITY wdCli SYSTEM "wd_cli.sgml">

doc/src/sgml/reference.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
&pcpReloadConfig;
112112
&pcpRecoveryNode;
113113
&pcpLogRotate;
114+
&pcpInvalidateCache;
114115

115116
</reference>
116117

src/include/pcp/libpcp_ext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* pgpool: a language independent connection pool server for PostgreSQL
55
* written by Tatsuo Ishii
66
*
7-
* Copyright (c) 2003-2023 PgPool Global Development Group
7+
* Copyright (c) 2003-2024 PgPool Global Development Group
88
*
99
* Permission to use, copy, modify, and distribute this software and
1010
* its documentation for any purpose and without fee is hereby
@@ -382,6 +382,7 @@ extern PCPResultInfo * pcp_process_count(PCPConnInfo * pcpConn);
382382
extern PCPResultInfo * pcp_process_info(PCPConnInfo * pcpConn, int pid);
383383
extern PCPResultInfo * pcp_reload_config(PCPConnInfo * pcpConn,char command_scope);
384384
extern PCPResultInfo * pcp_log_rotate(PCPConnInfo * pcpConn,char command_scope);
385+
extern PCPResultInfo * pcp_invalidate_query_cache(PCPConnInfo * pcpConn);
385386

386387
extern PCPResultInfo * pcp_detach_node(PCPConnInfo * pcpConn, int nid);
387388
extern PCPResultInfo * pcp_detach_node_gracefully(PCPConnInfo * pcpConn, int nid);

src/include/pool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ typedef struct
454454
bool follow_primary_lock_held_remotely; /* true when lock is held by
455455
watchdog coordinator*/
456456
bool follow_primary_ongoing; /* true if follow primary command is ongoing */
457+
bool query_cache_invalidate_request; /* true if pcp_invalidate_query_cache requested */
457458
} POOL_REQUEST_INFO;
458459

459460
/* description of row. corresponding to RowDescription message */

src/include/query_cache/pool_memqcache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,6 @@ extern void InvalidateQueryCache(int tableoid, int dboid);
305305

306306
extern void pool_init_whole_cache_blocks(void);
307307

308-
extern int delete_all_cache_on_memcached(void);
308+
extern void clear_query_cache(void);
309309

310310
#endif /* POOL_MEMQCACHE_H */

src/libs/pcp/pcp.c

Lines changed: 99 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* pgpool: a language independent connection pool server for PostgreSQL
99
* written by Tatsuo Ishii
1010
*
11-
* Copyright (c) 2003-2021 PgPool Global Development Group
11+
* Copyright (c) 2003-2024 PgPool Global Development Group
1212
*
1313
* Permission to use, copy, modify, and distribute this software and
1414
* its documentation for any purpose and without fee is hereby
@@ -390,132 +390,140 @@ static PCPResultInfo * process_pcp_response(PCPConnInfo * pcpConn, char sentMsg)
390390

391391
switch (toc)
392392
{
393-
case 'r': /* Authentication Response */
394-
{
395-
if (sentMsg != 'R')
396-
{
397-
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
398-
}
399-
else if (strcmp(buf, "AuthenticationOK") == 0)
400-
{
401-
pcpConn->connState = PCP_CONNECTION_OK;
402-
setResultStatus(pcpConn, PCP_RES_COMMAND_OK);
403-
}
404-
else
405-
{
406-
pcp_internal_error(pcpConn,
407-
"ERROR: authentication failed. reason=\"%s\"", buf);
408-
setResultStatus(pcpConn, PCP_RES_BACKEND_ERROR);
409-
}
410-
}
393+
case 'a': /* set configuration parameter */
394+
if (sentMsg != 'A')
395+
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
396+
else
397+
process_command_complete_response(pcpConn, buf, rsize);
411398
break;
412-
case 'm':
413-
if (sentMsg != 'M')
399+
400+
case 'b': /* status request */
401+
if (sentMsg != 'B')
414402
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
415403
else
416-
process_salt_info_response(pcpConn, buf, rsize);
404+
process_pool_status_response(pcpConn, buf, rsize);
417405
break;
418406

419-
case 'E':
420-
setResultStatus(pcpConn, PCP_RES_BACKEND_ERROR);
421-
process_error_response(pcpConn, toc, buf);
407+
case 'c': /* attach node */
408+
if (sentMsg != 'C' && sentMsg != 'O')
409+
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
410+
else
411+
process_command_complete_response(pcpConn, buf, rsize);
422412
break;
423413

424-
case 'N':
414+
case 'd': /* detach node */
415+
if (sentMsg != 'D' && sentMsg != 'J')
416+
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
417+
else
418+
process_command_complete_response(pcpConn, buf, rsize);
419+
break;
420+
421+
case 'E': /* error */
422+
setResultStatus(pcpConn, PCP_RES_BACKEND_ERROR);
425423
process_error_response(pcpConn, toc, buf);
426-
pfree(buf);
427-
continue;
428424
break;
429425

430-
case 'i':
431-
if (sentMsg != 'I')
426+
case 'g': /* invalidate query cache */
427+
if (sentMsg != 'G')
432428
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
433429
else
434-
process_node_info_response(pcpConn, buf, rsize);
430+
process_command_complete_response(pcpConn, buf, rsize);
435431
break;
436432

437-
case 'h':
433+
case 'h': /* health check stats */
438434
if (sentMsg != 'H')
439435
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
440436
else
441437
process_health_check_stats_response(pcpConn, buf, rsize);
442438
break;
443439

444-
case 'l':
445-
if (sentMsg != 'L')
440+
case 'i': /* node info */
441+
if (sentMsg != 'I')
446442
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
447443
else
448-
process_pcp_node_count_response(pcpConn, buf, rsize);
444+
process_node_info_response(pcpConn, buf, rsize);
449445
break;
450446

451-
case 'c':
452-
if (sentMsg != 'C' && sentMsg != 'O')
447+
case 'l': /* node count */
448+
if (sentMsg != 'L')
453449
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
454450
else
455-
process_command_complete_response(pcpConn, buf, rsize);
451+
process_pcp_node_count_response(pcpConn, buf, rsize);
456452
break;
457453

458-
case 'd':
459-
if (sentMsg != 'D' && sentMsg != 'J')
454+
case 'm': /* salt info response */
455+
if (sentMsg != 'M')
460456
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
461457
else
462-
process_command_complete_response(pcpConn, buf, rsize);
458+
process_salt_info_response(pcpConn, buf, rsize);
463459
break;
464460

465-
case 'a':
466-
if (sentMsg != 'A')
467-
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
468-
else
469-
process_command_complete_response(pcpConn, buf, rsize);
461+
case 'N': /* error response */
462+
process_error_response(pcpConn, toc, buf);
463+
pfree(buf);
464+
continue;
470465
break;
471466

472-
case 'z':
473-
if (sentMsg != 'Z')
467+
case 'n': /* process count */
468+
if (sentMsg != 'N')
474469
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
475470
else
476-
process_command_complete_response(pcpConn, buf, rsize);
471+
process_process_count_response(pcpConn, buf, rsize);
477472
break;
478473

479-
case 'v': /* pcp_log_rotate */
480-
if (sentMsg != 'V')
474+
case 'p': /* process info */
475+
if (sentMsg != 'P')
481476
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
482477
else
483-
process_command_complete_response(pcpConn, buf, rsize);
478+
process_process_info_response(pcpConn, buf, rsize);
484479
break;
485480

486-
case 'w':
487-
if (sentMsg != 'W')
488-
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
489-
else
490-
process_watchdog_info_response(pcpConn, buf, rsize);
481+
case 'r': /* Authentication Response */
482+
{
483+
if (sentMsg != 'R')
484+
{
485+
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
486+
}
487+
else if (strcmp(buf, "AuthenticationOK") == 0)
488+
{
489+
pcpConn->connState = PCP_CONNECTION_OK;
490+
setResultStatus(pcpConn, PCP_RES_COMMAND_OK);
491+
}
492+
else
493+
{
494+
pcp_internal_error(pcpConn,
495+
"ERROR: authentication failed. reason=\"%s\"", buf);
496+
setResultStatus(pcpConn, PCP_RES_BACKEND_ERROR);
497+
}
498+
}
491499
break;
492500

493-
case 'p':
494-
if (sentMsg != 'P')
501+
case 't': /* shutdown request */
502+
if (sentMsg != 'T')
495503
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
496504
else
497-
process_process_info_response(pcpConn, buf, rsize);
505+
setResultStatus(pcpConn, PCP_RES_COMMAND_OK);
498506
break;
499507

500-
case 'n':
501-
if (sentMsg != 'N')
508+
case 'v': /* pcp_log_rotate */
509+
if (sentMsg != 'V')
502510
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
503511
else
504-
process_process_count_response(pcpConn, buf, rsize);
512+
process_command_complete_response(pcpConn, buf, rsize);
505513
break;
506514

507-
case 'b':
508-
if (sentMsg != 'B')
515+
case 'w': /* watchdog info */
516+
if (sentMsg != 'W')
509517
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
510518
else
511-
process_pool_status_response(pcpConn, buf, rsize);
519+
process_watchdog_info_response(pcpConn, buf, rsize);
512520
break;
513521

514-
case 't':
515-
if (sentMsg != 'T')
522+
case 'z': /* command complete */
523+
if (sentMsg != 'Z')
516524
setResultStatus(pcpConn, PCP_RES_BAD_RESPONSE);
517525
else
518-
setResultStatus(pcpConn, PCP_RES_COMMAND_OK);
526+
process_command_complete_response(pcpConn, buf, rsize);
519527
break;
520528

521529
default:
@@ -959,6 +967,28 @@ pcp_log_rotate(PCPConnInfo * pcpConn,char command_scope)
959967
return process_pcp_response(pcpConn, 'V');
960968
}
961969

970+
PCPResultInfo *
971+
pcp_invalidate_query_cache(PCPConnInfo * pcpConn)
972+
{
973+
int wsize;
974+
975+
if (PCPConnectionStatus(pcpConn) != PCP_CONNECTION_OK)
976+
{
977+
pcp_internal_error(pcpConn, "invalid PCP connection");
978+
return NULL;
979+
}
980+
981+
pcp_write(pcpConn->pcpConn, "G", 1);
982+
wsize = htonl(sizeof(int));
983+
pcp_write(pcpConn->pcpConn, &wsize, sizeof(int));
984+
if (PCPFlush(pcpConn) < 0)
985+
return NULL;
986+
if (pcpConn->Pfdebug)
987+
fprintf(pcpConn->Pfdebug, "DEBUG: send: tos=\"G\", len=%d\n", ntohl(wsize));
988+
989+
return process_pcp_response(pcpConn, 'G');
990+
}
991+
962992
/*
963993
* Process health check response from PCP server.
964994
* pcpConn: connection to the server

0 commit comments

Comments
 (0)