aboutsummaryrefslogtreecommitdiff
path: root/src/auditordb/plugin_auditordb_postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/auditordb/plugin_auditordb_postgres.c')
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c253
1 files changed, 77 insertions, 176 deletions
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index c8fd4f487..b4bb50079 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -61,7 +61,7 @@ struct TALER_AUDITORDB_Session
61 /** 61 /**
62 * Postgres connection handle. 62 * Postgres connection handle.
63 */ 63 */
64 PGconn *conn; 64 struct GNUNET_PQ_Context *conn;
65}; 65};
66 66
67 67
@@ -92,71 +92,6 @@ struct PostgresClosure
92 92
93 93
94/** 94/**
95 * Function called by libpq whenever it wants to log something.
96 * We already log whenever we care, so this function does nothing
97 * and merely exists to silence the libpq logging.
98 *
99 * @param arg NULL
100 * @param res information about some libpq event
101 */
102static void
103pq_notice_receiver_cb (void *arg,
104 const PGresult *res)
105{
106 /* do nothing, intentionally */
107}
108
109
110/**
111 * Function called by libpq whenever it wants to log something.
112 * We log those using the Taler logger.
113 *
114 * @param arg NULL
115 * @param message information about some libpq event
116 */
117static void
118pq_notice_processor_cb (void *arg,
119 const char *message)
120{
121 LOG (GNUNET_ERROR_TYPE_INFO,
122 "%s",
123 message);
124}
125
126
127/**
128 * Establish connection to the Postgres database
129 * and initialize callbacks for logging.
130 *
131 * @param pc configuration to use
132 * @return NULL on error
133 */
134static PGconn *
135connect_to_postgres (struct PostgresClosure *pc)
136{
137 PGconn *conn;
138
139 conn = PQconnectdb (pc->connection_cfg_str);
140 if (CONNECTION_OK !=
141 PQstatus (conn))
142 {
143 TALER_LOG_ERROR ("Database connection failed: %s\n",
144 PQerrorMessage (conn));
145 GNUNET_break (0);
146 PQfinish (conn);
147 return NULL;
148 }
149 PQsetNoticeReceiver (conn,
150 &pq_notice_receiver_cb,
151 NULL);
152 PQsetNoticeProcessor (conn,
153 &pq_notice_processor_cb,
154 NULL);
155 return conn;
156}
157
158
159/**
160 * Drop all Taler tables. This should only be used by testcases. 95 * Drop all Taler tables. This should only be used by testcases.
161 * 96 *
162 * @param cls the `struct PostgresClosure` with the plugin-specific state 97 * @param cls the `struct PostgresClosure` with the plugin-specific state
@@ -198,25 +133,23 @@ postgres_drop_tables (void *cls,
198 GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_exchanges CASCADE;"), 133 GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_exchanges CASCADE;"),
199 GNUNET_PQ_EXECUTE_STATEMENT_END 134 GNUNET_PQ_EXECUTE_STATEMENT_END
200 }; 135 };
201 PGconn *conn; 136 struct GNUNET_PQ_Context *conn;
202 int ret; 137 int ret;
203 138
204 conn = connect_to_postgres (pc); 139 conn = GNUNET_PQ_connect (pc->connection_cfg_str,
140 es,
141 NULL);
205 if (NULL == conn) 142 if (NULL == conn)
206 return GNUNET_SYSERR; 143 return GNUNET_SYSERR;
207 LOG (GNUNET_ERROR_TYPE_INFO, 144 ret = GNUNET_OK;
208 "Dropping ALL tables\n"); 145 if (drop_exchangelist)
209 ret = GNUNET_PQ_exec_statements (conn,
210 es);
211 if ( (ret >= 0) &&
212 (drop_exchangelist) )
213 ret = GNUNET_PQ_exec_statements (conn, 146 ret = GNUNET_PQ_exec_statements (conn,
214 esx); 147 esx);
215 /* TODO: we probably need a bit more fine-grained control 148 /* TODO: we probably need a bit more fine-grained control
216 over drops for the '-r' option of taler-auditor; also, 149 over drops for the '-r' option of taler-auditor; also,
217 for the testcase, we currently fail to drop the 150 for the testcase, we currently fail to drop the
218 auditor_denominations table... */ 151 auditor_denominations table... */
219 PQfinish (conn); 152 GNUNET_PQ_disconnect (conn);
220 return ret; 153 return ret;
221} 154}
222 155
@@ -479,28 +412,52 @@ postgres_create_tables (void *cls)
479 ")"), 412 ")"),
480 GNUNET_PQ_EXECUTE_STATEMENT_END 413 GNUNET_PQ_EXECUTE_STATEMENT_END
481 }; 414 };
482 PGconn *conn; 415 struct GNUNET_PQ_Context *conn;
483 int ret;
484 416
485 conn = connect_to_postgres (pc); 417 conn = GNUNET_PQ_connect (pc->connection_cfg_str,
418 es,
419 NULL);
486 if (NULL == conn) 420 if (NULL == conn)
487 return GNUNET_SYSERR; 421 return GNUNET_SYSERR;
488 ret = GNUNET_PQ_exec_statements (conn, 422 GNUNET_PQ_disconnect (conn);
489 es); 423 return GNUNET_OK;
490 PQfinish (conn);
491 return ret;
492} 424}
493 425
494 426
495/** 427/**
496 * Setup prepared statements. 428 * Close thread-local database connection when a thread is destroyed.
497 * 429 *
498 * @param db_conn connection handle to initialize 430 * @param cls closure we get from pthreads (the db handle)
499 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
500 */ 431 */
501static int 432static void
502postgres_prepare (PGconn *db_conn) 433db_conn_destroy (void *cls)
503{ 434{
435 struct TALER_AUDITORDB_Session *session = cls;
436 struct GNUNET_PQ_Context *db_conn;
437
438 if (NULL == session)
439 return;
440 db_conn = session->conn;
441 session->conn = NULL;
442 if (NULL != db_conn)
443 GNUNET_PQ_disconnect (db_conn);
444 GNUNET_free (session);
445}
446
447
448/**
449 * Get the thread-local database-handle.
450 * Connect to the db if the connection does not exist yet.
451 *
452 * @param cls the `struct PostgresClosure` with the plugin-specific state
453 * @return the database connection, or NULL on error
454 */
455static struct TALER_AUDITORDB_Session *
456postgres_get_session (void *cls)
457{
458 struct PostgresClosure *pc = cls;
459 struct GNUNET_PQ_Context *db_conn;
460 struct TALER_AUDITORDB_Session *session;
504 struct GNUNET_PQ_PreparedStatement ps[] = { 461 struct GNUNET_PQ_PreparedStatement ps[] = {
505 /* used in #postgres_commit */ 462 /* used in #postgres_commit */
506 GNUNET_PQ_make_prepare ("do_commit", 463 GNUNET_PQ_make_prepare ("do_commit",
@@ -1036,80 +993,23 @@ postgres_prepare (PGconn *db_conn)
1036 GNUNET_PQ_PREPARED_STATEMENT_END 993 GNUNET_PQ_PREPARED_STATEMENT_END
1037 }; 994 };
1038 995
1039 return GNUNET_PQ_prepare_statements (db_conn,
1040 ps);
1041}
1042
1043
1044/**
1045 * Close thread-local database connection when a thread is destroyed.
1046 *
1047 * @param cls closure we get from pthreads (the db handle)
1048 */
1049static void
1050db_conn_destroy (void *cls)
1051{
1052 struct TALER_AUDITORDB_Session *session = cls;
1053 PGconn *db_conn;
1054
1055 if (NULL == session)
1056 return;
1057 db_conn = session->conn;
1058 if (NULL != db_conn)
1059 PQfinish (db_conn);
1060 GNUNET_free (session);
1061}
1062
1063
1064/**
1065 * Get the thread-local database-handle.
1066 * Connect to the db if the connection does not exist yet.
1067 *
1068 * @param cls the `struct PostgresClosure` with the plugin-specific state
1069 * @return the database connection, or NULL on error
1070 */
1071static struct TALER_AUDITORDB_Session *
1072postgres_get_session (void *cls)
1073{
1074 struct PostgresClosure *pc = cls;
1075 PGconn *db_conn;
1076 struct TALER_AUDITORDB_Session *session;
1077
1078 if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal))) 996 if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal)))
1079 { 997 {
1080 if (CONNECTION_BAD == PQstatus (session->conn)) 998 GNUNET_PQ_reconnect_if_down (session->conn);
1081 { 999 return session;
1082 /**
1083 * Reset the thread-local database-handle. Disconnects from the
1084 * DB. Needed after the database server restarts as we need to
1085 * properly reconnect. */
1086 GNUNET_assert (0 == pthread_setspecific (pc->db_conn_threadlocal,
1087 NULL));
1088 PQfinish (session->conn);
1089 GNUNET_free (session);
1090 }
1091 else
1092 {
1093 return session;
1094 }
1095 } 1000 }
1096 db_conn = connect_to_postgres (pc); 1001 db_conn = GNUNET_PQ_connect (pc->connection_cfg_str,
1002 NULL,
1003 ps);
1097 if (NULL == db_conn) 1004 if (NULL == db_conn)
1098 return NULL; 1005 return NULL;
1099 if (GNUNET_OK !=
1100 postgres_prepare (db_conn))
1101 {
1102 GNUNET_break (0);
1103 PQfinish (db_conn);
1104 return NULL;
1105 }
1106 session = GNUNET_new (struct TALER_AUDITORDB_Session); 1006 session = GNUNET_new (struct TALER_AUDITORDB_Session);
1107 session->conn = db_conn; 1007 session->conn = db_conn;
1108 if (0 != pthread_setspecific (pc->db_conn_threadlocal, 1008 if (0 != pthread_setspecific (pc->db_conn_threadlocal,
1109 session)) 1009 session))
1110 { 1010 {
1111 GNUNET_break (0); 1011 GNUNET_break (0);
1112 PQfinish (db_conn); 1012 GNUNET_PQ_disconnect (db_conn);
1113 GNUNET_free (session); 1013 GNUNET_free (session);
1114 return NULL; 1014 return NULL;
1115 } 1015 }
@@ -1128,20 +1028,19 @@ static int
1128postgres_start (void *cls, 1028postgres_start (void *cls,
1129 struct TALER_AUDITORDB_Session *session) 1029 struct TALER_AUDITORDB_Session *session)
1130{ 1030{
1131 PGresult *result; 1031 struct GNUNET_PQ_ExecuteStatement es[] = {
1032 GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
1033 GNUNET_PQ_EXECUTE_STATEMENT_END
1034 };
1132 1035
1133 result = PQexec (session->conn, 1036 if (GNUNET_OK !=
1134 "START TRANSACTION ISOLATION LEVEL SERIALIZABLE"); 1037 GNUNET_PQ_exec_statements (session->conn,
1135 if (PGRES_COMMAND_OK != 1038 es))
1136 PQresultStatus (result))
1137 { 1039 {
1138 TALER_LOG_ERROR ("Failed to start transaction: %s\n", 1040 TALER_LOG_ERROR ("Failed to start transaction\n");
1139 PQresultErrorMessage (result));
1140 GNUNET_break (0); 1041 GNUNET_break (0);
1141 PQclear (result);
1142 return GNUNET_SYSERR; 1042 return GNUNET_SYSERR;
1143 } 1043 }
1144 PQclear (result);
1145 return GNUNET_OK; 1044 return GNUNET_OK;
1146} 1045}
1147 1046
@@ -1157,13 +1056,14 @@ static void
1157postgres_rollback (void *cls, 1056postgres_rollback (void *cls,
1158 struct TALER_AUDITORDB_Session *session) 1057 struct TALER_AUDITORDB_Session *session)
1159{ 1058{
1160 PGresult *result; 1059 struct GNUNET_PQ_ExecuteStatement es[] = {
1060 GNUNET_PQ_make_execute ("ROLLBACK"),
1061 GNUNET_PQ_EXECUTE_STATEMENT_END
1062 };
1161 1063
1162 result = PQexec (session->conn, 1064 GNUNET_break (GNUNET_OK ==
1163 "ROLLBACK"); 1065 GNUNET_PQ_exec_statements (session->conn,
1164 GNUNET_break (PGRES_COMMAND_OK == 1066 es));
1165 PQresultStatus (result));
1166 PQclear (result);
1167} 1067}
1168 1068
1169 1069
@@ -1205,30 +1105,31 @@ postgres_gc (void *cls)
1205 TALER_PQ_query_param_absolute_time (&now), 1105 TALER_PQ_query_param_absolute_time (&now),
1206 GNUNET_PQ_query_param_end 1106 GNUNET_PQ_query_param_end
1207 }; 1107 };
1208 PGconn *conn; 1108 struct GNUNET_PQ_Context *conn;
1209 enum GNUNET_DB_QueryStatus qs; 1109 enum GNUNET_DB_QueryStatus qs;
1110 struct GNUNET_PQ_PreparedStatement ps[] = {
1111 /* FIXME: this is obviously not going to be this easy... */
1112 GNUNET_PQ_make_prepare ("gc_auditor",
1113 "FIXME",
1114 0),
1115 GNUNET_PQ_PREPARED_STATEMENT_END
1116 };
1210 1117
1211 now = GNUNET_TIME_absolute_get (); 1118 now = GNUNET_TIME_absolute_get ();
1212 conn = connect_to_postgres (pc); 1119 conn = GNUNET_PQ_connect (pc->connection_cfg_str,
1120 NULL,
1121 ps);
1213 if (NULL == conn) 1122 if (NULL == conn)
1214 return GNUNET_SYSERR; 1123 return GNUNET_SYSERR;
1215 if (GNUNET_OK !=
1216 postgres_prepare (conn))
1217 {
1218 PQfinish (conn);
1219 return GNUNET_SYSERR;
1220 }
1221 /* FIXME: this is obviously not going to be this easy... */
1222 qs = GNUNET_PQ_eval_prepared_non_select (conn, 1124 qs = GNUNET_PQ_eval_prepared_non_select (conn,
1223 "gc_auditor", 1125 "gc_auditor",
1224 params_time); 1126 params_time);
1127 GNUNET_PQ_disconnect (conn);
1225 if (0 > qs) 1128 if (0 > qs)
1226 { 1129 {
1227 GNUNET_break (0); 1130 GNUNET_break (0);
1228 PQfinish (conn);
1229 return GNUNET_SYSERR; 1131 return GNUNET_SYSERR;
1230 } 1132 }
1231 PQfinish (conn);
1232 return GNUNET_OK; 1133 return GNUNET_OK;
1233} 1134}
1234 1135