You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libsxmp/ydaemon/domx.c

250 lines
6.3 KiB
C

/*
* Yet another daemon library especially designed to be used
* with libsxmp based daemons.
*
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
*
* libsxmp is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libsxmp 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
*/
#include <ydaemon/dataobject.h>
#include <ydaemon/cache.h>
int domx_init(domx_t *dt, dataobject_t *dodesc)
{
if(!dt || !dodesc) return EINVAL;
/* init first values */
dt->dox = dodesc;
dt->name = dodesc->name;
dt->be = dt->cache = NULL;
/* init list for sntls lists */
list_init_head(&dt->sxmp_channels);
return 0;
}
int domx_set_be(domx_t *dt, void *be, const char *key)
{
struct be_ops *f = (struct be_ops *)be;
domx_dsbe_t *dbe;
if(!dt) return EINVAL;
if(!f || f->be_magic != BEMAGIC) return EINVAL;
if(!(dbe = malloc(sizeof(domx_dsbe_t)))) return ENOMEM;
dbe->domx = dt;
dbe->priv = NULL;
dbe->f = f;
dt->be = dbe;
return dbe->f->init(dbe, key);
}
int domx_set_cache(domx_t *dt, size_t size)
{
int r = 0;
/* paranoic check */
if(!dt || !dt->dox) return EINVAL;
if(!(dt->cache = (void *)yd_cache_init(dt->dox, size)))
r = errno;
else r = yd_cache_start_thread(dt);
return r;
}
int domx_set_sxmpchannel(domx_t *dt, const char *instance, int typeid, int access)
{
sxmp_ch_entry_t *sentry = NULL;
if(!dt || !instance) return EINVAL;
if(!(sentry = malloc(sizeof(sxmp_ch_entry_t)))) return ENOMEM;
/* init sntl channel entry */
strncpy(sentry->instance, instance, 31);
sentry->chtid = (uint16_t)typeid;
sentry->filter = (ydm_access_filter_t)access;
list_init_node(&sentry->node);
/* add this entry */
list_add2tail(&dt->sxmp_channels, &sentry->node);
return 0;
}
#define __ITEMSTOFREED 32
int domx_get(domx_t *dt, uint64_t oid, void **refdata)
{
void *data;
ydata_cache_item_t *itm;
ydata_qitem_t *qitem;
domx_dsbe_t *be;
list_head_t *rsitemslist = NULL;
list_node_t *iter, *siter;
int r = 0;
/* paranoic check up */
if(!dt || !dt->cache) return EINVAL;
if(!(be = dt->be)) return EINVAL;
__retry: /* yep, that's here, because anybody can inject our data while we're trying to refresh cache */
data = yd_cache_lookup((ydata_cache_t *)dt->cache, oid);
if(data) *refdata = data;
else { /* cache miss occured */
/* first allocate the required item within the cache */
data = yd_cache_alloc_item((ydata_cache_t *)dt->cache, &itm);
if(data) { /* we have a free entries ! */
if((r = be->f->get(be, oid, data))) yd_cache_discard_alloc_item((ydata_cache_t *)dt->cache, itm);
else {/* all is fine - confirm cache insertion */
yd_cache_confirm_alloc_item((ydata_cache_t *)dt->cache, itm, oid);
*refdata = data;
}
} else { /* we don't have free entries */
if(!(rsitemslist = yd_cache_getrslist((ydata_cache_t *)dt->cache, __ITEMSTOFREED)))
{ r = ENOMEM; goto __fini; }
/* ok, now we're ready to do something - we have unplugged items clean it up then */
list_for_each_safe(rsitemslist, iter, siter) {
qitem = container_of(iter, ydata_qitem_t, node);
itm = qitem->item;
if(itm->attr & YDC_DIRTY) /* if dirty - sync, but we don't care result here - if corrupted - data is totally corrupteed*/
be->f->set(be, itm->oid, (yd_cache_ptrbyidx((ydata_cache_t *)dt->cache, itm->idx)) + sizeof(uint32_t));
}
/* now we need to return there list back to the cache and retry */
yd_cache_qitems_pullback((ydata_cache_t *)dt->cache, rsitemslist);
goto __retry;
}
}
__fini:
return r;
}
int domx_set(domx_t *dt, uint64_t oid, const void *refdata)
{
domx_dsbe_t *be;
void *data;
ydata_cache_t *cc;
int r = 0;
/* paranoic check up */
if(!dt || !dt->cache) return EINVAL;
if(!(be = dt->be)) return EINVAL;
cc = (ydata_cache_t *)dt->cache;
data = yd_cache_lookup(cc, oid);
__again:
if(data) { /* we have those object with this oid in cache */
memcpy(data, refdata, cc->object_size); /* copy object data */
yd_cache_item_dirtyoid(cc, oid); /* just point to the cache - dirty */
} else { /* we're trying to set invalidated data */
r = domx_get(dt, oid, &data);
if(!r) goto __again;
}
return r;
}
int domx_remove(domx_t *dt, uint64_t oid)
{
domx_dsbe_t *be;
void *data;
ydata_cache_t *cc;
/* paranoic check up */
if(!dt || !dt->cache) return EINVAL;
if(!(be = dt->be)) return EINVAL;
cc = (ydata_cache_t *)dt->cache;
data = yd_cache_lookup(cc, oid);
if(data) yd_cache_item_invalidateoid(cc, oid);
return be->f->remove(be, oid);
}
int domx_creat(domx_t *dt, uint64_t *oid, const void *refdata)
{
domx_dsbe_t *be;
oid_t r = 0;
/* paranoic check up */
if(!dt || !dt->cache) return EINVAL;
if(!(be = dt->be)) return EINVAL;
/* here we just create this one and nothing */
r = be->f->creat(be, refdata);
if(!r) return errno;
*oid = r;
return 0;
}
yd_idx_stream_t *domx_idxl_open(domx_t *dt, ydm_access_filter_t afilter,
dataacc_pemctx_t *dacc, yd_filter_t *datafilter)
{
domx_dsbe_t *be;
/* paranoic check up */
if(!dt || !dt->cache) {
__einval:
errno = EINVAL;
return NULL;
}
if(!(be = dt->be)) goto __einval;
return be->f->create_idx_stream(be, afilter, dacc, datafilter);
}
void domx_idxl_close(domx_t *dt, yd_idx_stream_t *idxl)
{
domx_dsbe_t *be;
/* paranoic check up */
if(!dt || !dt->cache) {
__einval:
errno = EINVAL;
return;
}
if(!(be = dt->be) || !idxl) goto __einval;
be->f->destroy_idx_stream(idxl);
}
yd_idx_stream_win_t *domx_idxl_read(domx_t *dt, yd_idx_stream_t *idxl)
{
domx_dsbe_t *be;
/* paranoic check up */
if(!dt || !dt->cache) {
__einval:
errno = EINVAL;
return NULL;
}
if(!(be = dt->be) || !idxl) goto __einval;
return be->f->getportion_idx_stream(idxl);
}