Line data Source code
1 : /* 2 : This file is part of TALER 3 : Copyright (C) 2022 Taler Systems SA 4 : 5 : TALER is free software; you can redistribute it and/or modify it under the 6 : terms of the GNU General Public License as published by the Free Software 7 : Foundation; either version 3, or (at your option) any later version. 8 : 9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 : 13 : You should have received a copy of the GNU General Public License along with 14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 : */ 16 : /** 17 : * @file exchangedb/pg_preflight.c 18 : * @brief Implementation of the preflight function for Postgres 19 : * @author Christian Grothoff 20 : */ 21 : #include "platform.h" 22 : #include "taler_error_codes.h" 23 : #include "taler_dbevents.h" 24 : #include "taler_pq_lib.h" 25 : #include "pg_preflight.h" 26 : #include "pg_helper.h" 27 : #include "plugin_exchangedb_postgres.h" 28 : 29 : 30 : /** 31 : * Connect to the database if the connection does not exist yet 32 : * and check that we are ready to operate. 33 : * 34 : * @param pg the plugin-specific state 35 : * @return #GNUNET_OK on success 36 : */ 37 : static enum GNUNET_GenericReturnValue 38 32451 : internal_setup (struct PostgresClosure *pg) 39 : { 40 32451 : if (NULL == pg->conn) 41 : { 42 : #if AUTO_EXPLAIN 43 : /* Enable verbose logging to see where queries do not 44 : properly use indices */ 45 : struct GNUNET_PQ_ExecuteStatement es[] = { 46 : GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), 47 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), 48 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), 49 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), 50 : /* https://wiki.postgresql.org/wiki/Serializable suggests to really 51 : force the default to 'serializable' if SSI is to be used. */ 52 : GNUNET_PQ_make_try_execute ( 53 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), 54 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), 55 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), 56 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"), 57 : /* Mergejoin causes issues, see Postgres #18380 */ 58 : GNUNET_PQ_make_try_execute ("SET enable_mergejoin=OFF;"), 59 : GNUNET_PQ_EXECUTE_STATEMENT_END 60 : }; 61 : #else 62 871 : struct GNUNET_PQ_ExecuteStatement es[] = { 63 871 : GNUNET_PQ_make_try_execute ( 64 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), 65 871 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), 66 871 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), 67 : /* Mergejoin causes issues, see Postgres #18380 */ 68 871 : GNUNET_PQ_make_try_execute ("SET enable_mergejoin=OFF;"), 69 871 : GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"), 70 : GNUNET_PQ_EXECUTE_STATEMENT_END 71 : }; 72 : #endif 73 : struct GNUNET_PQ_Context *db_conn; 74 : 75 871 : db_conn = GNUNET_PQ_connect_with_cfg2 (pg->cfg, 76 : "exchangedb-postgres", 77 : "exchange-", /* load_path_suffix */ 78 : es, 79 : NULL /* prepared statements */, 80 : GNUNET_PQ_FLAG_CHECK_CURRENT); 81 871 : if (NULL == db_conn) 82 0 : return GNUNET_SYSERR; 83 : 84 871 : pg->prep_gen++; 85 871 : pg->conn = db_conn; 86 : } 87 32451 : if (NULL == pg->transaction_name) 88 32447 : GNUNET_PQ_reconnect_if_down (pg->conn); 89 32451 : return GNUNET_OK; 90 : } 91 : 92 : 93 : enum GNUNET_GenericReturnValue 94 32451 : TEH_PG_preflight (void *cls) 95 : { 96 32451 : struct PostgresClosure *pg = cls; 97 32451 : struct GNUNET_PQ_ExecuteStatement es[] = { 98 32451 : GNUNET_PQ_make_execute ("ROLLBACK"), 99 : GNUNET_PQ_EXECUTE_STATEMENT_END 100 : }; 101 : 102 32451 : if (GNUNET_OK != 103 32451 : internal_setup (pg)) 104 0 : return GNUNET_SYSERR; 105 32451 : if (NULL == pg->transaction_name) 106 32447 : return GNUNET_OK; /* all good */ 107 4 : if (GNUNET_OK == 108 4 : GNUNET_PQ_exec_statements (pg->conn, 109 : es)) 110 : { 111 4 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 112 : "BUG: Preflight check rolled back transaction `%s'!\n", 113 : pg->transaction_name); 114 : } 115 : else 116 : { 117 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 118 : "BUG: Preflight check failed to rollback transaction `%s'!\n", 119 : pg->transaction_name); 120 : } 121 4 : pg->transaction_name = NULL; 122 4 : return GNUNET_NO; 123 : }