/* * The event scheduler and resource ticker. */ static void run_ticker (db_t *database) { time_t last = time(NULL); int events = 0, sleeps = 0; debug(DEBUG_TICKER, "running"); while (!finish) { /* set up memory pool */ struct memory_pool *pool = memory_pool_new(); time_t now = time(NULL); int secs = now - last; if (secs >= TICKER_LOADAVG_TIME) { debug(DEBUG_TICKER, "ticker load: %.2f (%d events/min)", 1 - sleep_time / 1000000.0 * sleeps / secs, 60 * events / secs); events = sleeps = 0; last = now; #ifdef DEBUG_MALLOC CHECK_LEAKS(); #endif } if (reload) { debug(DEBUG_TICKER, "reload config"); reload = 0; /* read config file */ config_read_file(config_file); fetch_config_values(); log_handler_set_file(debug_log, debug_logfile); log_handler_set_file(error_log, error_logfile); log_handler_set_file(msg_log, msg_logfile); } try { char resource_timestamp[TIMESTAMP_LEN]; char timestamp[TIMESTAMP_LEN]; db_result_t *next_result = NULL; const char *next_timestamp = make_timestamp_gm(resource_timestamp, tick_next_event()); const char *next_db_eventID; int next_eventType; int i; /* check each event queue to find the next event to process */ debug(DEBUG_EVENTS, "start loop, next resource event"); for (i = 0; i < eventTableSize; ++i) { db_result_t *result; /* get only the next non-blocked event, if its timestamp is smaller than the smallest found timestamp */ debug(DEBUG_EVENTS, "query event table: %s", eventTableList[i].table); // debug(DEBUG_TICKER, "query event table: %s", eventTableList[i].table); result = db_query(database, "SELECT * FROM %s WHERE blocked = 0 AND end < '%s' " "ORDER BY end ASC, %s ASC LIMIT 0,1", eventTableList[i].table, next_timestamp, eventTableList[i].id_field); if (db_result_num_rows(result)) /* is there an earlier event? */ { /* extract this earlier event's needed data */ db_result_next_row(result); next_result = result; /* remember the earlier one */ next_timestamp = db_result_get_string(result, "end"); next_db_eventID = db_result_get_string(result, eventTableList[i].id_field); next_eventType = i; } } if (strcmp(next_timestamp, make_timestamp_gm(timestamp, time(NULL))) > 0) { debug(DEBUG_EVENTS, "no event pending, sleep"); ++sleeps; usleep(sleep_time); } else { debug(DEBUG_TICKER, "event: scheduled %s, now %s", next_timestamp, timestamp); /* check which handler to call (resource ticker or event handler) */ if (next_result) { /* found an event in the event tables: block the event */ debug(DEBUG_EVENTS, "block event: %s", next_db_eventID); ++events; db_query(database, "UPDATE %s SET blocked = 1 WHERE %s = %s", eventTableList[next_eventType].table, eventTableList[next_eventType].id_field, next_db_eventID); /* call handler and delete event */ eventTableList[next_eventType].handler(database, next_result); debug(DEBUG_EVENTS_DELETE, "delete event: %s", next_db_eventID); db_query(database, "DELETE FROM %s WHERE %s = %s", eventTableList[next_eventType].table, eventTableList[next_eventType].id_field, next_db_eventID); } else { /* next event is resource tick: call resource ticker */ debug(DEBUG_TICKER, "resource tick %s", resource_timestamp); resource_ticker(database, tick_advance()); debug(DEBUG_TICKER, "resource tick ended"); tick_log(); /* log last successful update */ } } } catch (BAD_ARGUMENT_EXCEPTION) { warning("%s", except_msg); } catch (SQL_EXCEPTION) { warning("%s", except_msg); } catch (GENERIC_EXCEPTION) { warning("%s", except_msg); } catch (DB_EXCEPTION) { block_ticker(except_msg); } catch (NULL) { error("%s", except_msg); } end_try; memory_pool_free(pool); } debug(DEBUG_TICKER, "end"); }
/* * merge_artefacts_special * Throws exception if needed conditions are not as they should have been. */ int merge_artefacts_special (db_t *database, const struct Artefact *key_artefact, struct Artefact *lock_artefact, struct Artefact *result_artefact) { db_result_t *result; db_result_t *temp_result; int row; /* get merging formulas */ result = db_query(database, "SELECT * FROM Artefact_merge_special " "WHERE keyID = %d", key_artefact->artefactID); /* check for a suitable merging formula */ while ((row = db_result_next_row(result))) { /* some special cases: * * lockID == 0 || keyID == lockID * no lock artefact needed; key artefact transforms directly * * resultID == 0 * key and lock artefacts just vanish */ /* lock artefact */ lock_artefact->artefactID = db_result_get_int(result, "lockID"); /* special cases: lockID == 0 || keyID == lockID (no lock required) */ if (lock_artefact->artefactID == 0 || lock_artefact->artefactID == key_artefact->artefactID) break; /* get lock_artefact */ /* throws exception, if that artefact is missing */ get_artefact_by_id(database, lock_artefact->artefactID, lock_artefact); /* check: key and lock have to be in the same cave and initiated */ if (lock_artefact->caveID == key_artefact->caveID && lock_artefact->initiated == ARTEFACT_INITIATED) break; } if (row) { /* result artefact */ result_artefact->artefactID = db_result_get_int(result, "resultID"); /* special case: resultID == 0 */ if (result_artefact->artefactID != 0) { /* get result_artefact */ /* throws exception, if that artefact is missing */ get_artefact_by_id(database, result_artefact->artefactID, result_artefact); /* check: result_artefact must not be in any cave */ if (result_artefact->caveID != 0) throwf(BAD_ARGUMENT_EXCEPTION, "merge_artefacts_special: result artefact %d is in cave %d", result_artefact->artefactID, result_artefact->caveID); /* result_artefact must not be in any movement */ temp_result = db_query(database, "SELECT * FROM Event_movement" " WHERE artefactID = %d", result_artefact->artefactID); if (db_result_num_rows(temp_result) != 0) throwf(BAD_ARGUMENT_EXCEPTION, "merge_artefacts_special: result artefact %d is moving", result_artefact->artefactID); /* check: result_artefact has to be uninitiated */ /* XXX can this ever happen (it is not in a cave)? */ if (result_artefact->initiated != ARTEFACT_UNINITIATED) uninitiate_artefact(database, result_artefact->artefactID); } /* now merge them */ merge_artefacts(database, key_artefact->caveID, key_artefact->artefactID, lock_artefact->artefactID, result_artefact->artefactID); return 1; } return 0; }