/* Helper function: This handles the PUT state action using an * <b>obj_type</b> and <b>data</b> needed for the action. * PUT frees the previous data before replacing it, if needed. */ static void state_query_put_(sr_state_object_t obj_type, void *data) { if (BUG(!sr_state)) return; switch (obj_type) { case SR_STATE_OBJ_COMMIT: { sr_commit_t *commit = data; tor_assert(commit); /* commit_add_to_state() frees the old commit, if there is one */ commit_add_to_state(commit, sr_state); break; } case SR_STATE_OBJ_CURSRV: /* Check if the new pointer is the same as the old one: if it is, it's * probably a bug. The caller may have confused current and previous, * or they may have forgotten to sr_srv_dup(). * Putting NULL multiple times is allowed. */ if (!BUG(data && sr_state->current_srv == (sr_srv_t *) data)) { /* We own the old SRV, so we need to free it. */ state_query_del_(SR_STATE_OBJ_CURSRV, NULL); sr_state->current_srv = (sr_srv_t *) data; } break; case SR_STATE_OBJ_PREVSRV: /* Check if the new pointer is the same as the old one: if it is, it's * probably a bug. The caller may have confused current and previous, * or they may have forgotten to sr_srv_dup(). * Putting NULL multiple times is allowed. */ if (!BUG(data && sr_state->previous_srv == (sr_srv_t *) data)) { /* We own the old SRV, so we need to free it. */ state_query_del_(SR_STATE_OBJ_PREVSRV, NULL); sr_state->previous_srv = (sr_srv_t *) data; } break; case SR_STATE_OBJ_VALID_AFTER: sr_state->valid_after = *((time_t *) data); break; /* It's not allowed to change the phase nor the full commitments map from * the state. The phase is decided during a strict process post voting and * the commits should be put individually. */ case SR_STATE_OBJ_PHASE: case SR_STATE_OBJ_COMMITS: default: tor_assert(0); } }
/* Query state using an <b>action</b> for an object type <b>obj_type</b>. * The <b>data</b> pointer needs to point to an object that the action needs * to use and if anything is required to be returned, it is stored in * <b>out</b>. * * This mechanism exists so we have one single point where we synchronized * our memory state with our disk state for every actions that changes it. * We then trigger a write on disk immediately. * * This should be the only entry point to our memory state. It's used by all * our state accessors and should be in the future. */ static void state_query(sr_state_action_t action, sr_state_object_t obj_type, void *data, void **out) { switch (action) { case SR_STATE_ACTION_GET: *out = state_query_get_(obj_type, data); break; case SR_STATE_ACTION_PUT: state_query_put_(obj_type, data); break; case SR_STATE_ACTION_DEL: state_query_del_(obj_type, data); break; case SR_STATE_ACTION_DEL_ALL: state_query_del_all_(obj_type); break; case SR_STATE_ACTION_SAVE: /* Only trigger a disk state save. */ break; default: tor_assert(0); } /* If the action actually changes the state, immediately save it to disk. * The following will sync the state -> disk state and then save it. */ if (action != SR_STATE_ACTION_GET) { disk_state_save_to_disk(); } }