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 "taler/platform.h"
22 : #include "taler/taler_error_codes.h"
23 : #include "taler/taler_dbevents.h"
24 : #include "taler/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 24597 : internal_setup (struct PostgresClosure *pg)
39 : {
40 24597 : 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 208 : struct GNUNET_PQ_ExecuteStatement es[] = {
63 208 : GNUNET_PQ_make_try_execute (
64 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
65 208 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
66 208 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
67 : /* Mergejoin causes issues, see Postgres #18380 */
68 208 : GNUNET_PQ_make_try_execute ("SET enable_mergejoin=OFF;"),
69 208 : 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 208 : 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 208 : if (NULL == db_conn)
82 0 : return GNUNET_SYSERR;
83 :
84 208 : pg->prep_gen++;
85 208 : pg->conn = db_conn;
86 : }
87 24597 : if (NULL == pg->transaction_name)
88 24593 : GNUNET_PQ_reconnect_if_down (pg->conn);
89 24597 : return GNUNET_OK;
90 : }
91 :
92 :
93 : enum GNUNET_GenericReturnValue
94 24597 : TEH_PG_preflight (void *cls)
95 : {
96 24597 : struct PostgresClosure *pg = cls;
97 24597 : struct GNUNET_PQ_ExecuteStatement es[] = {
98 24597 : GNUNET_PQ_make_execute ("ROLLBACK"),
99 : GNUNET_PQ_EXECUTE_STATEMENT_END
100 : };
101 :
102 24597 : if (GNUNET_OK !=
103 24597 : internal_setup (pg))
104 0 : return GNUNET_SYSERR;
105 24597 : if (NULL == pg->transaction_name)
106 24593 : 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 : }
|