/*! * \brief Write-back timer, used for WRITE_BACK db_mode * * Write-back timer, used for WRITE_BACK db_mode. Process * all contacts from the record, delete expired ones from the DB. * Furthermore it updates changed contacts, and also insert new * ones in the DB. * \param _r processed record */ static inline void wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; cstate_t old_state; int op; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } LM_DBG("Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); update_stat( _r->slot->d->expires, 1); t = ptr; ptr = ptr->next; /* Should we remove the contact from the database ? */ if (st_expired_ucontact(t) == 1) { if (db_delete_ucontact(t) < 0) { LM_ERR("failed to delete contact from the database\n"); } } mem_delete_ucontact(_r, t); } else { /* Determine the operation we have to do */ old_state = ptr->state; op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_insert_ucontact(ptr) < 0) { LM_ERR("inserting contact into database failed\n"); ptr->state = old_state; } break; case 2: /* update */ if (db_update_ucontact(ptr) < 0) { LM_ERR("updating contact in db failed\n"); ptr->state = old_state; } break; } ptr = ptr->next; } } }
/* * Update ucontact with new values */ int update_ucontact(ucontact_t* _c, time_t _e, float _q, str* _cid, int _cs, unsigned int _set, unsigned int _res) { /* we have to update memory in any case, but database directly * only in db_mode 1 */ if (mem_update_ucontact(_c, _e, _q, _cid, _cs, _set, _res) < 0) { LOG(L_ERR, "update_ucontact(): Error while updating\n"); return -1; } st_update_ucontact(_c); if (db_mode == WRITE_THROUGH) { if (db_update_ucontact(_c) < 0) { LOG(L_ERR, "update_ucontact(): Error while updating database\n"); } } return 0; }
/*! * \brief Update ucontact with new values * \param _r record the contact belongs to * \param _c updated contact * \param _ci new contact informations * \return 0 on success, -1 on failure */ int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci) { int res; /* we have to update memory in any case, but database directly * only in db_mode 1 */ if (mem_update_ucontact( _c, _ci) < 0) { LM_ERR("failed to update memory\n"); return -1; } /* run callbacks for UPDATE event */ if (exists_ulcb_type(UL_CONTACT_UPDATE)) { LM_DBG("exists callback for type= UL_CONTACT_UPDATE\n"); run_ul_callbacks( UL_CONTACT_UPDATE, _c); } if (_r && db_mode!=DB_ONLY) update_contact_pos( _r, _c); st_update_ucontact(_c); if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { /* * prevent problems when we're in a failover situation: the first DB contains * the complete location entries, the other misses some of them. Before the * update it checks for a entry in the first DB, this is ok. But the update * in the second DB will not work. Thus the expire mechanism don't work, it * takes too long until both DBs have the same number of entries again. */ if (ul_db_update_as_insert) res = db_insert_ucontact(_c); else res = db_update_ucontact(_c); if (res < 0 ) { LM_ERR("failed to update database\n"); return -1; } else { _c->state = CS_SYNC; } } return 0; }
/* * Update state of the contact * Returns 1 if the contact should be * delete from memory immediatelly, * 0 otherwise */ int st_delete_ucontact(ucontact_t* _c) { switch(_c->state) { case CS_NEW: /* Contact is new and isn't in the database * yet, we can delete it from the memory * safely if it is not marked for replication. * If it is marked we turn it into a zombie * but do not remove it from memory */ if (_c->replicate != 0) { _c->state = CS_ZOMBIE_N; return 0; } else return 1; case CS_SYNC: /* Contact is in the database so we can not * remove it from memory. Instead we turn it * into a zombie (which should be ignored by * normal functions) and let the timer process * decide how to proceed. */ _c->state = CS_ZOMBIE_D; /* to synchronyse the state change in db mode 1 * we need to update the db too */ if (db_mode == WRITE_THROUGH) { if (db_update_ucontact(_c) < 0) LOG(L_ERR, "st_delete_ucontact(): Error while updating contact" " in db\n"); else _c->state = CS_ZOMBIE_S; } return 0; case CS_DIRTY: /* Contact is in the database, * we cannot remove it from the memory * directly, but we can turn it into a zombie * and the timer will take care of deleting * the contact from the memory as well as * from the database */ _c->state = CS_ZOMBIE_D; return 0; case CS_ZOMBIE_N: /* If the removed contact in memory is still * marked for replication keep it, otherwise * remove it */ if (_c->replicate != 0) return 0; else return 1; case CS_ZOMBIE_S: case CS_ZOMBIE_D: /* This allready removed contact is in the * DB so we can not remove it from memory */ return 0; } return 0; /* Makes gcc happy */ }
/* * Write-back timer */ static inline int wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; int op; int not = 0; ptr = _r->contacts; while(ptr) { if (ptr->expires < act_time) { if (ptr->replicate != 0) { LOG(L_NOTICE, "Keeping binding '%.*s','%.*s' for " "replication\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); /* keep it for replication, but it expired normaly * and was the last contact, so notify */ if (!ptr->next && ptr->state < CS_ZOMBIE_N) not=1; ptr = ptr->next; } else { /* state == ZOMBIE the contact was remove by user */ if (ptr->state < CS_ZOMBIE_N) { LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); if (ptr->next == 0) not=1; _r->slot->d->expired++; } t = ptr; ptr = ptr->next; /* Should we remove the contact from the database ? */ if (st_expired_ucontact(t) == 1) { if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wb_timer(): Can't delete contact from the database\n"); } } mem_delete_ucontact(_r, t); } if (not) notify_watchers(_r, PRES_OFFLINE); } else { /* Determine the operation we have to do */ op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_insert_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while inserting contact into database\n"); } break; case 2: /* update */ if (db_update_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while updating contact in db\n"); } break; case 3: /* delete from memory */ mem_delete_ucontact(_r, ptr); break; case 4: /* delete */ if (db_delete_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Can't delete contact from database\n"); } mem_delete_ucontact(_r, ptr); break; } ptr = ptr->next; } } return 0; }