From 23b19029f436917dcd16b65abdb3ac87a15f2dfc Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Wed, 20 Apr 2016 05:02:30 +0300 Subject: [PATCH] [core] added ydaemon data manipulation stuff; --- include/Makefile.am | 2 +- include/ydaemon/cache.h | 95 +++++++ include/ydaemon/dataobject.h | 287 +++++++++++++++++++++ ydaemon/Makefile.am | 3 +- ydaemon/cache.c | 465 +++++++++++++++++++++++++++++++++++ ydaemon/data.c | 226 +++++++++++++++++ ydaemon/domx.c | 249 +++++++++++++++++++ ydaemon/filter.c | 219 +++++++++++++++++ ydaemon/idxstream.c | 67 +++++ 9 files changed, 1611 insertions(+), 2 deletions(-) create mode 100644 include/ydaemon/cache.h create mode 100644 include/ydaemon/dataobject.h create mode 100644 ydaemon/cache.c create mode 100644 ydaemon/data.c create mode 100644 ydaemon/domx.c create mode 100644 ydaemon/filter.c create mode 100644 ydaemon/idxstream.c diff --git a/include/Makefile.am b/include/Makefile.am index 022cfd1..91af4bc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,4 +4,4 @@ nobase_include_HEADERS = sxmp/sxmp.h sxmp/errno.h sxmp/limits.h sxmp/version.h \ sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h \ tdata/bitwise.h tdata/idx_allocator.h tdata/macro.h tdata/tree.h \ tdata/usrtc.h tdata/list.h tdata/ctrie.h \ - ydaemon/ydaemon.h + ydaemon/ydaemon.h ydaemon/cache.h ydaemon/dataobject.h diff --git a/include/ydaemon/cache.h b/include/ydaemon/cache.h new file mode 100644 index 0000000..5d0de49 --- /dev/null +++ b/include/ydaemon/cache.h @@ -0,0 +1,95 @@ +/* + * 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 ."; + * + */ + +#ifndef __YDATA_CACHE_H__ +#define __YDATA_CACHE_H__ + +#include + +#define YD_CACHE_SPACER_MAGIC 0xbeafbeef + +/* item flags */ +#define YDC_INVALIDATE (1 << 1) +#define YDC_UNUSED (1 << 2) +#define YDC_DIRTY (1 << 3) + +typedef struct __ydata_cache_item_type { + oid_t oid; + uint32_t idx; + uint8_t attr; + usrtc_node_t idxnode; + list_node_t listnode; +} ydata_cache_item_t; + +#define yd_item_idx(item) (item)->idx +#define yd_item_setoid(it, id) (it)->oid = id + +typedef struct __ydata_qitem_type { + ydata_cache_item_t *item; + list_node_t node; +} ydata_qitem_t; + +#define YDC_SYNCTHRESHOLD 64 +#define YDC_SYNCDELTASEC 30 + +typedef struct __ydata_cache_t { + usrtc_t idx_tree; + list_head_t free_poll; + list_head_t dirty_poll; + list_head_t pending_poll; + void *cache; + size_t object_size; + size_t objects_amount; + size_t cache_size; + size_t dirties; + pthread_t syncthread; + pthread_rwlock_t rwlock; + pthread_mutex_t dirtlock; +} ydata_cache_t; + +#define yd_cache_rdlock(c) pthread_rwlock_rdlock(&(c)->rwlock) +#define yd_cache_wrlock(c) pthread_rwlock_wrlock(&(c)->rwlock) +#define yd_cache_unlock(c) pthread_rwlock_unlock(&(c)->rwlock) + +#define yd_cache_ptrbyidx(c, n) (char *)(c)->cache + n*((c)->object_size + sizeof(uint32_t)) + +/* API, mostly internally used, but might be useful */ +ydata_cache_t *yd_cache_init(dataobject_t *, size_t); + +void *yd_cache_alloc_item(ydata_cache_t *, ydata_cache_item_t **); + +void yd_cache_discard_alloc_item(ydata_cache_t *, ydata_cache_item_t *); + +void yd_cache_confirm_alloc_item(ydata_cache_t *, ydata_cache_item_t *, oid_t); + +void *yd_cache_lookup(ydata_cache_t *, oid_t); + +list_head_t *yd_cache_getrslist(ydata_cache_t *, uint8_t); + +void yd_cache_qitems_pullback(ydata_cache_t *, list_head_t *); + +void yd_cache_item_dirtyoid(ydata_cache_t *, oid_t); + +void yd_cache_item_invalidateoid(ydata_cache_t *, oid_t); + +int yd_cache_start_thread(domx_t *); + +#endif /* __YDATA_CACHE_H__ */ diff --git a/include/ydaemon/dataobject.h b/include/ydaemon/dataobject.h new file mode 100644 index 0000000..957770f --- /dev/null +++ b/include/ydaemon/dataobject.h @@ -0,0 +1,287 @@ +/* + * 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 ."; + * + */ + +#ifndef __DM_DATAOBJECT_H__ +#define __DM_DATAOBJECT_H__ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_ITEM_NAME 32 +#define MAX_ITEMS 255 + +typedef uint64_t oid_t; + +enum { + U8 = 0, + S8, + U16, + S16, + U32, + S32, + U64, + S64, + CSTR, + TBLOB, + TACRT, +}; + +struct typelen { + uint8_t type; + uint64_t len; +}; + +typedef struct __access_rights_type { + uint32_t ouid; + uint32_t ogid; + uint8_t domainid; + uint8_t sal; + uint8_t amask; + uint8_t reserve; +}__attribute__((packed)) acc_right_t; + +typedef struct __dataacc_pemctx_type { + acc_right_t *uobj; + uint32_t gids[16]; +} dataacc_pemctx_t; + +#ifdef DMUX_USE +static struct typelen tltable[] = { + {.type = U8, .len = 1}, + {.type = S8, .len = 1}, + {.type = U16, .len = 2}, + {.type = S16, .len = 2}, + {.type = U32, .len = 4}, + {.type = S32, .len = 4}, + {.type = U64, .len = 8}, + {.type = S64, .len = 8}, + {.type = CSTR, .len = 0}, + {.type = TBLOB, .len = 0}, + {.type = TACRT, .len = sizeof(acc_right_t) }, +}; +#endif + +typedef struct __dataobject_item_type { + uint8_t id; + uint8_t type; + uint64_t len; + char name[MAX_ITEM_NAME]; + list_node_t node; +}__attribute__ ((packed)) dataobject_item_t; + +typedef struct __item_idx_type { + void *key; + dataobject_item_t *dtr; + usrtc_node_t node; +} item_idx_t; + +typedef struct __dataobject_type { + char name[MAX_ITEMS]; + list_head_t description; /* description of the data */ + usrtc_t id_index; + usrtc_t name_index; +} dataobject_t; + +/* API */ +dataobject_t *dotr_create(const char *name); + +int dotr_set_item(dataobject_t *dotr, uint8_t type, uint64_t len, const char *name); + +uint8_t dotr_item_type(dataobject_t *obj, const char *name, uint64_t *len); + +char *dotr_item_nameptr(dataobject_t *obj, const char *name); + +int dotr_item_nameidx(dataobject_t *obj, const char *name); + +void dotr_destroy(dataobject_t *dotr); + +/* dataobject misc operations */ +int dtocmp(const dataobject_t *src, const dataobject_t *dst); + +size_t dtolen(const dataobject_t *src); + +/* + * Filtering used for access to the data stream. + */ +typedef enum { + YDM_NO_FILTER = 0, /* no access right filter */ + YDM_DOMAIN_FILTER, /* filter only by domain */ + YDM_USERDAC_FILTER, /* filter by domain and user with DAC */ + YDM_FULL_FILTER, /* all above filter plus additional filtering */ +} ydm_access_filter_t; + +typedef struct __sxmp_ch_entry_type { + char instance[32]; + uint16_t chtid; + ydm_access_filter_t filter; + list_node_t node; +} sxmp_ch_entry_t; + +struct __domx_dsbe_type; + +/* some intermodular structures */ +typedef struct __domx_type { + dataobject_t *dox; + char *name; + list_head_t sxmp_channels; + struct __domx_dsbe_type *be; + void *cache; +} domx_t; + +/* initialization */ +int domx_init(domx_t *dt, dataobject_t *dodesc); +int domx_set_be(domx_t *dt, void *be, const char *key); +int domx_set_cache(domx_t *dt, size_t size); +int domx_set_sxmpchannel(domx_t *dt, const char *instance, int typeid, int access); + +/* data operations */ +int domx_get(domx_t *dt, uint64_t oid, void **refdata); +int domx_set(domx_t *dt, uint64_t oid, const void *refdata); +int domx_remove(domx_t *dt, uint64_t oid); +int domx_creat(domx_t *dt, uint64_t *oid, const void *refdata); + +/* cache ops for backends */ +int domx_cache_invalidate(domx_t *dt, uint64_t oid); +int domx_cache_invalidate_list(domx_t *dt, list_head_t *oids); +int domx_cache_getdirtylist(domx_t *dt, uint16_t amount, list_head_t **list); +int domx_cache_freelist(domx_t *dt, list_head_t *list); +int domx_cache_freeitems(domx_t *dt, uint16_t amount); + +/* data filters */ +typedef enum { + YDEQUAL = 0, + YDNOTEQUAL, + YDGREATER, + YDLESS, + YDEQOGREATER, + YDEQOLESS, + YDINRANGE, + YDINLIST, +} filt_t; + +typedef struct __yd_inlist_item_type { + union { + uint64_t val; + char *dta; + }; + list_node_t node; +}__attribute__((packed)) yd_inlist_item_t; + +typedef struct __yd_filter_item_type { + char *name; /* dataobject item name ptr */ + filt_t ftype; /* filtering type */ + union { + struct { + uint64_t vf; /* first value */ + uint64_t vc; /* second value if applicable */ + }; + struct { + char *cstr; + list_head_t *inlist; + }; + }; + list_node_t node; +}__attribute__((packed)) yd_filter_item_t; + +typedef struct __yd_filter_type { + domx_t *domx; + list_head_t filter; +} yd_filter_t; + +yd_filter_t *yd_filter_create(domx_t *refobj); +void yd_filter_destroy(yd_filter_t *f); +int yd_filter_add_sf(yd_filter_t *f, const char *name, filt_t ftype, + uint64_t vf, uint64_t vc); +int yd_filter_add_str(yd_filter_t *f, const char *name, const char *value, int eq); +int yd_filter_add_inlist(yd_filter_t *f, const char *name, int length, void **array); + +#define YD_CHUNK_AMOUNT 128 + +typedef struct __yd_wlist_node_type { + oid_t oid; + list_node_t node; +} yd_wlist_node_t; + +typedef struct __yd_index_stream_type { + yd_filter_t *filter; + uint32_t offset; + uint8_t amount; + list_head_t entries_wlist; + void *priv; +} yd_idx_stream_t; + +#define yd_index_stream_setfilter(sw, filt) (sw)->filter = (filt) +#define yd_index_stream_setpriv(sw, prv) (sw)->priv = prv +#define yd_index_stream_getpriv(sw) (sw)->priv + +yd_idx_stream_t *yd_index_stream_init(void); +void yd_index_stream_destroy(yd_idx_stream_t *); +void yd_index_stream_emptylist(yd_idx_stream_t *); + +typedef struct __yd_index_stream_window_type { + uint8_t amount; + list_head_t *wlist; +} yd_idx_stream_win_t; + +#define yd_idx_stream_win_size(sw) (sw)->amount + +/* domx stream operations */ +yd_idx_stream_t *domx_idxl_open(domx_t *dt, ydm_access_filter_t afilter, + dataacc_pemctx_t *dacc, yd_filter_t *datafilter); + +void domx_idxl_close(domx_t *dt, yd_idx_stream_t *idxl); + +yd_idx_stream_win_t *domx_idxl_read(domx_t *dt, yd_idx_stream_t *idxl); + +struct be_ops; + +#define BEMAGIC 0xffffbeef + +typedef struct __domx_dsbe_type { + domx_t *domx; + void *priv; + struct be_ops *f; +} domx_dsbe_t; + +struct be_ops { + uint32_t be_magic; + /* initialization part */ + int (*init)(domx_dsbe_t *, const char *); + /* data manipulation */ + int (*get)(domx_dsbe_t *, oid_t, void *); + int (*set)(domx_dsbe_t *, oid_t, void *); + oid_t (*creat)(domx_dsbe_t *, const void *); + int (*remove)(domx_dsbe_t *, oid_t); + /* list requesting */ + yd_idx_stream_t* (*create_idx_stream)(domx_dsbe_t *, ydm_access_filter_t, + dataacc_pemctx_t *, yd_filter_t *); + void (*destroy_idx_stream)(yd_idx_stream_t *); + yd_idx_stream_win_t* (*getportion_idx_stream)(yd_idx_stream_t *); +}; + +#endif /* __YD_DATAOBJECT_H__ */ diff --git a/ydaemon/Makefile.am b/ydaemon/Makefile.am index f0d38a9..87b22b6 100644 --- a/ydaemon/Makefile.am +++ b/ydaemon/Makefile.am @@ -15,7 +15,8 @@ lib_LTLIBRARIES = libydaemon.la libydaemon_la_SOURCES = \ values.c functions.c log.c module.c \ - daemon.c context.c + daemon.c context.c data.c cache.c \ + domx.c filter.c idxstream.c libydaemon_la_LDFLAGS = -Wl,--export-dynamic diff --git a/ydaemon/cache.c b/ydaemon/cache.c new file mode 100644 index 0000000..fc931a4 --- /dev/null +++ b/ydaemon/cache.c @@ -0,0 +1,465 @@ +/* + * 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 +#include + +#include +#include + +static long __cmp_oids(const void *a, const void *b) +{ + return (long)(*(oid_t *)a - *(oid_t *)b); +} + +static ydata_cache_item_t *__alloc_ydcitem(uint32_t idx) +{ + ydata_cache_item_t *out = malloc(sizeof(ydata_cache_item_t)); + + if(out) { + memset(out, 0, sizeof(ydata_cache_item_t)); + out->idx = idx; + out->attr |= YDC_UNUSED; + list_init_node(&out->listnode); + usrtc_node_init(&out->idxnode, out); + } + + return out; +} + +static void *__sync_thread(void *p); + +int yd_cache_start_thread(domx_t *domx) +{ + ydata_cache_t *cc; + + if(!domx || !(cc = (ydata_cache_t *)domx->cache)) return EINVAL; + + return pthread_create(&cc->syncthread, NULL, __sync_thread, (void *)domx); +} + +static void *__sync_thread(void *p) +{ + domx_t *domx = (domx_t *)p; + ydata_cache_t *cc; + domx_dsbe_t *be; + list_node_t *iter, *siter; + ydata_cache_item_t *citem; + struct timespec tio; + int r, c, o; + + /* check up, we shouldn't falls to segmentation */ + if(!p || !(cc = (ydata_cache_t *)domx->cache)) goto __fini; + if(!(be = domx->be)) goto __fini; + + /* everyday life is here */ + while(1) { + /* get our tio, yes it's not so green ... but it works */ + tio.tv_sec = time(NULL) + YDC_SYNCDELTASEC; + /* lock on mutex for a time being or will wake up on request */ + r = pthread_mutex_timedlock(&cc->dirtlock, &tio); + + __retrywolock: + yd_cache_rdlock(cc); + if(!cc->dirties) { + yd_cache_unlock(cc); + goto __again; + } + yd_cache_unlock(cc); + + yd_cache_wrlock(cc); + c = 0; + list_for_each_safe(&cc->dirty_poll, iter, siter) { + citem = container_of(iter, ydata_cache_item_t, listnode); + list_del(&citem->listnode); + + if(citem->attr & YDC_INVALIDATE) { /* invalidated item, just pullback it */ + citem->attr = 0; + citem->attr |= YDC_UNUSED; + list_add2tail(&cc->free_poll, &citem->listnode); + usrtc_delete(&cc->idx_tree, &citem->idxnode); + } else { + o = be->f->set(be, citem->oid, yd_cache_ptrbyidx(cc, citem->idx)); + if(o != 0) { /* invalidate */ + citem->attr = 0; + citem->attr |= YDC_UNUSED; + list_add2tail(&cc->free_poll, &citem->listnode); + usrtc_delete(&cc->idx_tree, &citem->idxnode); + } else citem->attr &= ~YDC_DIRTY; /* just remove this flag */ + } + cc->dirties--; + c++; + if(c >= YDC_SYNCTHRESHOLD) break; + } + yd_cache_unlock(cc); + + if(c >= YDC_SYNCTHRESHOLD) { + usleep(100); /* looks like a huge load, let's wait and retry without lock */ + goto __retrywolock; + } + + __again: + if(r != ETIMEDOUT) pthread_mutex_lock(&cc->dirtlock); /* acquire lock again */ + } + + __fini: + return NULL; +} + +ydata_cache_t *yd_cache_init(dataobject_t *object, size_t cache_size) +{ + ydata_cache_t *cache = NULL; + char *iter; + ydata_cache_item_t *zcitem; + list_node_t *it, *sit; + int r = 0; + size_t i; + + if(!object || !cache_size) { + errno = EINVAL; + goto __fail; + } + + /* allocate and zero structure */ + if(!(cache = malloc(sizeof(ydata_cache_t)))) { + errno = ENOMEM; + goto __fail; + } else memset(cache, 0, sizeof(ydata_cache_t)); + + /* map a memory buffer */ + cache->cache = mmap(NULL, cache_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if(cache->cache == MAP_FAILED) { + errno = ENOMEM; + goto __fail; + } + + /* allocate all the locks */ + if((r = pthread_rwlock_init(&cache->rwlock, NULL))) { + errno = r; + goto __fail; + } + if((r = pthread_mutex_init(&cache->dirtlock, NULL))) { + pthread_rwlock_destroy(&cache->rwlock); + errno = r; + goto __fail; + } + + /* init other values */ + cache->cache_size = cache_size; + cache->object_size = dtolen(object); + + /* some paranoic check up */ + if(!cache->object_size) { + pthread_rwlock_destroy(&cache->rwlock); + pthread_mutex_destroy(&cache->dirtlock); + errno = EINVAL; + goto __fail; + } + /* well, able to continue ... */ + cache->objects_amount = cache->cache_size/(cache->object_size + sizeof(uint32_t)); + + /* init structures */ + usrtc_init(&cache->idx_tree, USRTC_SPLAY, cache->objects_amount, __cmp_oids); /* indexing one */ + list_init_head(&cache->free_poll); + list_init_head(&cache->dirty_poll); + list_init_head(&cache->pending_poll); + + /* mark i.e. format our memory buffer, also it will populate the pages */ + for(i = 0, iter = (char *)cache->cache; i < cache->objects_amount; + i++, iter += cache->object_size + sizeof(uint32_t)) { + /* mark with spacer */ + *(uint32_t *)iter = YD_CACHE_SPACER_MAGIC; + zcitem = __alloc_ydcitem(i); + if(!zcitem) { errno = ENOMEM; goto __failall; } + + list_add2tail(&cache->free_poll, &zcitem->listnode); + } + + /* lock the mutex */ + pthread_mutex_lock(&cache->dirtlock); + + return cache; + + __failall: + pthread_rwlock_destroy(&cache->rwlock); + pthread_mutex_destroy(&cache->dirtlock); + + __fail: + /* failcase freeing */ + if(cache) { + /* memory buffer */ + if(cache->cache != MAP_FAILED || cache->cache != NULL) { + /* if we have a buffer, we might have some items already allocated ... */ + list_for_each_safe(&cache->free_poll, it, sit) { + zcitem = container_of(it, ydata_cache_item_t, listnode); + list_del(&zcitem->listnode); + free(zcitem); + } + + munmap(cache->cache, cache_size); + } + + free(cache); + } + + return NULL; /* sadly ... */ +} + +/* allocating is quite simple: + * we're trying to get a free item, if it + * exists, we're moving this the the pending poll, + * otherwise return nil. + */ +void *yd_cache_alloc_item(ydata_cache_t *cache, ydata_cache_item_t **item) +{ + char *data = NULL; + list_node_t *listnode; + ydata_cache_item_t *zcitem; + + yd_cache_rdlock(cache); + listnode = list_node_first(&cache->free_poll); + if(listnode) { + yd_cache_unlock(cache); /* retake locks */ + yd_cache_wrlock(cache); + zcitem = container_of(listnode, ydata_cache_item_t, listnode); + list_del(&zcitem->listnode); /* delete from free poll */ + list_add2tail(&cache->pending_poll, &zcitem->listnode); /* add to the pending poll */ + /* do the magic */ + data = yd_cache_ptrbyidx(cache, zcitem->idx); + /* mark it invalidate - since we don't know what will be in future */ + zcitem->attr |= YDC_INVALIDATE; + *item = zcitem; + } + yd_cache_unlock(cache); + + /* ok. we'll do some automagically check for the near items safety */ + if(data && *(uint32_t *)data != YD_CACHE_SPACER_MAGIC ) { /* currupted - mark near elements invalidated ! */ + /* TODO: do it */ + } + + if(data) { + data += sizeof(uint32_t); /* bypass magic spacer */ + + return (void *)data; + } + + return NULL; +} + +void yd_cache_discard_alloc_item(ydata_cache_t *cache, ydata_cache_item_t *item) +{ + if(!(item->attr & YDC_INVALIDATE)) return; /* some shit happens */ + + yd_cache_wrlock(cache); + list_del(&item->listnode); /* delete from panding poll - guess, u can use API ugly and dirty */ + list_add2tail(&cache->free_poll, &item->listnode); /* add to the pending poll */ + item->attr &= ~YDC_INVALIDATE; /* clear the invalidate bit */ + yd_cache_unlock(cache); + + return; +} + +void yd_cache_confirm_alloc_item(ydata_cache_t *cache, ydata_cache_item_t *item, oid_t oid) +{ + if(!(item->attr & YDC_INVALIDATE)) return; /* some shit happens */ + + yd_cache_wrlock(cache); + list_del(&item->listnode); /* delete from pending poll - guess, u can use API ugly and dirty */ + item->attr &= ~YDC_INVALIDATE; /* clear the invalidate bit */ + item->attr &= ~YDC_UNUSED; /* clear the use bit */ + yd_item_setoid(item, oid); + usrtc_insert(&cache->idx_tree, &item->idxnode, (void *)&item->oid); /* now it will be in the splay tree of the active cached data */ + yd_cache_unlock(cache); + + return; +} + +void *yd_cache_lookup(ydata_cache_t *cache, oid_t oid) +{ + usrtc_node_t *node; + ydata_cache_item_t *item; + void *ret = NULL; + + yd_cache_rdlock(cache); + node = usrtc_lookup(&cache->idx_tree, &oid); + if(node) { + item = (ydata_cache_item_t *)usrtc_node_getdata(node); + if(!(item->attr & YDC_INVALIDATE)) ret = yd_cache_ptrbyidx(cache, yd_item_idx(item)); + else if(item->attr & YDC_INVALIDATE) { /* invalidated item */ + yd_cache_unlock(cache); /* retake lock */ + yd_cache_wrlock(cache); + usrtc_delete(&cache->idx_tree, &item->idxnode); + if(item->attr & YDC_DIRTY) { list_del(&item->listnode); /* it was dirty - but invalidated, remove it */ + cache->dirties--; + } + item->attr = 0; /* clear attributes */ + item->attr |= YDC_UNUSED; + list_add2tail(&cache->free_poll, &item->listnode); + ret = NULL; + } + } + yd_cache_unlock(cache); + + if(ret && *(uint32_t *)ret != YD_CACHE_SPACER_MAGIC ) { /* currupted - mark near elements invalidated ! */ + /* TODO: do it */ + } + + if(ret) ret += sizeof(uint32_t); + + return ret; +} + +static inline ydata_qitem_t *__quickitem_alloc(ydata_cache_item_t *zitem) +{ + ydata_qitem_t *itm = malloc(sizeof(ydata_qitem_t)); + + if(itm) { + list_init_node(&itm->node); + itm->item = zitem; + } + + return itm; +} + +list_head_t *yd_cache_getrslist(ydata_cache_t *cache, uint8_t amount) +{ + list_head_t *head = malloc(sizeof(list_head_t)); + usrtc_node_t *node; + list_node_t *_i, *_si; + ydata_qitem_t *itm; + ydata_cache_item_t *zitem; + int i; + + if(!head) return NULL; + if(!cache || !amount) goto __failcase; /* little bit of paranoic check */ + + yd_cache_wrlock(cache); + for(i = 0, node = usrtc_last(&cache->idx_tree); + i < amount; + i++, node = usrtc_last(&cache->idx_tree)) { + if(!node) break; /* pfff */ + zitem = (ydata_cache_item_t *)usrtc_node_getdata(node); + /* create an quick entry */ + if(!(itm = __quickitem_alloc(zitem))) goto __failcase_hasent; + + /* delete from the index tree */ + usrtc_delete(&cache->idx_tree, &zitem->idxnode); + list_add2tail(head, &itm->node); + } + yd_cache_unlock(cache); + + return head; + + __failcase_hasent: + if(head) { + list_for_each_safe(head, _i, _si) { + itm = container_of(_i, ydata_qitem_t, node); + zitem = itm->item; + if(zitem->attr & YDC_INVALIDATE) { /* oops, invalidated item found ! */ + if(zitem->attr & YDC_DIRTY) { + list_del(&zitem->listnode); + cache->dirties--; + } + list_add2tail(&cache->free_poll, &zitem->listnode); + zitem->attr = 0; + zitem->attr |= YDC_UNUSED; + } else /* return back */ + usrtc_insert(&cache->idx_tree, &zitem->idxnode, (void *)&zitem->oid); + + list_del(&itm->node); + free(itm); + } + yd_cache_unlock(cache); + } + + __failcase: + if(head) free(head); + return NULL; +} + +void yd_cache_qitems_pullback(ydata_cache_t *cache, list_head_t *list) +{ + list_node_t *iter, *siter; + ydata_qitem_t *itm; + ydata_cache_item_t *zitem; + + yd_cache_wrlock(cache); + list_for_each_safe(list, iter, siter) { + itm = container_of(iter, ydata_qitem_t, node); + zitem = itm->item; + if(zitem->attr & YDC_DIRTY) { + list_del(&zitem->listnode); + cache->dirties--; + } + zitem->attr = 0; /* reset flags */ + zitem->attr |= YDC_UNUSED; + list_add2tail(&cache->free_poll, &zitem->listnode); + + /* free it at all */ + list_del(&itm->node); + free(itm); + } + yd_cache_unlock(cache); + + free(list); + + return; +} + +void yd_cache_item_dirtyoid(ydata_cache_t *cache, oid_t oid) +{ + usrtc_node_t *node; + ydata_cache_item_t *zitem; + + yd_cache_wrlock(cache); + node = usrtc_lookup(&cache->idx_tree, &oid); + if(node) { + zitem = (ydata_cache_item_t *)usrtc_node_getdata(node); + if(!(zitem->attr & YDC_DIRTY)) { + list_add2tail(&cache->dirty_poll, &zitem->listnode); + zitem->attr |= YDC_DIRTY; + cache->dirties++; + /* schedule sync thread, since threshold of dirty items occured */ + if(cache->dirties >= YDC_SYNCTHRESHOLD) pthread_mutex_unlock(&cache->dirtlock); + } + } + yd_cache_unlock(cache); + + return; +} + +void yd_cache_item_invalidateoid(ydata_cache_t *cache, oid_t oid) +{ + usrtc_node_t *node; + ydata_cache_item_t *zitem; + + yd_cache_wrlock(cache); + node = usrtc_lookup(&cache->idx_tree, &oid); + if(node) { + zitem = (ydata_cache_item_t *)usrtc_node_getdata(node); + if(!(zitem->attr & YDC_INVALIDATE)) zitem->attr |= YDC_INVALIDATE; + } + yd_cache_unlock(cache); + + return; +} diff --git a/ydaemon/data.c b/ydaemon/data.c new file mode 100644 index 0000000..6ec5efd --- /dev/null +++ b/ydaemon/data.c @@ -0,0 +1,226 @@ +/* + * 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 + +static long __cmp_uint8(const void *a, const void *b) +{ + return *(uint8_t *)a - *(uint8_t *)b; +} + +static long __cmp_cstr(const void *a, const void *b) +{ + return strcmp((const char *)a, (const char *)b); +} + +dataobject_t *dotr_create(const char *name) +{ + dataobject_t *dtr = malloc(sizeof(dataobject_t)); + + if(!dtr) return NULL; + else memset(dtr, 0, sizeof(dataobject_t)); + + /* init name, indexes etc ... */ + strncpy(dtr->name, name, MAX_ITEM_NAME - sizeof(char)); + + list_init_head(&dtr->description); + usrtc_init(&dtr->id_index, USRTC_REDBLACK, MAX_ITEMS, __cmp_uint8); + usrtc_init(&dtr->name_index, USRTC_REDBLACK, MAX_ITEMS, __cmp_cstr); + + return dtr; +} + +int dotr_set_item(dataobject_t *dotr, uint8_t type, uint64_t len, + const char *name) +{ + dataobject_item_t *ditem = malloc(sizeof(dataobject_item_t)); + char *indexes = malloc(2*sizeof(item_idx_t)); + item_idx_t *iidx, *nidx; + + if(!ditem || !indexes) { + if(ditem) free(ditem); + if(indexes) free(indexes); + return ENOMEM; + } else { + iidx = (item_idx_t *)indexes; + nidx = (item_idx_t *)(indexes + sizeof(item_idx_t)); + } + + /* init items */ + strncpy(ditem->name, name, MAX_ITEM_NAME - sizeof(char)); + ditem->id = usrtc_count(&dotr->id_index); + ditem->type = type; + ditem->len = len; + list_init_node(&ditem->node); + + iidx->key = &ditem->id; + iidx->dtr = ditem; + usrtc_node_init(&iidx->node, iidx); + + nidx->key = ditem->name; + nidx->dtr = ditem; + usrtc_node_init(&nidx->node, nidx); + + /* now insert all */ + list_add2tail(&dotr->description, &ditem->node); + usrtc_insert(&dotr->id_index, &iidx->node, iidx->key); + usrtc_insert(&dotr->name_index, &nidx->node, nidx->key); + + return 0; +} + +void dotr_destroy(dataobject_t *dotr) +{ + usrtc_t *tree = &dotr->id_index; + usrtc_node_t *node = NULL; + item_idx_t *idx; + list_node_t *iter, *save; + dataobject_item_t *ditem; + + if(usrtc_count(tree)) { /* we can free only index, since it was allocated as one memory chunk */ + for(node = usrtc_first(tree); node != NULL; node = usrtc_first(tree)) { + idx = (item_idx_t *)usrtc_node_getdata(node); + usrtc_delete(tree, node); + free(idx); + } + + /* free description */ + list_for_each_safe(&dotr->description, iter, save) { + ditem = container_of(iter, dataobject_item_t, node); + list_del(&ditem->node); + free(ditem); + } + } + + free(dotr); + + return; +} + +uint8_t dotr_item_type(dataobject_t *obj, const char *name, uint64_t *len) +{ + usrtc_node_t *node = usrtc_lookup(&obj->name_index, name); + item_idx_t *idxnode; + dataobject_item_t *dtr = NULL; + + if(!node) { /* not found ! */ + __failed: + *len = 0; + return 0; + } + + idxnode = (item_idx_t *)usrtc_node_getdata(node); + if(!idxnode) goto __failed; + else dtr = idxnode->dtr; + + if(!dtr) goto __failed; + + *len = dtr->len; + return dtr->type; +} + +char *dotr_item_nameptr(dataobject_t *obj, const char *name) +{ + usrtc_node_t *node = usrtc_lookup(&obj->name_index, name); + item_idx_t *idxnode; + dataobject_item_t *dtr = NULL; + + if(!node) /* not found ! */ return NULL; + + idxnode = (item_idx_t *)usrtc_node_getdata(node); + if(!idxnode) return NULL; + else dtr = idxnode->dtr; + + if(!dtr) return NULL; + + return dtr->name; +} + +int dotr_item_nameidx(dataobject_t *obj, const char *name) +{ + usrtc_node_t *node = usrtc_lookup(&obj->name_index, name); + item_idx_t *idxnode; + dataobject_item_t *dtr = NULL; + + if(!node) /* not found ! */ return -1; + + idxnode = (item_idx_t *)usrtc_node_getdata(node); + if(!idxnode) return -1; + else dtr = idxnode->dtr; + + if(!dtr) return -1; + + return dtr->id; +} + +static inline int __itemcmp(const dataobject_item_t *s1, + const dataobject_item_t *s2) +{ + int r = 0; + if((r = strcmp(s1->name, s2->name))) return r; + if((r = s1->len - s2->len)) return r; + if((r = s1->type - s2->type)) return r; + + return 0; +} + +int dtocmp(const dataobject_t *src, const dataobject_t *dst) +{ + int r = 0; + list_node_t *iter, *siter; + dataobject_item_t *ditem, *sitem; + usrtc_node_t *unode; + item_idx_t *iidx; + + /* check name */ + if((r = strcmp(src->name, dst->name))) return r; + /* check amount of items */ + if((r = usrtc_count((usrtc_t *)&src->id_index) - usrtc_count((usrtc_t *)&dst->id_index))) + return r; + + /* check items itself */ + list_for_each_safe(&src->description, iter, siter) { + ditem = container_of(iter, dataobject_item_t, node); + if(!(unode = usrtc_lookup((usrtc_t *)&dst->id_index, (const void *)&ditem->id))) + return 100*ditem->id; + + iidx = (item_idx_t *)usrtc_node_getdata(unode); + sitem = iidx->dtr; + + if((r = __itemcmp(ditem, sitem))) return r*ditem->id; + } + + return 0; +} + +size_t dtolen(const dataobject_t *src) +{ + size_t len = 0; + list_node_t *iter, *siter; + dataobject_item_t *ditem; + + list_for_each_safe(&src->description, iter, siter) { + ditem = container_of(iter, dataobject_item_t, node); + len += ditem->len; + } + + return len; +} diff --git a/ydaemon/domx.c b/ydaemon/domx.c new file mode 100644 index 0000000..4b654b1 --- /dev/null +++ b/ydaemon/domx.c @@ -0,0 +1,249 @@ +/* + * 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); +} + diff --git a/ydaemon/filter.c b/ydaemon/filter.c new file mode 100644 index 0000000..fef27a0 --- /dev/null +++ b/ydaemon/filter.c @@ -0,0 +1,219 @@ +/* + * 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 ."; + * + */ + +#define DMUX_USE 1 +#include + +yd_filter_t *yd_filter_create(domx_t *refobj) +{ + yd_filter_t *f = malloc(sizeof(yd_filter_t)); + + if(f) { + f->domx = refobj; + list_init_head(&f->filter); + } + + return f; +} + +void yd_filter_destroy(yd_filter_t *f) +{ + list_head_t *lhead; + list_node_t *iter, *siter, *liter, *lsiter; + yd_filter_item_t *filter_item; + yd_inlist_item_t *inl_item; + dataobject_t *obj; + uint64_t len; + uint8_t type; + + if(!f) return; + else { + lhead = &f->filter; + obj = f->domx->dox; + } + + list_for_each_safe(lhead, iter, siter) { + filter_item = container_of(iter, yd_filter_item_t, node); + type = dotr_item_type(obj, filter_item->name, &len); + if(type && len) { + switch(filter_item->ftype) { + case YDEQUAL: + case YDNOTEQUAL: + if(type == CSTR || type == TBLOB) free(filter_item->cstr); + break; + case YDINLIST: + /* we must destroy the list */ + list_for_each_safe(filter_item->inlist, liter, lsiter) { + inl_item = container_of(liter, yd_inlist_item_t, node); + if(type == CSTR || type == TBLOB) free(inl_item->dta); + list_del(&inl_item->node); + free(inl_item); + } + free(filter_item->inlist); + break; + default: break; /* nothing to do */ + } + } + + /* free struct itself */ + list_del(&filter_item->node); + free(filter_item); + } + + free(f); + + return; +} + +static yd_filter_item_t *__alloc_init_fitem(filt_t ftype, char *name) +{ + yd_filter_item_t *fitem = NULL; + + if(name && (fitem = malloc(sizeof(yd_filter_item_t)))) { + memset(fitem, 0, sizeof(yd_filter_item_t)); + fitem->name = name; + fitem->ftype = ftype; + list_init_node(&fitem->node); + } + + return fitem; +} + +int yd_filter_add_sf(yd_filter_t *f, const char *name, filt_t ftype, + uint64_t vf, uint64_t vc) +{ + yd_filter_item_t *fitem; + dataobject_t *obj; + uint64_t len; + uint8_t type; + + if(!f || !name) return EINVAL; + + /* lookup for existing entry and check it */ + obj = f->domx->dox; + type = dotr_item_type(obj, name, &len); + if(!type && !len) return EINVAL; + + /* check validity */ + if((type < CSTR) && (len > tltable[type].len)) return EINVAL; /* we cannot filter by array here */ + if(type > S64) return EINVAL; /* we're adding a simple filter rule */ + if(ftype == YDINLIST) return EINVAL; /* we're not working with that in this function */ + + fitem = __alloc_init_fitem(ftype, dotr_item_nameptr(obj, name)); + if(!fitem) return ENOMEM; + + fitem->vf = vf; + if(ftype == YDINLIST) fitem->vc = vc; + + /* add this entry */ + list_add2tail(&f->filter, &fitem->node); + + return 0; +} + +int yd_filter_add_str(yd_filter_t *f, const char *name, const char *value, int eq) +{ + yd_filter_item_t *fitem; + dataobject_t *obj; + filt_t ftype; + uint64_t len; + uint8_t type; + + if(!f || !name) return EINVAL; + + /* lookup for existing entry and check it */ + obj = f->domx->dox; + type = dotr_item_type(obj, name, &len); + if(!type && !len) return EINVAL; + + if(type != CSTR) return EINVAL; /* cannot do it, invalid */ + + if(!eq) ftype = YDNOTEQUAL; + else ftype = YDEQUAL; + + fitem = __alloc_init_fitem(ftype, dotr_item_nameptr(obj, name)); + if(!fitem) return ENOMEM; + + if(!(fitem->cstr = strndup(value, len - sizeof(char)))) { + free(fitem); + return ENOMEM; + } + + /* add this entry */ + list_add2tail(&f->filter, &fitem->node); + + return 0; +} + +int yd_filter_add_inlist(yd_filter_t *f, const char *name, int length, void **array) +{ + yd_filter_item_t *fitem; + yd_inlist_item_t *list_item; + dataobject_t *obj; + list_node_t *iter, *siter; + uint64_t len; + int i; + uint8_t type; + + if(!f || !name) return EINVAL; + if(!length || !array) return EINVAL; + + /* lookup for existing entry and check it */ + obj = f->domx->dox; + type = dotr_item_type(obj, name, &len); + if(!type && !len) return EINVAL; + + fitem = __alloc_init_fitem(YDINLIST, dotr_item_nameptr(obj, name)); + if(!fitem) return ENOMEM; + + if(!(fitem->inlist = malloc(sizeof(list_head_t)))) { + __enomem: + free(fitem); + return ENOMEM; + } + + /* fill the list */ + for(i = 0; i < length; i++) { + if(!(list_item = malloc(sizeof(yd_inlist_item_t)))) { + __deep_enomem: + list_for_each_safe(fitem->inlist, iter, siter) { + list_item = container_of(iter, yd_inlist_item_t, node); + if(type == CSTR || type == TBLOB) free(list_item->dta); + list_del(&list_item->node); + free(list_item); + } + /* free the list */ + free(fitem->inlist); + goto __enomem; + } + if(type < CSTR) list_item->val = *(uint64_t *)array[i]; + else if(!(list_item->dta = strndup((const char *)array[i], len - sizeof(char)))) goto __deep_enomem; + + list_init_node(&list_item->node); + list_add2tail(fitem->inlist, &list_item->node); + } + + /* add this entry */ + list_add2tail(&f->filter, &fitem->node); + + return 0; +} + diff --git a/ydaemon/idxstream.c b/ydaemon/idxstream.c new file mode 100644 index 0000000..9986620 --- /dev/null +++ b/ydaemon/idxstream.c @@ -0,0 +1,67 @@ +/* + * 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 + +yd_idx_stream_t *yd_index_stream_init(void) +{ + yd_idx_stream_t *is = malloc(sizeof(yd_idx_stream_t)); + + if(!is) return NULL; + else memset(is, 0, sizeof(yd_idx_stream_t)); + + list_init_head(&is->entries_wlist); + + return is; +} + +static inline void __empty_list(list_head_t *list) +{ + list_node_t *iter, *siter; + yd_wlist_node_t *wlistnode; + + list_for_each_safe(list, iter, siter){ + wlistnode = container_of(iter, yd_wlist_node_t, node); + list_del(&wlistnode->node); + free(wlistnode); + } + + return; +} + +void yd_index_stream_destroy(yd_idx_stream_t *is) +{ + if(!is) return; + else __empty_list(&is->entries_wlist); + + free(is); + + return; +} + +void yd_index_stream_emptylist(yd_idx_stream_t *is) +{ + if(!is) return; + else __empty_list(&is->entries_wlist); + + return; +} +