diff options
Diffstat (limited to 'src/auditordb/plugin_auditordb_postgres.c')
-rw-r--r-- | src/auditordb/plugin_auditordb_postgres.c | 253 |
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 | */ | ||
102 | static void | ||
103 | pq_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 | */ | ||
117 | static void | ||
118 | pq_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 | */ | ||
134 | static PGconn * | ||
135 | connect_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 | */ |
501 | static int | 432 | static void |
502 | postgres_prepare (PGconn *db_conn) | 433 | db_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 | */ | ||
455 | static struct TALER_AUDITORDB_Session * | ||
456 | postgres_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 | */ | ||
1049 | static void | ||
1050 | db_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 | */ | ||
1071 | static struct TALER_AUDITORDB_Session * | ||
1072 | postgres_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 | |||
1128 | postgres_start (void *cls, | 1028 | postgres_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 | |||
1157 | postgres_rollback (void *cls, | 1056 | postgres_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 | ||