Ejemplo n.º 1
0
/*!
 * \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;
		}
	}
}
Ejemplo n.º 2
0
/*
 * 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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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 */
}
Ejemplo n.º 5
0
/*
 * 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;
}