/* * Yet another daemon library especially designed to be used * with libsxmp based daemons. * * (c) Alexander Vdolainen 2016 * * 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 ."; * */ #include #include 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); }