Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions modules/cachedb_local/cachedb_local.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

#include "cachedb_local.h"
#include "cachedb_local_replication.h"
#include "cachedb_local_evi.h"
#include "hash.h"

#include "../../mem/rpm_mem.h"
Expand Down Expand Up @@ -743,6 +744,11 @@ static int mod_init(void)
}
}

if (lcache_event_init() < 0) {
LM_ERR("failed to init cachedb_local events\n");
return -1;
}

/* register timer to delete the expired entries */
register_timer("localcache-expire",localcache_clean, 0,
cache_clean_period, TIMER_FLAG_DELAY_ON_DELAY);
Expand Down Expand Up @@ -815,19 +821,29 @@ static void destroy(void)
}
}

/* temporary list node for collecting expired entries outside the lock */
struct expired_ev {
str key;
str value;
struct expired_ev *next;
};

void localcache_clean(unsigned int ticks,void *param)
{
int i;
lcache_entry_t* me1, *me2;
lcache_col_t* it;
lcache_t* cache_htable;
struct expired_ev *ev_list, *ev, *ev_next;

for ( it=lcache_collection; it; it=it->next ) {
LM_DBG("start\n");
cache_htable = it->col_htable->htable;

for(i = 0; i< it->col_htable->size; i++)
{
ev_list = NULL;

lock_get(&cache_htable[i].lock);
me1 = cache_htable[i].entries;
me2 = NULL;
Expand All @@ -839,6 +855,25 @@ void localcache_clean(unsigned int ticks,void *param)
LM_DBG("deleted entry attr= [%.*s]\n",
me1->attr.len, me1->attr.s);

/* save key/value for event after lock release */
if (ei_lcache_expired_id != EVI_ERROR) {
ev = pkg_malloc(sizeof(*ev) +
me1->attr.len + me1->value.len);
if (ev) {
ev->key.s = (char *)(ev + 1);
ev->key.len = me1->attr.len;
memcpy(ev->key.s, me1->attr.s,
me1->attr.len);
ev->value.s = ev->key.s +
me1->attr.len;
ev->value.len = me1->value.len;
memcpy(ev->value.s, me1->value.s,
me1->value.len);
ev->next = ev_list;
ev_list = ev;
}
}

if(me2)
{
me2->next = me1->next;
Expand All @@ -863,6 +898,15 @@ void localcache_clean(unsigned int ticks,void *param)
}

lock_release(&cache_htable[i].lock);

/* raise events outside the lock to avoid deadlocks
* if the event_route handler accesses the cache */
for (ev = ev_list; ev; ev = ev_next) {
ev_next = ev->next;
lcache_raise_expired_event(&ev->key,
&ev->value, &it->col_name);
pkg_free(ev);
}
}
}
}
Expand Down
93 changes: 93 additions & 0 deletions modules/cachedb_local/cachedb_local_evi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2026 OpenSIPS Solutions
*
* This file is part of opensips, a free SIP server.
*
* opensips is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* opensips is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "cachedb_local_evi.h"
#include "../../dprint.h"
#include "../../mem/mem.h"

event_id_t ei_lcache_expired_id = EVI_ERROR;

static evi_params_p lcache_expired_params;
static evi_param_p lcache_ev_key;
static evi_param_p lcache_ev_value;
static evi_param_p lcache_ev_collection;

int lcache_event_init(void)
{
ei_lcache_expired_id = evi_publish_event(
str_init(LCACHE_EV_EXPIRED));
if (ei_lcache_expired_id == EVI_ERROR) {
LM_ERR("cannot register %s event\n", LCACHE_EV_EXPIRED);
return -1;
}

lcache_expired_params = pkg_malloc(sizeof(evi_params_t));
if (!lcache_expired_params) {
LM_ERR("no more pkg memory\n");
return -1;
}
memset(lcache_expired_params, 0, sizeof(evi_params_t));

lcache_ev_key = evi_param_create(lcache_expired_params,
_str(LCACHE_EV_PARAM_KEY));
if (!lcache_ev_key)
goto error;

lcache_ev_value = evi_param_create(lcache_expired_params,
_str(LCACHE_EV_PARAM_VALUE));
if (!lcache_ev_value)
goto error;

lcache_ev_collection = evi_param_create(lcache_expired_params,
_str(LCACHE_EV_PARAM_COLLECTION));
if (!lcache_ev_collection)
goto error;

return 0;

error:
LM_ERR("cannot create event parameter\n");
return -1;
}

void lcache_raise_expired_event(const str *key, const str *value,
const str *collection)
{
if (ei_lcache_expired_id == EVI_ERROR || !evi_probe_event(ei_lcache_expired_id))
return;

if (evi_param_set_str(lcache_ev_key, key) < 0) {
LM_ERR("cannot set key parameter\n");
return;
}

if (evi_param_set_str(lcache_ev_value, value) < 0) {
LM_ERR("cannot set value parameter\n");
return;
}

if (evi_param_set_str(lcache_ev_collection, collection) < 0) {
LM_ERR("cannot set collection parameter\n");
return;
}

if (evi_raise_event(ei_lcache_expired_id, lcache_expired_params) < 0)
LM_ERR("cannot raise %s event\n", LCACHE_EV_EXPIRED);
}
39 changes: 39 additions & 0 deletions modules/cachedb_local/cachedb_local_evi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2026 OpenSIPS Solutions
*
* This file is part of opensips, a free SIP server.
*
* opensips is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* opensips is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef _CACHEDB_LOCAL_EVI_H_
#define _CACHEDB_LOCAL_EVI_H_

#include "../../evi/evi_modules.h"
#include "../../evi/evi_params.h"

#define LCACHE_EV_EXPIRED "E_CACHEDB_LOCAL_EXPIRED"

#define LCACHE_EV_PARAM_KEY "key"
#define LCACHE_EV_PARAM_VALUE "value"
#define LCACHE_EV_PARAM_COLLECTION "collection"

extern event_id_t ei_lcache_expired_id;

int lcache_event_init(void);
void lcache_raise_expired_event(const str *key, const str *value,
const str *collection);

#endif /* _CACHEDB_LOCAL_EVI_H_ */
39 changes: 39 additions & 0 deletions modules/cachedb_local/doc/cachedb_local_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,43 @@ opensips-cli -x mi cachedb_local:fetch_chunk "keyprefix*" collection
</section>
</section>

<section id="exported_events" xreflabel="Exported Events">
<title>Exported Events</title>
<section id="event_E_CACHEDB_LOCAL_EXPIRED"
xreflabel="E_CACHEDB_LOCAL_EXPIRED">
<title>
<function moreinfo="none">E_CACHEDB_LOCAL_EXPIRED</function>
</title>
<para>
This event is raised when a cached entry expires and is
removed during the periodic cleanup (controlled by
<varname>cache_clean_period</varname>).
</para>
<para>Parameters:</para>
<itemizedlist>
<listitem><para>
<emphasis>key</emphasis> - The key of the
expired cache entry.
</para></listitem>
<listitem><para>
<emphasis>value</emphasis> - The value of the
expired cache entry.
</para></listitem>
<listitem><para>
<emphasis>collection</emphasis> - The name of
the cache collection.
</para></listitem>
</itemizedlist>
<example>
<title>E_CACHEDB_LOCAL_EXPIRED usage</title>
<programlisting format="linespecific">
event_route[E_CACHEDB_LOCAL_EXPIRED] {
xlog("cache expired: $param(key) = $param(value) "
"in collection $param(collection)\n");
}
</programlisting>
</example>
</section>
</section>

</chapter>