aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoronefang2020-05-22 14:06:15 +1000
committeronefang2020-05-22 14:06:15 +1000
commit3786fbcb20e77ff6a4367349f22b6817671ab62a (patch)
tree5c0ec460dd4f40cc643950ae5c2015f37af5bce6
parentClear out some no longer needed stuff. (diff)
downloadopensim-SC_OLD-3786fbcb20e77ff6a4367349f22b6817671ab62a.zip
opensim-SC_OLD-3786fbcb20e77ff6a4367349f22b6817671ab62a.tar.gz
opensim-SC_OLD-3786fbcb20e77ff6a4367349f22b6817671ab62a.tar.bz2
opensim-SC_OLD-3786fbcb20e77ff6a4367349f22b6817671ab62a.tar.xz
Deal with the database connection going away, and various related clean ups.
Or try to, MariaDB don't make it easy.
-rw-r--r--src/sledjchisl/sledjchisl.c757
1 files changed, 402 insertions, 355 deletions
diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c
index 537b435..a8d8b3f 100644
--- a/src/sledjchisl/sledjchisl.c
+++ b/src/sledjchisl/sledjchisl.c
@@ -375,7 +375,6 @@ struct _reqData
375 qhashtbl_t *configs, *queries, *body, *cookies, *headers, *valid, *stuff, *database, *Rcookies, *Rheaders; 375 qhashtbl_t *configs, *queries, *body, *cookies, *headers, *valid, *stuff, *database, *Rcookies, *Rheaders;
376 char *Scheme, *Host, *Method, *Script, *Path, *RUri, *doit, *form, *output, *outQuery; 376 char *Scheme, *Host, *Method, *Script, *Path, *RUri, *doit, *form, *output, *outQuery;
377 sesh shs, *lnk; 377 sesh shs, *lnk;
378 MYSQL *db;
379 gridStats *stats; 378 gridStats *stats;
380 qlist_t *errors, *messages; 379 qlist_t *errors, *messages;
381 qgrow_t *reply; 380 qgrow_t *reply;
@@ -411,6 +410,9 @@ char toybuf[4096];
411lua_State *L; 410lua_State *L;
412qhashtbl_t *configs; 411qhashtbl_t *configs;
413MYSQL *database, *dbconn; 412MYSQL *database, *dbconn;
413unsigned int dbTimeout;
414struct timespec dbLast;
415my_bool dbReconnect;
414gridStats *stats; 416gridStats *stats;
415boolean isTmux = 0; 417boolean isTmux = 0;
416boolean isWeb = 0; 418boolean isWeb = 0;
@@ -882,36 +884,203 @@ static void dumpArray(int d, char **ar)
882} 884}
883 885
884 886
885/* How to deal with prepared SQL statements.
886http://karlssonondatabases.blogspot.com/2010/07/prepared-statements-are-they-useful-or.html
887https://blog.cotten.io/a-taste-of-mysql-in-c-87c5de84a31d?gi=ab3dd1425b29
888https://raspberry-projects.com/pi/programming-in-c/databases-programming-in-c/mysql/accessing-the-database
889 887
890IG and CG now both have sims connected to other grids, so some sort of 888typedef struct _dbFields dbFields;
891multi database solution would be good, then we can run the grid and the 889struct _dbFields
892external sims all in one. 890{
891 qlisttbl_t *flds;
892 int count;
893};
894typedef struct _dbField dbField;
895struct _dbField
896{
897 char *name;
898 enum enum_field_types type;
899 unsigned long length;
900 unsigned int flags;
901 unsigned int decimals;
902};
893 903
894Not sure if this'll work with Count(*). 904void dbFreeFields(dbFields *flds, boolean all)
905{
906 flds->count--;
895 907
896--------------------------------------------- 908// TODO - sigh, looks to be inconsistant why some do and some don't leak.
909// I guess the ones that don't leak are the ones that crash?
910// It's only a tiny leak anyway, 80 bytes total.
911// if ((0 >= flds->count) || all) // CRASHY
912 if ((0 >= flds->count)) // LEAKY
913 {
914 qlisttbl_obj_t obj;
897 915
898The complicated bit is the binds. 916 memset((void *) &obj, 0, sizeof(obj));
917 flds->flds->lock(flds->flds);
918 while(flds->flds->getnext(flds->flds, &obj, NULL, false) == true)
919 {
920 dbField *fld = (dbField *) obj.data;
921 free(fld->name);
922 }
923 flds->flds->unlock(flds->flds);
924 flds->flds->free(flds->flds);
925 flds->flds = NULL;
926 free(flds);
927 }
928}
899 929
900You are binding field values to C memory locations. 930enum dbCommandType
901The parameters and returned fields need binds. 931{
902Mostly seems to be the value parts of the SQL statements. 932 CT_SELECT,
933 CT_CREATE,
934 CT_UPDATE,
935 CT_NONE
936};
903 937
904I suspect most will be of the form - 938typedef struct _dbRequest dbRequest;
905 ... WHERE x=? and foo=? 939struct _dbRequest
906 INSERT INTO table VALUES (?,?,?) 940{
907 UPDATE table SET x=?, foo=? WHERE id=? 941 char *table, *join, *where, *order, *sql;
942 MYSQL_STMT *prep; // NOTE - executing it stores state in this.
943 dbFields *fields;
944 int inCount, outCount, rowCount;
945 char **inParams, **outParams;
946 MYSQL_BIND *inBind, *outBind;
947 rowData *rows;
948 my_ulonglong count;
949 enum dbCommandType type;
950 boolean freeOutParams;
951};
908 952
909 A multi table update - 953void dbFreeRequest(dbRequest *req, boolean all)
910 UPDATE items,month SET items.price=month.price WHERE items.id=month.id; 954{
911*/ 955 int i;
956
957 D("Cleaning up prepared database request %s - %s %d %d", req->table, req->where, req->outCount, req->inCount);
958
959 if (NULL != req->outBind)
960 {
961 for (i = 0; i < req->outCount; i++)
962 {
963 if (NULL != req->outBind[i].buffer) free(req->outBind[i].buffer);
964 if (NULL != req->outBind[i].length) free(req->outBind[i].length);
965 if (NULL != req->outBind[i].error) free(req->outBind[i].error);
966 if (NULL != req->outBind[i].is_null) free(req->outBind[i].is_null);
967 }
968 free(req->outBind);
969 req->outBind = NULL;
970 }
971 else
972 D(" No out binds to clean up for %s - %s.", req->table, req->where);
973 if (NULL != req->inBind)
974 {
975 for (i = 0; i < req->inCount; i++)
976 {
977 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer);
978 if (NULL != req->inBind[i].length) free(req->inBind[i].length);
979 if (NULL != req->inBind[i].error) free(req->inBind[i].error);
980 if (NULL != req->inBind[i].is_null) free(req->inBind[i].is_null);
981 }
982 free(req->inBind);
983 req->inBind = NULL;
984 }
985 else
986 D(" No in binds to clean up for %s - %s.", req->table, req->where);
987
988 if (req->freeOutParams && all)
989 {
990 if (NULL != req->outParams)
991 {
992 free(req->outParams);
993 req->outParams = NULL;
994 }
995 else
996 D(" No out params to clean up for %s - %s.", req->table, req->where);
997 }
998 if (NULL != req->sql) free(req->sql);
999 else
1000 D(" No SQL to clean up for %s - %s.", req->table, req->where);
1001 req->sql = NULL;
1002 if (NULL != req->prep)
1003 {
1004 if (0 != mysql_stmt_close(req->prep))
1005 C(" Unable to close the prepared statement!");
1006 req->prep = NULL;
1007 }
1008
1009 if (all)
1010 {
1011 if (NULL != req->fields)
1012 {
1013 dbFreeFields(req->fields, all);
1014 req->fields = NULL;
1015 }
1016 else
1017 D(" No fields to clean up for %s - %s.", req->table, req->where);
1018 }
1019}
1020
1021void freeDb(boolean all)
1022{
1023 dbRequest **rq;
1024
1025 if (dbRequests)
1026 {
1027 if (all)
1028 {
1029 while (NULL != (rq = (dbRequest **) dbRequests->popfirst(dbRequests, NULL)))
1030 {
1031 dbFreeRequest(*rq, all);
1032 free(rq);
1033 }
1034 dbRequests->free(dbRequests);
1035 dbRequests = NULL;
1036 }
1037 else
1038 {
1039 qlist_obj_t obj;
1040
1041 memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call
1042 dbRequests->lock(dbRequests);
1043 while (dbRequests->getnext(dbRequests, &obj, false) == true)
1044 dbFreeRequest(*((dbRequest **) obj.data), all);
1045 dbRequests->unlock(dbRequests);
1046 }
1047 }
1048
1049 if (database) mysql_close(database);
1050 database = NULL;
1051 mysql_library_end();
1052}
912 1053
913static boolean dbConnect() 1054static boolean dbConnect()
914{ 1055{
1056 database = mysql_init(NULL);
1057 if (NULL == database)
1058 {
1059 E("mysql_init() failed - %s", mysql_error(database));
1060 return FALSE;
1061 }
1062
1063/* TODO - dammit, no mysql_get_option(), MariaDB docs say mysql_get_optionv(), which doesn't exist either.
1064 Says "This function was added in MariaDB Connector/C 3.0.0.", I have MariaDB / MySQL client version: 10.1.44-MariaDB.
1065
1066 if (mysql_get_option(database, MYSQL_OPT_CONNECT_TIMEOUT, &dbTimeout))
1067 E("mysql_get_option(MYSQL_OPT_CONNECT_TIMEOUT) failed - %s", mysql_error(database));
1068 else
1069 D("Database MYSQL_OPT_CONNECT_TIMEOUT = %d", dbTimeout);
1070
1071 if (mysql_get_option(database, MYSQL_OPT_RECONNECT, &dbReconnect))
1072 E("mysql_get_option(MYSQL_OPT_RECONNECT) failed - %s", mysql_error(database));
1073 else
1074 D("Database MYSQL_OPT_RECONNECT = %d", (int) dbReconnect);
1075*/
1076
1077 // Seems best to disable auto-reconnect, so I have more control over reconnections.
1078 dbReconnect = 0;
1079 if (mysql_options(database, MYSQL_OPT_RECONNECT, &dbReconnect))
1080 E("mysql_options(MYSQL_OPT_RECONNECT) failed - %s", mysql_error(database));
1081 else
1082 D("Database MYSQL_OPT_RECONNECT is now %d", (int) dbReconnect);
1083
915 dbconn = mysql_real_connect(database, 1084 dbconn = mysql_real_connect(database,
916 getStrH(configs, "Data Source"), 1085 getStrH(configs, "Data Source"),
917 getStrH(configs, "User ID"), 1086 getStrH(configs, "User ID"),
@@ -925,6 +1094,21 @@ static boolean dbConnect()
925 E("mysql_real_connect() failed - %s", mysql_error(database)); 1094 E("mysql_real_connect() failed - %s", mysql_error(database));
926 return FALSE; 1095 return FALSE;
927 } 1096 }
1097
1098 // Just set the fucking thing. Pffft.
1099 dbTimeout = 60 * 60 * 24 * 7 * 52;
1100dbTimeout = 100;
1101 char *sql = xmprintf("SET SESSION wait_timeout=%d", (int) dbTimeout);
1102
1103 if (mysql_query(database, sql))
1104 E("SET SESSION wait_timeout=%d failed - %s", (int) dbTimeout, mysql_error(database));
1105 else
1106 D("Database wait_timeout = %d", (int) dbReconnect);
1107 free(sql);
1108
1109 if (-1 == clock_gettime(CLOCK_REALTIME, &dbLast))
1110 perror_msg("Unable to get the time.");
1111
928 return TRUE; 1112 return TRUE;
929} 1113}
930 1114
@@ -933,43 +1117,41 @@ static boolean dbConnect()
933// 1129? 1152? 1184? 1218? 1927 3032? 4150? 1117// 1129? 1152? 1184? 1218? 1927 3032? 4150?
934// "server has gone away" isn't listed there, that's the one I was getting. Pffft 1118// "server has gone away" isn't listed there, that's the one I was getting. Pffft
935// It's 2006, https://dev.mysql.com/doc/refman/8.0/en/gone-away.html 1119// It's 2006, https://dev.mysql.com/doc/refman/8.0/en/gone-away.html
936// Though none of the mentioned reasons make sense here.
937// Ah it could be "connection inactive for 8 hours". 1120// Ah it could be "connection inactive for 8 hours".
938// Which might be why OpenSim opens a new connection for EVERYTHING. 1121// Which might be why OpenSim opens a new connection for EVERYTHING.
939// TODO - see if I can either find out what the time out is, or just check and re open for each db thing. 1122// https://dev.mysql.com/doc/refman/5.7/en/c-api-auto-reconnect.html
940// int mysql_ping(MYSQL * mysql); // https://mariadb.com/kb/en/mysql_ping/ 1123// Has more details.
941// "If it has gone down, and global option reconnect is enabled an automatic reconnection is attempted." 1124static boolean dbCheckError(char *error, char *sql)
942// "Returns zero on success, nonzero if an error occured."
943// "resources bundled to the connection (prepared statements, locks, temporary tables, ...) will be released." sigh
944// Quick'n'dirty until this is properly event driven - have a cron job curl the stats page every hour.
945static boolean dbCheckError(MYSQL *db, char *error, char *sql)
946{ 1125{
947 int e = mysql_errno(db); 1126 int e = mysql_errno(database);
948 1127
949 E("MariaDB error %d - %s: %s\n%s", e, error, mysql_error(db), sql); 1128 E("MariaDB error %d - %s: %s\n%s", e, error, mysql_error(database), sql);
950 if (2006 == e) 1129 if (2006 == e)
1130 {
1131 W("Reconnecting to database.");
1132 freeDb(false);
951 return dbConnect(); 1133 return dbConnect();
1134 }
952 1135
953 return FALSE; 1136 return FALSE;
954} 1137}
955 1138// "Statement execute failed 2013: Lost connection to MySQL server during query"
956typedef struct _dbFields dbFields; 1139static boolean dbStmtCheckError(dbRequest *req, char *error, char *sql)
957struct _dbFields
958{ 1140{
959 qlisttbl_t *flds; 1141 int e = mysql_stmt_errno(req->prep);
960 int count; 1142
961}; 1143 E("MariaDB prepared statement error %d - %s: %s\n%s", e, error, mysql_stmt_error(req->prep), sql);
962typedef struct _dbField dbField; 1144 if (2013 == e)
963struct _dbField 1145 {
964{ 1146 W("Reconnecting to database.");
965 char *name; 1147 freeDb(false);
966 enum enum_field_types type; 1148 return dbConnect();
967 unsigned long length; 1149 }
968 unsigned int flags; 1150
969 unsigned int decimals; 1151 return FALSE;
970}; 1152}
971 1153
972dbFields *dbGetFields(MYSQL *db, char *table) 1154dbFields *dbGetFields(char *table)
973{ 1155{
974 static qhashtbl_t *tables = NULL; 1156 static qhashtbl_t *tables = NULL;
975 if (NULL == tables) tables = qhashtbl(0, 0); 1157 if (NULL == tables) tables = qhashtbl(0, 0);
@@ -982,33 +1164,33 @@ dbFields *dbGetFields(MYSQL *db, char *table)
982 char *sql = xmprintf("SELECT * FROM %s LIMIT 0", table); 1164 char *sql = xmprintf("SELECT * FROM %s LIMIT 0", table);
983 1165
984d("Getting field metadata for %s", table); 1166d("Getting field metadata for %s", table);
985 if (mysql_query(db, sql)) 1167 if (mysql_query(database, sql))
986 { 1168 {
987// E("MariaDB error %d - Query failed 0: %s\n%s", mysql_errno(db), mysql_error(db), sql); 1169// E("MariaDB error %d - Query failed 0: %s\n%s", mysql_errno(database), mysql_error(database), sql);
988 if (dbCheckError(db, "Query failed 0", sql)) 1170 if (dbCheckError("Query failed 0", sql))
989 { 1171 {
990 ret = dbGetFields(db, table); 1172 ret = dbGetFields(table);
991 free(sql); 1173 free(sql);
992 return ret; 1174 return ret;
993 } 1175 }
994 } 1176 }
995 else 1177 else
996 { 1178 {
997 MYSQL_RES *res = mysql_store_result(db); 1179 MYSQL_RES *res = mysql_store_result(database);
998 1180
999 if (!res) 1181 if (!res)
1000 E("MariaDB error %d - Couldn't get results set from %s\n %s", mysql_errno(db), mysql_error(db), sql); 1182 E("MariaDB error %d - Couldn't get results set from %s\n %s", mysql_errno(database), mysql_error(database), sql);
1001 else 1183 else
1002 { 1184 {
1003 MYSQL_FIELD *fields = mysql_fetch_fields(res); 1185 MYSQL_FIELD *fields = mysql_fetch_fields(res);
1004 1186
1005 if (!fields) 1187 if (!fields)
1006 E("MariaDB error %d - Failed fetching fields: %s", mysql_errno(db), mysql_error(db)); 1188 E("MariaDB error %d - Failed fetching fields: %s", mysql_errno(database), mysql_error(database));
1007 else 1189 else
1008 { 1190 {
1009 unsigned int i, num_fields = mysql_num_fields(res); 1191 unsigned int i, num_fields = mysql_num_fields(res);
1010 1192
1011 ret = xmalloc(sizeof(dbFields)); 1193 ret = xmalloc(sizeof(dbFields)); // Little bit LEAKY
1012 ret->flds = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_LOOKUPFORWARD); 1194 ret->flds = qlisttbl(QLISTTBL_UNIQUE | QLISTTBL_LOOKUPFORWARD);
1013 ret->count = 1; 1195 ret->count = 1;
1014 for (i = 0; i < num_fields; i++) 1196 for (i = 0; i < num_fields; i++)
@@ -1035,62 +1217,61 @@ d("Getting field metadata for %s", table);
1035 return ret; 1217 return ret;
1036} 1218}
1037 1219
1038void dbFreeFields(dbFields *flds)
1039{
1040 flds->count--;
1041 if (0 >= flds->count)
1042 {
1043 qlisttbl_obj_t obj;
1044 1220
1045 memset((void *) &obj, 0, sizeof(obj)); 1221/* How to deal with prepared SQL statements.
1046 flds->flds->lock(flds->flds); 1222http://karlssonondatabases.blogspot.com/2010/07/prepared-statements-are-they-useful-or.html
1047 while(flds->flds->getnext(flds->flds, &obj, NULL, false) == true) 1223https://blog.cotten.io/a-taste-of-mysql-in-c-87c5de84a31d?gi=ab3dd1425b29
1048 { 1224https://raspberry-projects.com/pi/programming-in-c/databases-programming-in-c/mysql/accessing-the-database
1049 dbField *fld = (dbField *) obj.data;
1050 free(fld->name);
1051 }
1052 flds->flds->unlock(flds->flds);
1053 flds->flds->free(flds->flds);
1054 free(flds);
1055 }
1056}
1057 1225
1058enum dbCommandType 1226IG and CG now both have sims connected to other grids, so some sort of
1059{ 1227multi database solution would be good, then we can run the grid and the
1060 CT_SELECT, 1228external sims all in one.
1061 CT_CREATE,
1062 CT_UPDATE,
1063 CT_NONE
1064};
1065 1229
1066typedef struct _dbRequest dbRequest; 1230Not sure if this'll work with Count(*).
1067struct _dbRequest 1231
1068{ 1232---------------------------------------------
1069 MYSQL *db; 1233
1070 char *table, *join, *where, *order, *sql; 1234The complicated bit is the binds.
1071 MYSQL_STMT *prep; // NOTE - executing it stores state in this. 1235
1072 dbFields *fields; 1236You are binding field values to C memory locations.
1073 qlisttbl_t *flds; 1237The parameters and returned fields need binds.
1074 int inCount, outCount, rowCount; 1238Mostly seems to be the value parts of the SQL statements.
1075 char **inParams, **outParams; 1239
1076 MYSQL_BIND *inBind, *outBind; 1240I suspect most will be of the form -
1077 rowData *rows; 1241 ... WHERE x=? and foo=?
1078 my_ulonglong count; 1242 INSERT INTO table VALUES (?,?,?)
1079 enum dbCommandType type; 1243 UPDATE table SET x=?, foo=? WHERE id=?
1080 boolean freeOutParams; 1244
1081}; 1245 A multi table update -
1246 UPDATE items,month SET items.price=month.price WHERE items.id=month.id;
1247*/
1082 1248
1083int dbDoSomething(dbRequest *req, boolean count, ...) 1249int dbDoSomething(dbRequest *req, boolean count, ...)
1084{ 1250{
1085 int ret = 0; 1251 int ret = 0;
1086 va_list ap; 1252 va_list ap;
1087 struct timespec now, then; 1253 struct timespec then;
1088 int i, j; 1254 int i, j;
1089 MYSQL_RES *prepare_meta_result = NULL; 1255 MYSQL_RES *prepare_meta_result = NULL;
1090 1256
1091 if (-1 == clock_gettime(CLOCK_REALTIME, &then)) 1257 if (-1 == clock_gettime(CLOCK_REALTIME, &then))
1092 perror_msg("Unable to get the time."); 1258 perror_msg("Unable to get the time.");
1093 1259
1260 double n = (dbLast.tv_sec * 1000000000.0) + dbLast.tv_nsec;
1261 double t = (then.tv_sec * 1000000000.0) + then.tv_nsec;
1262
1263t("Database timeout test %lf > %lf", ((t - n) / 1000000000.0), (dbTimeout / 2.0));
1264 if (((t - n) / 1000000000.0) > (dbTimeout / 2.0))
1265 {
1266 T("Avoid database timeout of %d seconds, pinging it.", dbTimeout);
1267 if (0 != mysql_ping(database))
1268 {
1269 W("Reconnecting to database.");
1270 freeDb(false);
1271 dbConnect();
1272 }
1273 }
1274
1094 va_start(ap, count); 1275 va_start(ap, count);
1095 1276
1096 if (NULL == req->prep) 1277 if (NULL == req->prep)
@@ -1100,14 +1281,13 @@ int dbDoSomething(dbRequest *req, boolean count, ...)
1100 if (0 == req->type) 1281 if (0 == req->type)
1101 req->type = CT_SELECT; 1282 req->type = CT_SELECT;
1102 1283
1103 req->fields = dbGetFields(req->db, req->table); 1284 req->fields = dbGetFields(req->table);
1104 if (NULL == req->fields) 1285 if (NULL == req->fields)
1105 { 1286 {
1106 E("Unknown fields for table %s.", req->table); 1287 E("Unknown fields for table %s.", req->table);
1107 ret++; 1288 ret++;
1108 goto end; 1289 goto end;
1109 } 1290 }
1110 req->flds = req->fields->flds;
1111 1291
1112 switch (req->type) 1292 switch (req->type)
1113 { 1293 {
@@ -1189,7 +1369,7 @@ int dbDoSomething(dbRequest *req, boolean count, ...)
1189 1369
1190d("New SQL statement - %s", req->sql); 1370d("New SQL statement - %s", req->sql);
1191 // prepare statement with the other fields 1371 // prepare statement with the other fields
1192 req->prep = mysql_stmt_init(req->db); 1372 req->prep = mysql_stmt_init(database);
1193 if (NULL == req->prep) 1373 if (NULL == req->prep)
1194 { 1374 {
1195 E("Statement prepare init failed: %s\n", mysql_stmt_error(req->prep)); 1375 E("Statement prepare init failed: %s\n", mysql_stmt_error(req->prep));
@@ -1218,7 +1398,7 @@ d("New SQL statement - %s", req->sql);
1218//W("Allocated %d %d inBinds for %s", i, req->inCount, req->sql); 1398//W("Allocated %d %d inBinds for %s", i, req->inCount, req->sql);
1219 for (i = 0; i < req->inCount; i++) 1399 for (i = 0; i < req->inCount; i++)
1220 { 1400 {
1221 dbField *fld = req->flds->get(req->flds, req->inParams[i], NULL, false); 1401 dbField *fld = req->fields->flds->get(req->fields->flds, req->inParams[i], NULL, false);
1222 1402
1223 if (NULL == fld) 1403 if (NULL == fld)
1224 { 1404 {
@@ -1359,15 +1539,15 @@ I("count!!!!!!!!!!!!!!!!");
1359 req->freeOutParams = TRUE; 1539 req->freeOutParams = TRUE;
1360 qlisttbl_obj_t obj; 1540 qlisttbl_obj_t obj;
1361 memset((void*)&obj, 0, sizeof(obj)); 1541 memset((void*)&obj, 0, sizeof(obj));
1362 req->flds->lock(req->flds); 1542 req->fields->flds->lock(req->fields->flds);
1363 while (req->flds->getnext(req->flds, &obj, NULL, false) == true) 1543 while (req->fields->flds->getnext(req->fields->flds, &obj, NULL, false) == true)
1364 { 1544 {
1365 dbField *fld = (dbField *) obj.data; 1545 dbField *fld = (dbField *) obj.data;
1366 req->outParams[i] = fld->name; 1546 req->outParams[i] = fld->name;
1367 i++; 1547 i++;
1368 } 1548 }
1369 req->outParams[i] = NULL; 1549 req->outParams[i] = NULL;
1370 req->flds->unlock(req->flds); 1550 req->fields->flds->unlock(req->fields->flds);
1371 } 1551 }
1372 if (i != req->outCount) 1552 if (i != req->outCount)
1373 { 1553 {
@@ -1379,7 +1559,7 @@ I("count!!!!!!!!!!!!!!!!");
1379//W("Allocated %d %d outBinds for %s", i, req->outCount, req->sql); 1559//W("Allocated %d %d outBinds for %s", i, req->outCount, req->sql);
1380 for (i = 0; i < req->outCount; i++) 1560 for (i = 0; i < req->outCount; i++)
1381 { 1561 {
1382 dbField *fld = req->flds->get(req->flds, req->outParams[i], NULL, false); 1562 dbField *fld = req->fields->flds->get(req->fields->flds, req->outParams[i], NULL, false);
1383 1563
1384 if (NULL == fld) 1564 if (NULL == fld)
1385 { 1565 {
@@ -1503,7 +1683,7 @@ I("count!!!!!!!!!!!!!!!!");
1503//d("input bind for %s", req->sql); 1683//d("input bind for %s", req->sql);
1504 for (i = 0; i < req->inCount; i++) 1684 for (i = 0; i < req->inCount; i++)
1505 { 1685 {
1506 dbField *fld = req->flds->get(req->flds, req->inParams[i], NULL, false); 1686 dbField *fld = req->fields->flds->get(req->fields->flds, req->inParams[i], NULL, false);
1507 1687
1508 if (NULL == fld) 1688 if (NULL == fld)
1509 { 1689 {
@@ -1651,9 +1831,11 @@ I("count!!!!!!!!!!!!!!!!");
1651 // do the prepared statement req->prep. 1831 // do the prepared statement req->prep.
1652 if (mysql_stmt_execute(req->prep)) 1832 if (mysql_stmt_execute(req->prep))
1653 { 1833 {
1654 E("Statement execute failed %d: %s\n", mysql_stmt_errno(req->prep), mysql_stmt_error(req->prep)); 1834 if (dbStmtCheckError(req, "Statement failed 0", req->sql))
1655 ret++; 1835 {
1656 goto freeIt; 1836 ret++;
1837 goto freeIt;
1838 }
1657 } 1839 }
1658 1840
1659 int fs = mysql_stmt_field_count(req->prep); 1841 int fs = mysql_stmt_field_count(req->prep);
@@ -1681,7 +1863,7 @@ I("count!!!!!!!!!!!!!!!!");
1681 1863
1682 for (i = 0; i < req->outCount; i++) 1864 for (i = 0; i < req->outCount; i++)
1683 { 1865 {
1684 dbField *fld = req->flds->get(req->flds, req->outParams[i], NULL, false); 1866 dbField *fld = req->fields->flds->get(req->fields->flds, req->outParams[i], NULL, false);
1685 1867
1686 req->rows->fieldNames[i] = fld->name; 1868 req->rows->fieldNames[i] = fld->name;
1687 if (!*(req->outBind[i].is_null)) 1869 if (!*(req->outBind[i].is_null))
@@ -1803,10 +1985,9 @@ freeIt:
1803end: 1985end:
1804 va_end(ap); 1986 va_end(ap);
1805 1987
1806 if (-1 == clock_gettime(CLOCK_REALTIME, &now)) 1988 if (-1 == clock_gettime(CLOCK_REALTIME, &dbLast))
1807 perror_msg("Unable to get the time."); 1989 perror_msg("Unable to get the time.");
1808 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec; 1990 n = (dbLast.tv_sec * 1000000000.0) + dbLast.tv_nsec;
1809 double t = (then.tv_sec * 1000000000.0) + then.tv_nsec;
1810 T("dbDoSomething(%s) took %lf seconds", req->sql, (n - t) / 1000000000.0); 1991 T("dbDoSomething(%s) took %lf seconds", req->sql, (n - t) / 1000000000.0);
1811 1992
1812 return ret; 1993 return ret;
@@ -1838,62 +2019,7 @@ d("dbPull(Rd->database) %s = %s", where, (char *) obj.data);
1838 free(rows); 2019 free(rows);
1839} 2020}
1840 2021
1841void dbFreeRequest(dbRequest *req) 2022my_ulonglong dbCount(char *table, char *where)
1842{
1843 int i;
1844
1845 D("Cleaning up prepared database request %s - %s %d %d", req->table, req->where, req->outCount, req->inCount);
1846
1847 if (NULL != req->fields)
1848 {
1849 dbFreeFields(req->fields);
1850 req->fields = NULL;
1851 }
1852 else
1853 D(" No fields to clean up for %s - %s.", req->table, req->where);
1854
1855 if (NULL != req->outBind)
1856 {
1857 for (i = 0; i < req->outCount; i++)
1858 {
1859 if (NULL != req->outBind[i].buffer) free(req->outBind[i].buffer);
1860 if (NULL != req->outBind[i].length) free(req->outBind[i].length);
1861 if (NULL != req->outBind[i].error) free(req->outBind[i].error);
1862 if (NULL != req->outBind[i].is_null) free(req->outBind[i].is_null);
1863 }
1864 free(req->outBind);
1865 }
1866 else
1867 D(" No out binds to clean up for %s - %s.", req->table, req->where);
1868 if (NULL != req->inBind)
1869 {
1870 for (i = 0; i < req->inCount; i++)
1871 {
1872 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer);
1873 if (NULL != req->inBind[i].length) free(req->inBind[i].length);
1874 if (NULL != req->inBind[i].error) free(req->inBind[i].error);
1875 if (NULL != req->inBind[i].is_null) free(req->inBind[i].is_null);
1876 }
1877 free(req->inBind);
1878 }
1879 else
1880 D(" No in binds to clean up for %s - %s.", req->table, req->where);
1881
1882 if (req->freeOutParams) free(req->outParams);
1883 else
1884 D(" No out params to clean up for %s - %s.", req->table, req->where);
1885 if (NULL != req->sql) free(req->sql);
1886 else
1887 D(" No SQL to clean up for %s - %s.", req->table, req->where);
1888 if (NULL != req->prep)
1889 {
1890 if (0 != mysql_stmt_close(req->prep))
1891 C(" Unable to close the prepared statement!");
1892 req->prep = NULL;
1893 }
1894}
1895
1896my_ulonglong dbCount(MYSQL *db, char *table, char *where)
1897{ 2023{
1898 my_ulonglong ret = 0; 2024 my_ulonglong ret = 0;
1899 char *sql; 2025 char *sql;
@@ -1907,27 +2033,27 @@ my_ulonglong dbCount(MYSQL *db, char *table, char *where)
1907 else 2033 else
1908 sql = xmprintf("SELECT Count(*) FROM %s", table); 2034 sql = xmprintf("SELECT Count(*) FROM %s", table);
1909 2035
1910 if (mysql_query(db, sql)) 2036 if (mysql_query(database, sql))
1911 { 2037 {
1912// E("MariaDB error %d - Query failed 1: %s", mysql_errno(db), mysql_error(db)); 2038// E("MariaDB error %d - Query failed 1: %s", mysql_errno(database), mysql_error(database));
1913 if (dbCheckError(db, "Query failed 1", sql)) 2039 if (dbCheckError("Query failed 1", sql))
1914 { 2040 {
1915 ret = dbCount(db, table, where); 2041 ret = dbCount(table, where);
1916 free(sql); 2042 free(sql);
1917 return ret; 2043 return ret;
1918 } 2044 }
1919 } 2045 }
1920 else 2046 else
1921 { 2047 {
1922 MYSQL_RES *result = mysql_store_result(db); 2048 MYSQL_RES *result = mysql_store_result(database);
1923 2049
1924 if (!result) 2050 if (!result)
1925 E("Couldn't get results set from %s\n: %s", sql, mysql_error(db)); 2051 E("Couldn't get results set from %s\n: %s", sql, mysql_error(database));
1926 else 2052 else
1927 { 2053 {
1928 MYSQL_ROW row = mysql_fetch_row(result); 2054 MYSQL_ROW row = mysql_fetch_row(result);
1929 if (!row) 2055 if (!row)
1930 E("MariaDB error %d - Couldn't get row from %s\n: %s", mysql_errno(db), sql, mysql_error(db)); 2056 E("MariaDB error %d - Couldn't get row from %s\n: %s", mysql_errno(database), sql, mysql_error(database));
1931 else 2057 else
1932 ret = atoll(row[0]); 2058 ret = atoll(row[0]);
1933 mysql_free_result(result); 2059 mysql_free_result(result);
@@ -1943,7 +2069,7 @@ my_ulonglong dbCount(MYSQL *db, char *table, char *where)
1943 return ret; 2069 return ret;
1944} 2070}
1945 2071
1946my_ulonglong dbCountJoin(MYSQL *db, char *table, char *select, char *join, char *where) 2072my_ulonglong dbCountJoin(char *table, char *select, char *join, char *where)
1947{ 2073{
1948 my_ulonglong ret = 0; 2074 my_ulonglong ret = 0;
1949 char *sql; 2075 char *sql;
@@ -1962,22 +2088,22 @@ my_ulonglong dbCountJoin(MYSQL *db, char *table, char *select, char *join, char
1962 else 2088 else
1963 sql = xmprintf("SELECT %s FROM %s", select, table, join); 2089 sql = xmprintf("SELECT %s FROM %s", select, table, join);
1964 2090
1965 if (mysql_query(db, sql)) 2091 if (mysql_query(database, sql))
1966 { 2092 {
1967// E("MariaDB error %d - Query failed 2: %s", mysql_errno(db), mysql_error(db)); 2093// E("MariaDB error %d - Query failed 2: %s", mysql_errno(database), mysql_error(database));
1968 if (dbCheckError(db, "Query failed 2", sql)) 2094 if (dbCheckError("Query failed 2", sql))
1969 { 2095 {
1970 ret = dbCountJoin(db, table, select, join, where); 2096 ret = dbCountJoin(table, select, join, where);
1971 free(sql); 2097 free(sql);
1972 return ret; 2098 return ret;
1973 } 2099 }
1974 } 2100 }
1975 else 2101 else
1976 { 2102 {
1977 MYSQL_RES *result = mysql_store_result(db); 2103 MYSQL_RES *result = mysql_store_result(database);
1978 2104
1979 if (!result) 2105 if (!result)
1980 E("MariaDB error %d - Couldn't get results set from %s\n: %s", mysql_errno(db), sql, mysql_error(db)); 2106 E("MariaDB error %d - Couldn't get results set from %s\n: %s", mysql_errno(database), sql, mysql_error(database));
1981 else 2107 else
1982 ret = mysql_num_rows(result); 2108 ret = mysql_num_rows(result);
1983 mysql_free_result(result); 2109 mysql_free_result(result);
@@ -1992,51 +2118,6 @@ my_ulonglong dbCountJoin(MYSQL *db, char *table, char *select, char *join, char
1992 return ret; 2118 return ret;
1993} 2119}
1994 2120
1995MYSQL_RES *dbSelect(MYSQL *db, char *table, char *select, char *join, char *where, char *order)
1996{
1997 MYSQL_RES *ret = NULL;
1998 char *sql;
1999 struct timespec now, then;
2000
2001 if (-1 == clock_gettime(CLOCK_REALTIME, &then))
2002 perror_msg("Unable to get the time.");
2003
2004 if (NULL == select)
2005 select = "*";
2006 if (NULL == join)
2007 join = "";
2008
2009 if (where)
2010 sql = xmprintf("SELECT %s FROM %s %s WHERE %s", select, table, join, where);
2011 else
2012 sql = xmprintf("SELECT %s FROM %s", select, table, join);
2013
2014 if (order)
2015 {
2016 char *t = xmprintf("%s ORDER BY %s", sql, order);
2017
2018 free(sql);
2019 sql = t;
2020 }
2021
2022 if (mysql_query(db, sql))
2023 E("MariaDB error %d - Query failed 3: %s\n%s", mysql_errno(db), mysql_error(db), sql);
2024 else
2025 {
2026 ret = mysql_store_result(db);
2027 if (!ret)
2028 E("MariaDB error %d - Couldn't get results set from %s\n %s", mysql_errno(db), mysql_error(db), sql);
2029 }
2030
2031 if (-1 == clock_gettime(CLOCK_REALTIME, &now))
2032 perror_msg("Unable to get the time.");
2033 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec;
2034 double t = (then.tv_sec * 1000000000.0) + then.tv_nsec;
2035 T("dbSelect(%s) took %lf seconds", sql, (n - t) / 1000000000.0);
2036 free(sql);
2037 return ret;
2038}
2039
2040 2121
2041void replaceStr(qhashtbl_t *ssi, char *key, char *value) 2122void replaceStr(qhashtbl_t *ssi, char *key, char *value)
2042{ 2123{
@@ -2105,91 +2186,88 @@ gridStats *getStats(MYSQL *db, gridStats *stats)
2105 replaceStr(stats->stats, "gridOnline", "online"); 2186 replaceStr(stats->stats, "gridOnline", "online");
2106 else 2187 else
2107 replaceStr(stats->stats, "gridOnline", "offline"); 2188 replaceStr(stats->stats, "gridOnline", "offline");
2108 if (db)
2109 {
2110 char *tmp;
2111 my_ulonglong locIn = dbCount(db, "Presence", "RegionID != '00000000-0000-0000-0000-000000000000'"); // Locals online but not HGing, and HGers in world.
2112 my_ulonglong HGin = dbCount(db, "Presence", "UserID NOT IN (SELECT PrincipalID FROM UserAccounts)"); // HGers in world.
2113 2189
2114 // Collect stats about members. 2190 char *tmp;
2115 replaceLong(stats->stats, "hgers", HGin); 2191 my_ulonglong locIn = dbCount("Presence", "RegionID != '00000000-0000-0000-0000-000000000000'"); // Locals online but not HGing, and HGers in world.
2116 if (locIn >= HGin) // Does OpenSim have too many ghosts? 2192 my_ulonglong HGin = dbCount("Presence", "UserID NOT IN (SELECT PrincipalID FROM UserAccounts)"); // HGers in world.
2117 replaceLong(stats->stats, "inworld", locIn - HGin);
2118 else
2119 replaceLong(stats->stats, "inworld", 0);
2120 tmp = xmprintf("GridExternalName != '%s'", stats->stats->getstr(stats->stats, "uri", false));
2121 replaceLong(stats->stats, "outworld", dbCount(db, "hg_traveling_data", tmp));
2122 free(tmp);
2123 replaceLong(stats->stats, "members", dbCount(db, "UserAccounts", NULL));
2124
2125 // Count local and HG visitors for the last 30 and 60 days.
2126 locIn = dbCountJoin(db, "GridUser", "GridUser.UserID", "INNER JOIN UserAccounts ON GridUser.UserID = UserAccounts.PrincipalID",
2127 "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 2419200))");
2128 HGin = dbCount(db, "GridUser", "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 2419200))");
2129 replaceLong(stats->stats, "locDay30", locIn);
2130 replaceLong(stats->stats, "day30", HGin);
2131 replaceLong(stats->stats, "HGday30", HGin - locIn);
2132
2133 locIn = dbCountJoin(db, "GridUser", "GridUser.UserID", "INNER JOIN UserAccounts ON GridUser.UserID = UserAccounts.PrincipalID",
2134 "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 4838400))");
2135 HGin = dbCount(db, "GridUser", "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 4838400))");
2136 replaceLong(stats->stats, "locDay60", locIn);
2137 replaceLong(stats->stats, "day60", HGin);
2138 replaceLong(stats->stats, "HGday60", HGin - locIn);
2139
2140 // Collect stats about sims.
2141 replaceLong(stats->stats, "sims", dbCount(db, "regions", NULL));
2142 replaceLong(stats->stats, "onlineSims", dbCount(db, "regions", "sizeX != 0"));
2143 replaceLong(stats->stats, "varRegions", dbCount(db, "regions", "sizeX > 256 or sizeY > 256"));
2144 replaceLong(stats->stats, "singleSims", dbCount(db, "regions", "sizeX = 256 and sizeY = 256"));
2145 replaceLong(stats->stats, "offlineSims", dbCount(db, "regions", "sizeX = 0"));
2146
2147 // Calculate total size of all regions.
2148 my_ulonglong simSize = 0;
2149 static dbRequest *rgnSizes = NULL;
2150 if (NULL == rgnSizes)
2151 {
2152 static char *szi[] = {NULL};
2153 static char *szo[] = {"sizeX", "sizeY", NULL};
2154 rgnSizes = xzalloc(sizeof(dbRequest));
2155 rgnSizes->db = db;
2156 rgnSizes->table = "regions";
2157 rgnSizes->inParams = szi;
2158 rgnSizes->outParams = szo;
2159 rgnSizes->where = "sizeX != 0";
2160 dbRequests->addfirst(dbRequests, &rgnSizes, sizeof(dbRequest *));
2161 }
2162 dbDoSomething(rgnSizes, FALSE);
2163 rowData *rows = rgnSizes->rows;
2164 2193
2165 qhashtbl_t *row; 2194 // Collect stats about members.
2166 while (NULL != (row = rows->rows->getat(rows->rows, 0, NULL, true))) 2195 replaceLong(stats->stats, "hgers", HGin);
2167 { 2196 if (locIn >= HGin) // Does OpenSim have too many ghosts?
2168 my_ulonglong x = 0, y = 0; 2197 replaceLong(stats->stats, "inworld", locIn - HGin);
2198 else
2199 replaceLong(stats->stats, "inworld", 0);
2200 tmp = xmprintf("GridExternalName != '%s'", stats->stats->getstr(stats->stats, "uri", false));
2201 replaceLong(stats->stats, "outworld", dbCount("hg_traveling_data", tmp));
2202 free(tmp);
2203 replaceLong(stats->stats, "members", dbCount("UserAccounts", NULL));
2169 2204
2170 tmp = row->getstr(row, "sizeX", false); 2205 // Count local and HG visitors for the last 30 and 60 days.
2171 if (NULL == tmp) 2206 locIn = dbCountJoin("GridUser", "GridUser.UserID", "INNER JOIN UserAccounts ON GridUser.UserID = UserAccounts.PrincipalID",
2172 E("No regions.sizeX!"); 2207 "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 2419200))");
2173 else 2208 HGin = dbCount("GridUser", "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 2419200))");
2174 x = atoll(tmp); 2209 replaceLong(stats->stats, "locDay30", locIn);
2175 tmp = row->getstr(row, "sizeY", false); 2210 replaceLong(stats->stats, "day30", HGin);
2176 if (NULL == tmp) 2211 replaceLong(stats->stats, "HGday30", HGin - locIn);
2177 E("No regions.sizeY!");
2178 else
2179 y = atoll(tmp);
2180 simSize += x * y;
2181 row->free(row);
2182 rows->rows->removefirst(rows->rows);
2183 }
2184 free(rows->fieldNames);
2185 rows->rows->free(rows->rows);
2186 free(rows);
2187 2212
2188 tmp = xmprintf("%lu", simSize); 2213 locIn = dbCountJoin("GridUser", "GridUser.UserID", "INNER JOIN UserAccounts ON GridUser.UserID = UserAccounts.PrincipalID",
2189 stats->stats->putstr(stats->stats, "simsSize", tmp); 2214 "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 4838400))");
2190 free(tmp); 2215 HGin = dbCount("GridUser", "Login > UNIX_TIMESTAMP(FROM_UNIXTIME(UNIX_TIMESTAMP(now()) - 4838400))");
2191 gettimeofday(&(stats->last), NULL); 2216 replaceLong(stats->stats, "locDay60", locIn);
2217 replaceLong(stats->stats, "day60", HGin);
2218 replaceLong(stats->stats, "HGday60", HGin - locIn);
2219
2220 // Collect stats about sims.
2221 replaceLong(stats->stats, "sims", dbCount("regions", NULL));
2222 replaceLong(stats->stats, "onlineSims", dbCount("regions", "sizeX != 0"));
2223 replaceLong(stats->stats, "varRegions", dbCount("regions", "sizeX > 256 or sizeY > 256"));
2224 replaceLong(stats->stats, "singleSims", dbCount("regions", "sizeX = 256 and sizeY = 256"));
2225 replaceLong(stats->stats, "offlineSims", dbCount("regions", "sizeX = 0"));
2226
2227 // Calculate total size of all regions.
2228 my_ulonglong simSize = 0;
2229 static dbRequest *rgnSizes = NULL;
2230 if (NULL == rgnSizes)
2231 {
2232 static char *szi[] = {NULL};
2233 static char *szo[] = {"sizeX", "sizeY", NULL};
2234 rgnSizes = xzalloc(sizeof(dbRequest));
2235 rgnSizes->table = "regions";
2236 rgnSizes->inParams = szi;
2237 rgnSizes->outParams = szo;
2238 rgnSizes->where = "sizeX != 0";
2239 dbRequests->addfirst(dbRequests, &rgnSizes, sizeof(dbRequest *));
2240 }
2241 dbDoSomething(rgnSizes, FALSE); // LEAKY
2242 rowData *rows = rgnSizes->rows;
2243
2244 qhashtbl_t *row;
2245 while (NULL != (row = rows->rows->getat(rows->rows, 0, NULL, true)))
2246 {
2247 my_ulonglong x = 0, y = 0;
2248
2249 tmp = row->getstr(row, "sizeX", false);
2250 if (NULL == tmp)
2251 E("No regions.sizeX!");
2252 else
2253 x = atoll(tmp);
2254 tmp = row->getstr(row, "sizeY", false);
2255 if (NULL == tmp)
2256 E("No regions.sizeY!");
2257 else
2258 y = atoll(tmp);
2259 simSize += x * y;
2260 row->free(row);
2261 rows->rows->removefirst(rows->rows);
2192 } 2262 }
2263 free(rows->fieldNames);
2264 rows->rows->free(rows->rows);
2265 free(rows);
2266
2267 tmp = xmprintf("%lu", simSize);
2268 stats->stats->putstr(stats->stats, "simsSize", tmp);
2269 free(tmp);
2270 gettimeofday(&(stats->last), NULL);
2193 2271
2194 return stats; 2272 return stats;
2195} 2273}
@@ -3587,7 +3665,7 @@ static void generateAccountUUID(reqData *Rd)
3587 // Try database. 3665 // Try database.
3588 where = xmprintf("UserAccounts.PrincipalID = '%s'", uuid); 3666 where = xmprintf("UserAccounts.PrincipalID = '%s'", uuid);
3589 D("Trying new UUID %s.", where); 3667 D("Trying new UUID %s.", where);
3590 users = dbCount(Rd->db, "UserAccounts", where); 3668 users = dbCount("UserAccounts", where);
3591 free(where); 3669 free(where);
3592 } while (users != 0); 3670 } while (users != 0);
3593 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); 3671 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
@@ -3828,7 +3906,6 @@ notWritten:
3828 }; 3906 };
3829 static char *szo[] = {NULL}; 3907 static char *szo[] = {NULL};
3830 acntsI = xzalloc(sizeof(dbRequest)); 3908 acntsI = xzalloc(sizeof(dbRequest));
3831 acntsI->db = Rd->db;
3832 acntsI->table = "UserAccounts"; 3909 acntsI->table = "UserAccounts";
3833 acntsI->inParams = szi; 3910 acntsI->inParams = szi;
3834 acntsI->outParams = szo; 3911 acntsI->outParams = szo;
@@ -3842,7 +3919,6 @@ notWritten:
3842 static char *szi[] = {"UUID", "passwordSalt", "passwordHash", "accountType", "webLoginKey", NULL}; 3919 static char *szi[] = {"UUID", "passwordSalt", "passwordHash", "accountType", "webLoginKey", NULL};
3843 static char *szo[] = {NULL}; 3920 static char *szo[] = {NULL};
3844 authI = xzalloc(sizeof(dbRequest)); 3921 authI = xzalloc(sizeof(dbRequest));
3845 authI->db = Rd->db;
3846 authI->table = "auth"; 3922 authI->table = "auth";
3847 authI->inParams = szi; 3923 authI->inParams = szi;
3848 authI->outParams = szo; 3924 authI->outParams = szo;
@@ -3865,7 +3941,6 @@ notWritten:
3865 }; 3941 };
3866 static char *szo[] = {NULL}; 3942 static char *szo[] = {NULL};
3867 invFolderI = xzalloc(sizeof(dbRequest)); 3943 invFolderI = xzalloc(sizeof(dbRequest));
3868 invFolderI->db = Rd->db;
3869 invFolderI->table = "inventoryfolders"; 3944 invFolderI->table = "inventoryfolders";
3870 invFolderI->inParams = szi; 3945 invFolderI->inParams = szi;
3871 invFolderI->outParams = szo; 3946 invFolderI->outParams = szo;
@@ -3880,7 +3955,6 @@ notWritten:
3880 static char *szi[] = {"UserID", NULL}; // All the defaults are what we would set anyway. 3955 static char *szi[] = {"UserID", NULL}; // All the defaults are what we would set anyway.
3881 static char *szo[] = {NULL}; 3956 static char *szo[] = {NULL};
3882 gUserI = xzalloc(sizeof(dbRequest)); 3957 gUserI = xzalloc(sizeof(dbRequest));
3883 gUserI->db = Rd->db;
3884 gUserI->table = "GridUser"; 3958 gUserI->table = "GridUser";
3885 gUserI->inParams = szi; 3959 gUserI->inParams = szi;
3886 gUserI->outParams = szo; 3960 gUserI->outParams = szo;
@@ -3922,7 +3996,7 @@ notWritten:
3922 uuid_unparse_lower(binuuidI, uuidI); 3996 uuid_unparse_lower(binuuidI, uuidI);
3923// TODO - should check there isn't a folder with this UUID already. 3997// TODO - should check there isn't a folder with this UUID already.
3924 D("Creating %s inventory folder for user %s.", sysFolders[i].name, getStrH(Rd->stuff, "name")); 3998 D("Creating %s inventory folder for user %s.", sysFolders[i].name, getStrH(Rd->stuff, "name"));
3925 r += dbDoSomething(invFolderI, FALSE, uuid, sysFolders[i].name, sysFolders[i].type, 1, uuidI, uuidR); 3999 r += dbDoSomething(invFolderI, FALSE, uuid, sysFolders[i].name, sysFolders[i].type, 1, uuidI, uuidR); // LEAKY
3926 if (0 != r) 4000 if (0 != r)
3927 bitch(Rd, "Internal error.", "Failed to create invenoryFolder record."); 4001 bitch(Rd, "Internal error.", "Failed to create invenoryFolder record.");
3928 if (strcmp("My Inventory", sysFolders[i].name) == 0) 4002 if (strcmp("My Inventory", sysFolders[i].name) == 0)
@@ -3965,7 +4039,7 @@ notWritten:
3965 { 4039 {
3966 // Create location record. 4040 // Create location record.
3967 D("Creating home and last positions for user %s.", getStrH(Rd->stuff, "name")); 4041 D("Creating home and last positions for user %s.", getStrH(Rd->stuff, "name"));
3968 if (0 != dbDoSomething(gUserI, FALSE, uuid)) 4042 if (0 != dbDoSomething(gUserI, FALSE, uuid)) // LEAKY
3969 bitch(Rd, "Internal error.", "Failed to create GridUser record."); 4043 bitch(Rd, "Internal error.", "Failed to create GridUser record.");
3970 else 4044 else
3971 { 4045 {
@@ -5055,7 +5129,6 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5055 static char *szi[] = {"PrincipalID", NULL}; 5129 static char *szi[] = {"PrincipalID", NULL};
5056 static char *szo[] = {NULL}; 5130 static char *szo[] = {NULL};
5057 uuids = xzalloc(sizeof(dbRequest)); 5131 uuids = xzalloc(sizeof(dbRequest));
5058 uuids->db = Rd->db;
5059 uuids->table = "UserAccounts"; 5132 uuids->table = "UserAccounts";
5060 uuids->inParams = szi; 5133 uuids->inParams = szi;
5061 uuids->outParams = szo; 5134 uuids->outParams = szo;
@@ -5068,7 +5141,6 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5068 static char *szi[] = {"FirstName", "LastName", NULL}; 5141 static char *szi[] = {"FirstName", "LastName", NULL};
5069 static char *szo[] = {NULL}; 5142 static char *szo[] = {NULL};
5070 acnts = xzalloc(sizeof(dbRequest)); 5143 acnts = xzalloc(sizeof(dbRequest));
5071 acnts->db = Rd->db;
5072 acnts->table = "UserAccounts"; 5144 acnts->table = "UserAccounts";
5073 acnts->inParams = szi; 5145 acnts->inParams = szi;
5074 acnts->outParams = szo; 5146 acnts->outParams = szo;
@@ -5081,7 +5153,6 @@ static int accountRead(reqData *Rd, char *uuid, char *firstName, char *lastName)
5081 static char *szi[] = {"UUID", NULL}; 5153 static char *szi[] = {"UUID", NULL};
5082 static char *szo[] = {"passwordSalt", "passwordHash", NULL}; 5154 static char *szo[] = {"passwordSalt", "passwordHash", NULL};
5083 auth = xzalloc(sizeof(dbRequest)); 5155 auth = xzalloc(sizeof(dbRequest));
5084 auth->db = Rd->db;
5085 auth->table = "auth"; 5156 auth->table = "auth";
5086 auth->inParams = szi; 5157 auth->inParams = szi;
5087 auth->outParams = szo; 5158 auth->outParams = szo;
@@ -5145,7 +5216,7 @@ d("accountRead() UUID %s, name %s %s", uuid, first, last);
5145 rt = LuaToHash(Rd, where, "user", tnm, ret, &st, &now, "user"); 5216 rt = LuaToHash(Rd, where, "user", tnm, ret, &st, &now, "user");
5146 5217
5147 free(where); 5218 free(where);
5148 dbDoSomething(acnts, FALSE, first, last); 5219 dbDoSomething(acnts, FALSE, first, last); // LEAKY
5149 rows = acnts->rows; 5220 rows = acnts->rows;
5150 } 5221 }
5151 } 5222 }
@@ -5194,7 +5265,7 @@ T("Found database record.");
5194 Rd->fromDb = TRUE; 5265 Rd->fromDb = TRUE;
5195 Rd->database->putstr(Rd->database, "Lua.name", name); 5266 Rd->database->putstr(Rd->database, "Lua.name", name);
5196 free(name); 5267 free(name);
5197 dbDoSomething(auth, FALSE, getStrH(Rd->database, "UserAccounts.PrincipalID")); 5268 dbDoSomething(auth, FALSE, getStrH(Rd->database, "UserAccounts.PrincipalID")); // LEAKY
5198 rows = auth->rows; 5269 rows = auth->rows;
5199 if (rows) 5270 if (rows)
5200 { 5271 {
@@ -6263,18 +6334,6 @@ static void cleanup(void)
6263{ 6334{
6264// TODO - not sure why, but this gets called twice on quitting sometimes. 6335// TODO - not sure why, but this gets called twice on quitting sometimes.
6265 C("Caught signal, or quitting, cleaning up."); 6336 C("Caught signal, or quitting, cleaning up.");
6266 dbRequest **rq;
6267
6268 if (dbRequests)
6269 {
6270 while (NULL != (rq = (dbRequest **) dbRequests->popfirst(dbRequests, NULL)))
6271 {
6272 dbFreeRequest(*rq);
6273 free(rq);
6274 }
6275 dbRequests->free(dbRequests);
6276 dbRequests = NULL;
6277 }
6278 6337
6279 if (accountPages) 6338 if (accountPages)
6280 { 6339 {
@@ -6326,9 +6385,7 @@ static void cleanup(void)
6326 } 6385 }
6327 if (mimeTypes) mimeTypes->free(mimeTypes); 6386 if (mimeTypes) mimeTypes->free(mimeTypes);
6328 mimeTypes = NULL; 6387 mimeTypes = NULL;
6329 if (database) mysql_close(database); 6388 freeDb(true);
6330 database = NULL;
6331 mysql_library_end();
6332 if (L) lua_close(L); 6389 if (L) lua_close(L);
6333 L = NULL; 6390 L = NULL;
6334 if (stats) 6391 if (stats)
@@ -6671,28 +6728,19 @@ jit library is loaded or the JIT compiler will not be activated.
6671 E("mysql_library_init() failed!"); 6728 E("mysql_library_init() failed!");
6672 goto finished; 6729 goto finished;
6673 } 6730 }
6674 database = mysql_init(NULL); 6731 if (!dbConnect())
6675 if (NULL == database)
6676 {
6677 E("mysql_init() failed - %s", mysql_error(database));
6678 goto finished; 6732 goto finished;
6679 }
6680 else
6681 {
6682 if (!dbConnect())
6683 goto finished;
6684 6733
6685 // Need to kick this off. 6734 // Need to kick this off.
6686 stats = getStats(database, stats); 6735 stats = getStats(database, stats);
6687 char *h = qstrunchar(qconfig->getstr(qconfig, "Const.HostName", false), '"', '"'); 6736 char *h = qstrunchar(qconfig->getstr(qconfig, "Const.HostName", false), '"', '"');
6688 char *p = qstrunchar(qconfig->getstr(qconfig, "Const.PublicPort", false), '"', '"'); 6737 char *p = qstrunchar(qconfig->getstr(qconfig, "Const.PublicPort", false), '"', '"');
6689 stats->stats->putstr(stats->stats, "grid", qstrunchar(qconfig->getstr(qconfig, "Const.GridName", false), '"', '"')); 6738 stats->stats->putstr(stats->stats, "grid", qstrunchar(qconfig->getstr(qconfig, "Const.GridName", false), '"', '"'));
6690 stats->stats->putstr(stats->stats, "HostName", h); 6739 stats->stats->putstr(stats->stats, "HostName", h);
6691 stats->stats->putstr(stats->stats, "PublicPort", p); 6740 stats->stats->putstr(stats->stats, "PublicPort", p);
6692 snprintf(toybuf, sizeof(toybuf), "http://%s:%s/", h, p); 6741 snprintf(toybuf, sizeof(toybuf), "http://%s:%s/", h, p);
6693 6742
6694 stats->stats->putstr(stats->stats, "uri", toybuf); 6743 stats->stats->putstr(stats->stats, "uri", toybuf);
6695 }
6696 qconfig->free(qconfig); 6744 qconfig->free(qconfig);
6697 } 6745 }
6698 6746
@@ -6746,7 +6794,6 @@ jit library is loaded or the JIT compiler will not be activated.
6746 Rd->database = qhashtbl(0, 0); 6794 Rd->database = qhashtbl(0, 0);
6747 Rd->Rcookies = qhashtbl(0, 0); 6795 Rd->Rcookies = qhashtbl(0, 0);
6748 Rd->Rheaders = qhashtbl(0, 0); 6796 Rd->Rheaders = qhashtbl(0, 0);
6749 Rd->db = database;
6750 Rd->stats = stats; 6797 Rd->stats = stats;
6751 Rd->errors = qlist(0); 6798 Rd->errors = qlist(0);
6752 Rd->messages = qlist(0); 6799 Rd->messages = qlist(0);