liquid_feedback_core
annotate lf_update.c @ 336:a7537038640d
Cleanup of new code for allowing "lf_update" to run without extensive locking
- Removed unnecessary variable "direct_voter_update_v" in function "forbid_changes_on_closed_issue_trigger"()
- Added PERFORM "require_transaction_isolation"() in more functions
- Integrated functions "issue_admission", "initiative_admission" and "freeze_after_snapshot" into "check_issue" function
- Removed function "manual_freeze" (replacement: set "issue" timings accordingly, when needed)
- Added/modified some comments
- Removed unnecessary variable "direct_voter_update_v" in function "forbid_changes_on_closed_issue_trigger"()
- Added PERFORM "require_transaction_isolation"() in more functions
- Integrated functions "issue_admission", "initiative_admission" and "freeze_after_snapshot" into "check_issue" function
- Removed function "manual_freeze" (replacement: set "issue" timings accordingly, when needed)
- Added/modified some comments
| author | jbe |
|---|---|
| date | Wed Feb 20 02:56:49 2013 +0100 (2013-02-20) |
| parents | ab370f3b9892 |
| children | 2ea60e88265a |
| rev | line source |
|---|---|
| jbe@0 | 1 #include <stdlib.h> |
| jbe@0 | 2 #include <stdio.h> |
| jbe@0 | 3 #include <string.h> |
| jbe@0 | 4 #include <libpq-fe.h> |
| jbe@0 | 5 |
| jbe@0 | 6 int main(int argc, char **argv) { |
| jbe@1 | 7 |
| jbe@1 | 8 // variable declarations: |
| jbe@65 | 9 int err = 0; |
| jbe@0 | 10 int i, count; |
| jbe@0 | 11 char *conninfo; |
| jbe@0 | 12 PGconn *db; |
| jbe@334 | 13 PGresult *res; |
| jbe@1 | 14 |
| jbe@1 | 15 // parse command line: |
| jbe@0 | 16 if (argc == 0) return 1; |
| jbe@0 | 17 if (argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { |
| jbe@0 | 18 FILE *out; |
| jbe@0 | 19 out = argc == 1 ? stderr : stdout; |
| jbe@0 | 20 fprintf(stdout, "\n"); |
| jbe@0 | 21 fprintf(stdout, "Usage: %s <conninfo>\n", argv[0]); |
| jbe@0 | 22 fprintf(stdout, "\n"); |
| jbe@0 | 23 fprintf(stdout, "<conninfo> is specified by PostgreSQL's libpq,\n"); |
| jbe@334 | 24 fprintf(stdout, "see http://www.postgresql.org/docs/9.1/static/libpq-connect.html\n"); |
| jbe@0 | 25 fprintf(stdout, "\n"); |
| jbe@0 | 26 fprintf(stdout, "Example: %s dbname=liquid_feedback\n", argv[0]); |
| jbe@0 | 27 fprintf(stdout, "\n"); |
| jbe@0 | 28 return argc == 1 ? 1 : 0; |
| jbe@0 | 29 } |
| jbe@0 | 30 { |
| jbe@0 | 31 size_t len = 0; |
| jbe@0 | 32 for (i=1; i<argc; i++) len += strlen(argv[i]) + 1; |
| jbe@0 | 33 conninfo = malloc(len * sizeof(char)); |
| jbe@0 | 34 if (!conninfo) { |
| jbe@0 | 35 fprintf(stderr, "Error: Could not allocate memory for conninfo string\n"); |
| jbe@0 | 36 return 1; |
| jbe@0 | 37 } |
| jbe@0 | 38 conninfo[0] = 0; |
| jbe@0 | 39 for (i=1; i<argc; i++) { |
| jbe@0 | 40 if (i>1) strcat(conninfo, " "); |
| jbe@0 | 41 strcat(conninfo, argv[i]); |
| jbe@0 | 42 } |
| jbe@0 | 43 } |
| jbe@1 | 44 |
| jbe@1 | 45 // connect to database: |
| jbe@0 | 46 db = PQconnectdb(conninfo); |
| jbe@0 | 47 if (!db) { |
| jbe@0 | 48 fprintf(stderr, "Error: Could not create database handle\n"); |
| jbe@0 | 49 return 1; |
| jbe@0 | 50 } |
| jbe@0 | 51 if (PQstatus(db) != CONNECTION_OK) { |
| jbe@0 | 52 fprintf(stderr, "Could not open connection:\n%s", PQerrorMessage(db)); |
| jbe@0 | 53 return 1; |
| jbe@0 | 54 } |
| jbe@1 | 55 |
| jbe@235 | 56 // delete expired sessions: |
| jbe@334 | 57 res = PQexec(db, "DELETE FROM \"expired_session\""); |
| jbe@334 | 58 if (!res) { |
| jbe@235 | 59 fprintf(stderr, "Error in pqlib while sending SQL command deleting expired sessions\n"); |
| jbe@235 | 60 err = 1; |
| jbe@235 | 61 } else if ( |
| jbe@334 | 62 PQresultStatus(res) != PGRES_COMMAND_OK && |
| jbe@334 | 63 PQresultStatus(res) != PGRES_TUPLES_OK |
| jbe@235 | 64 ) { |
| jbe@334 | 65 fprintf(stderr, "Error while executing SQL command deleting expired sessions:\n%s", PQresultErrorMessage(res)); |
| jbe@235 | 66 err = 1; |
| jbe@334 | 67 PQclear(res); |
| jbe@235 | 68 } else { |
| jbe@334 | 69 PQclear(res); |
| jbe@235 | 70 } |
| jbe@235 | 71 |
| jbe@184 | 72 // check member activity: |
| jbe@334 | 73 res = PQexec(db, "SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT \"check_activity\"()"); |
| jbe@334 | 74 if (!res) { |
| jbe@184 | 75 fprintf(stderr, "Error in pqlib while sending SQL command checking member activity\n"); |
| jbe@103 | 76 err = 1; |
| jbe@103 | 77 } else if ( |
| jbe@334 | 78 PQresultStatus(res) != PGRES_COMMAND_OK && |
| jbe@334 | 79 PQresultStatus(res) != PGRES_TUPLES_OK |
| jbe@103 | 80 ) { |
| jbe@334 | 81 fprintf(stderr, "Error while executing SQL command checking member activity:\n%s", PQresultErrorMessage(res)); |
| jbe@103 | 82 err = 1; |
| jbe@334 | 83 PQclear(res); |
| jbe@103 | 84 } else { |
| jbe@334 | 85 PQclear(res); |
| jbe@103 | 86 } |
| jbe@103 | 87 |
| jbe@4 | 88 // calculate member counts: |
| jbe@334 | 89 res = PQexec(db, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT \"calculate_member_counts\"()"); |
| jbe@334 | 90 if (!res) { |
| jbe@4 | 91 fprintf(stderr, "Error in pqlib while sending SQL command calculating member counts\n"); |
| jbe@65 | 92 err = 1; |
| jbe@65 | 93 } else if ( |
| jbe@334 | 94 PQresultStatus(res) != PGRES_COMMAND_OK && |
| jbe@334 | 95 PQresultStatus(res) != PGRES_TUPLES_OK |
| jbe@4 | 96 ) { |
| jbe@334 | 97 fprintf(stderr, "Error while executing SQL command calculating member counts:\n%s", PQresultErrorMessage(res)); |
| jbe@65 | 98 err = 1; |
| jbe@334 | 99 PQclear(res); |
| jbe@65 | 100 } else { |
| jbe@334 | 101 PQclear(res); |
| jbe@4 | 102 } |
| jbe@4 | 103 |
| jbe@1 | 104 // update open issues: |
| jbe@334 | 105 res = PQexec(db, "SELECT \"id\" FROM \"open_issue\""); |
| jbe@334 | 106 if (!res) { |
| jbe@0 | 107 fprintf(stderr, "Error in pqlib while sending SQL command selecting open issues\n"); |
| jbe@65 | 108 err = 1; |
| jbe@334 | 109 } else if (PQresultStatus(res) != PGRES_TUPLES_OK) { |
| jbe@334 | 110 fprintf(stderr, "Error while executing SQL command selecting open issues:\n%s", PQresultErrorMessage(res)); |
| jbe@65 | 111 err = 1; |
| jbe@334 | 112 PQclear(res); |
| jbe@65 | 113 } else { |
| jbe@334 | 114 count = PQntuples(res); |
| jbe@65 | 115 for (i=0; i<count; i++) { |
| jbe@334 | 116 char *issue_id, *escaped_issue_id; |
| jbe@334 | 117 PGresult *res2, *old_res2; |
| jbe@334 | 118 int j; |
| jbe@334 | 119 issue_id = PQgetvalue(res, i, 0); |
| jbe@334 | 120 escaped_issue_id = PQescapeLiteral(db, issue_id, strlen(issue_id)); |
| jbe@334 | 121 old_res2 = NULL; |
| jbe@334 | 122 for (j=0; ; j++) { |
| jbe@334 | 123 if (j >= 20) { // safety to avoid endless loops |
| jbe@334 | 124 fprintf(stderr, "Function \"check_issue\"(...) returned non-null value too often.\n"); |
| jbe@334 | 125 err = 1; |
| jbe@334 | 126 if (j > 0) PQclear(old_res2); |
| jbe@334 | 127 break; |
| jbe@334 | 128 } |
| jbe@334 | 129 if (j == 0) { |
| jbe@334 | 130 char *cmd; |
| jbe@334 | 131 if (asprintf(&cmd, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT \"check_issue\"(%s, NULL)", escaped_issue_id) < 0) { |
| jbe@334 | 132 fprintf(stderr, "Could not prepare query string in memory.\n"); |
| jbe@334 | 133 err = 1; |
| jbe@334 | 134 break; |
| jbe@334 | 135 } |
| jbe@334 | 136 res2 = PQexec(db, cmd); |
| jbe@334 | 137 free(cmd); |
| jbe@334 | 138 } else { |
| jbe@334 | 139 char *persist, *escaped_persist, *cmd; |
| jbe@334 | 140 persist = PQgetvalue(old_res2, 0, 0); |
| jbe@334 | 141 escaped_persist = PQescapeLiteral(db, persist, strlen(persist)); |
| jbe@334 | 142 if (asprintf(&cmd, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT \"check_issue\"(%s, %s::\"check_issue_persistence\")", escaped_issue_id, escaped_persist) < 0) { |
| jbe@334 | 143 PQfreemem(escaped_persist); |
| jbe@334 | 144 fprintf(stderr, "Could not prepare query string in memory.\n"); |
| jbe@334 | 145 err = 1; |
| jbe@334 | 146 PQclear(old_res2); |
| jbe@334 | 147 break; |
| jbe@334 | 148 } |
| jbe@334 | 149 PQfreemem(escaped_persist); |
| jbe@334 | 150 res2 = PQexec(db, cmd); |
| jbe@334 | 151 free(cmd); |
| jbe@334 | 152 PQclear(old_res2); |
| jbe@334 | 153 } |
| jbe@334 | 154 if (!res2) { |
| jbe@334 | 155 fprintf(stderr, "Error in pqlib while sending SQL command to call function \"check_issue\"(...):\n"); |
| jbe@334 | 156 err = 1; |
| jbe@334 | 157 break; |
| jbe@334 | 158 } else if ( |
| jbe@334 | 159 PQresultStatus(res2) != PGRES_COMMAND_OK && |
| jbe@334 | 160 PQresultStatus(res2) != PGRES_TUPLES_OK |
| jbe@334 | 161 ) { |
| jbe@334 | 162 fprintf(stderr, "Error while calling SQL function \"check_issue\"(...):\n%s", PQresultErrorMessage(res2)); |
| jbe@334 | 163 err = 1; |
| jbe@334 | 164 PQclear(res2); |
| jbe@334 | 165 break; |
| jbe@334 | 166 } else { |
| jbe@334 | 167 if (PQntuples(res2) >= 1 && !PQgetisnull(res2, 0, 0)) { |
| jbe@334 | 168 old_res2 = res2; |
| jbe@334 | 169 } else { |
| jbe@334 | 170 PQclear(res2); |
| jbe@334 | 171 break; |
| jbe@334 | 172 } |
| jbe@334 | 173 } |
| jbe@65 | 174 } |
| jbe@334 | 175 PQfreemem(escaped_issue_id); |
| jbe@65 | 176 } |
| jbe@334 | 177 PQclear(res); |
| jbe@0 | 178 } |
| jbe@1 | 179 |
| jbe@1 | 180 // cleanup and exit |
| jbe@0 | 181 PQfinish(db); |
| jbe@65 | 182 return err; |
| jbe@1 | 183 |
| jbe@0 | 184 } |