[core] added ydaemon data manipulation stuff;
parent
77d0ee4a0b
commit
23b19029f4
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.";
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YDATA_CACHE_H__
|
||||||
|
#define __YDATA_CACHE_H__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#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__ */
|
@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.";
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DM_DATAOBJECT_H__
|
||||||
|
#define __DM_DATAOBJECT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <tdata/usrtc.h>
|
||||||
|
#include <tdata/list.h>
|
||||||
|
|
||||||
|
#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__ */
|
@ -0,0 +1,465 @@
|
|||||||
|
/*
|
||||||
|
* 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 <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <ydaemon/dataobject.h>
|
||||||
|
#include <ydaemon/cache.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.";
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DMUX_USE 1
|
||||||
|
#include <ydaemon/dataobject.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue