diff --git a/src/controller/apiserver.c b/src/controller/apiserver.c index 058cfffd..fbba0bd2 100644 --- a/src/controller/apiserver.c +++ b/src/controller/apiserver.c @@ -6,6 +6,7 @@ #include "objmgr.h" #include "request.h" #include "xce/types.h" +#include "xstring.h" static int xce_apiserver_push_configs(cluster_t* c, endpoint_t* ep) { @@ -603,9 +604,8 @@ int add_apiserver(cluster_t* c, char* name, endpoint_t* ep) for (i = 0; i < N_APISERVER_MAX; i++) { if (c->apiservers[i].name == NULL) { - c->apiservers[i].name - = create_obj_by_typename(&(c->objmgr), "xstring", name); - c->apiservers[i].ep = ep; + c->apiservers[i].name = makeString(name); + c->apiservers[i].ep = ep; return i; } } diff --git a/src/controller/cluster.c b/src/controller/cluster.c index 0e0b15c4..0749c883 100644 --- a/src/controller/cluster.c +++ b/src/controller/cluster.c @@ -514,6 +514,8 @@ int cluster_init(cluster_t* c) iomgr_set_ssl_ctx(&(c->iomgr), ssl_ctx); + xstring_table_init(c->myconf->cluster_config->xstrings->nhash_slots); + register_xstring(&(c->objmgr), c->myconf->cluster_config->xstrings->nhash_slots, c->myconf->cluster_config->xstrings->delta); @@ -583,7 +585,7 @@ static int check_worker_timeout_(void* arg1, void* arg2) if (w1 == NULL) { return -EINVAL; } - + config = c->myconf->cluster_config; timeout = config->heartbeat_interval * config->inactive_heartbeat_count; @@ -712,5 +714,7 @@ void cluster_fini(cluster_t* c) cleanup_openssl(); + xstring_table_fini(); + return; } diff --git a/src/controller/meson.build b/src/controller/meson.build index ebcd21a2..f625c6ad 100644 --- a/src/controller/meson.build +++ b/src/controller/meson.build @@ -27,6 +27,7 @@ incdir = include_directories('.', '../include', '../lib', controller_deps = [ libxce_dep, + librtti_dep, c_capnproto_dep, math_dep, tinylog_dep, @@ -48,6 +49,7 @@ history_dep = dependency('history') xce_test_deps = [ libxce_dep, + librtti_dep, struct2json_dep, readline_dep, history_dep, diff --git a/src/flake.lock b/src/flake.lock index 0d915305..b575d1af 100644 --- a/src/flake.lock +++ b/src/flake.lock @@ -117,11 +117,11 @@ "xbuild": "xbuild" }, "locked": { - "lastModified": 1770966016, - "narHash": "sha256-HZEy2nuM2g8anxKidaxv5hbDlV1+4yk18Dzre8fSAHE=", + "lastModified": 1771035982, + "narHash": "sha256-SC9T1ltnamOCJuWbWeFKjwAG+XauLr1VAoJvzevH2nw=", "ref": "master", - "rev": "e5f39839522dcfa7a66dc09a177ba89034659580", - "revCount": 10, + "rev": "c1e40697060a4f689ff9ee70e830eb93a09fa145", + "revCount": 11, "type": "git", "url": "ssh://forgejo@gitea.shenrs.eu/rshen/librtti" }, diff --git a/src/include/xstring.h b/src/include/xstring.h index 58bb42e7..c46881c2 100644 --- a/src/include/xstring.h +++ b/src/include/xstring.h @@ -2,6 +2,8 @@ #define __XSTRING_H__ 1 +#include + #include "objmgr.h" typedef struct { @@ -21,4 +23,8 @@ typedef struct { extern int register_xstring(objmgr_t*, int, int); +extern int xstring_table_init(int); +extern void xstring_table_fini(); +extern char* makeString(char*); + #endif diff --git a/src/lib/testsuite/test_xstring.c b/src/lib/testsuite/test_xstring.c index 57c07f27..25e378d8 100644 --- a/src/lib/testsuite/test_xstring.c +++ b/src/lib/testsuite/test_xstring.c @@ -4,122 +4,77 @@ #include #include "objmgr.h" +#include "utils.h" #include "xstring.h" -void test_xstring_create(void) +static void test_xstring_create(void) { - objmgr_t mgr; - char* s1 = "Hello,world"; - char* s2 = NULL; - int rc = 0; - myobj_t* obj; + char* s = "Hello, world"; + char* d = NULL; + int rc; - objmgr_init(&mgr); - register_xstring(&mgr, 4, 4); - TEST_ASSERT_EQUAL(1, mgr.types.count); + rc = xstring_table_init(139); + TEST_ASSERT_TRUE(rc >= 0); - s2 = create_obj_by_typename(&mgr, "xstring", s1); - TEST_ASSERT_NOT_NULL(s2); - obj = TO_MYOBJ(s2); - TEST_ASSERT_EQUAL(1, XSTRING_OBJ_TYPE_STRINGS(obj).count); + d = makeString(s); + TEST_ASSERT_TRUE(d != NULL); - rc = strcmp(s1, s2); - TEST_ASSERT_EQUAL(0, rc); + TEST_ASSERT_TRUE(strcmp(d, s) == 0); + TEST_ASSERT_TRUE(length(d) == strlen(s)); + TEST_ASSERT_TRUE(hash(d) == hash_string(s)); - objmgr_fini(&mgr); + xstring_table_fini(); } -void test_xstring_ref(void) +static void test_xstring_share(void) { - objmgr_t mgr; - char* s1 = NULL; - char* s2 = NULL; - myobj_t* obj; + char* s = "Hello, world"; + char* d = NULL; + char* d1 = NULL; + int rc; - objmgr_init(&mgr); - register_xstring(&mgr, 4, 4); - TEST_ASSERT_EQUAL(1, mgr.types.count); + rc = xstring_table_init(139); + TEST_ASSERT_TRUE(rc >= 0); - s1 = create_obj_by_typename(&mgr, "xstring", "Hello,world"); - TEST_ASSERT_NOT_NULL(s1); + d = makeString(s); + TEST_ASSERT_TRUE(d != NULL); - obj = TO_MYOBJ(s1); - TEST_ASSERT_EQUAL(1, XSTRING_OBJ_TYPE_STRINGS(obj).count); + TEST_ASSERT_TRUE(strcmp(d, s) == 0); + TEST_ASSERT_TRUE(length(d) == strlen(s)); + TEST_ASSERT_TRUE(hash(d) == hash_string(s)); - s2 = (char*)obj_ref(s1, OBJREF_READ); - TEST_ASSERT_EQUAL(s1, s2); + d1 = makeString(s); + TEST_ASSERT_TRUE(d1 != NULL); + TEST_ASSERT_TRUE(d == d1); - TEST_ASSERT_EQUAL(2, obj->nref); - objmgr_fini(&mgr); + xstring_table_fini(); } -void test_xstring_deref(void) +static void test_xstring_deref(void) { - objmgr_t mgr; - char* s1 = "Hello,world"; - char* s2 = NULL; - int rc = 0; - myobj_t* obj; + char* s = "Hello, world"; + char* d = NULL; + int rc; - objmgr_init(&mgr); - register_xstring(&mgr, 4, 4); - TEST_ASSERT_EQUAL(1, mgr.types.count); + rc = xstring_table_init(139); + TEST_ASSERT_TRUE(rc >= 0); - s2 = create_obj_by_typename(&mgr, "xstring", s1); - TEST_ASSERT_NOT_NULL(s2); + d = makeString(s); + TEST_ASSERT_TRUE(d != NULL); - rc = strcmp(s1, s2); + TEST_ASSERT_TRUE(strcmp(d, s) == 0); + TEST_ASSERT_TRUE(length(d) == strlen(s)); + TEST_ASSERT_TRUE(hash(d) == hash_string(s)); - TEST_ASSERT_EQUAL(0, rc); - if (rc == 0) { - objtype_t* typeval; + dereference((var)d); - obj = TO_MYOBJ(s2); - typeval = obj->type; - - obj_deref(s2); - - TEST_ASSERT_EQUAL(0, XSTRING_TYPE_STRINGS(typeval).count); - } - - objmgr_fini(&mgr); -} - -void test_xstring_share(void) -{ - objmgr_t mgr; - char* s1 = "Hello,world"; - char* s2 = NULL; - char* s3 = NULL; - int rc = 0; - - objmgr_init(&mgr); - register_xstring(&mgr, 4, 4); - TEST_ASSERT_EQUAL(1, mgr.types.count); - - s2 = create_obj_by_typename(&mgr, "xstring", s1); - TEST_ASSERT_NOT_NULL(s2); - - rc = strcmp(s1, s2); - - TEST_ASSERT_EQUAL(0, rc); - s3 = create_obj_by_typename(&mgr, "xstring", s1); - TEST_ASSERT_EQUAL(s2, s3); - if (1) { - myobj_t* obj; - - obj = TO_MYOBJ(s3); - TEST_ASSERT_EQUAL(2, obj->nref); - } - - objmgr_fini(&mgr); + xstring_table_fini(); } void test_xstrings(void) { printf("\n>> xstring test\n\n"); RUN_TEST(test_xstring_create); - RUN_TEST(test_xstring_ref); RUN_TEST(test_xstring_deref); RUN_TEST(test_xstring_share); diff --git a/src/lib/xstring.c b/src/lib/xstring.c index ad9a91c7..672a26e4 100644 --- a/src/lib/xstring.c +++ b/src/lib/xstring.c @@ -1,9 +1,12 @@ #include +#include #include #include #include #include "htab.h" +#include "kv.h" +#include "mylock.h" #include "utils.h" #include "xstring.h" @@ -139,3 +142,188 @@ static void xstring_type_fini(objtype_t* typeval) ht_fini(&(typedata->tab)); zarray_fini(&(typedata->strings)); } + +static struct { + mylock_t lock; + var xstr_table; +} xstring_table; + +typedef struct { + mylock_t lock; + uint64_t refcount; + uint32_t hashcode; + size_t len; +} xstring_private_t; + +static typeinfo_t xstring_type; +static void xstring_destroy(meta_obj_t*); + +static void my_xstring_killer(var s) +{ + if (s == NULL) { + return; + } + + destroy_(s, (obj_destroy_fn_t)xstring_destroy); +} + +int xstring_table_init(int nslots) +{ + if (nslots <= 1) { + return -EINVAL; + } + + mylock_init(&(xstring_table.lock)); + xstring_table.xstr_table + = makeInstance(&kvtab_string_type, nslots, my_xstring_killer); + + if (xstring_table.xstr_table == NULL) { + return -errno; + } + + return 0; +} + +void xstring_table_fini() +{ + destroy(xstring_table.xstr_table); + mylock_fini(&(xstring_table.lock)); +} + +static size_t xstring_datasize(va_list ap) +{ + char* src = va_arg(ap, char*); + + return strlen(src) + 1; +} + +static int xstring_init(meta_obj_t* obj, va_list ap) +{ + char* src = va_arg(ap, char*); + char* dest = RTTI_OBJ_TO_DATA(char, obj); + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + + if (src == NULL) { + src = ""; + } + + strcpy(dest, src); + + mylock_init(&(priv->lock)); + priv->refcount = 1; + priv->hashcode = hash_string(src); + priv->len = strlen(src); + + return 1; +} + +static void xstring_destroy(meta_obj_t* obj) +{ + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + + mylock_fini(&(priv->lock)); + memset(priv, 0x0, sizeof(*priv)); + + return; +} + +static int xstring_reference(meta_obj_t* obj) +{ + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + + mylock_lock(&(priv->lock)); + priv->refcount++; + mylock_unlock(&(priv->lock)); + + return 0; +} + +static void xstring_dereference(meta_obj_t* obj) +{ + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + char* v = RTTI_OBJ_TO_DATA(char, obj); + uint64_t count; + + mylock_lock(&(priv->lock)); + priv->refcount--; + + count = priv->refcount; + mylock_unlock(&(priv->lock)); + + if (count == 0) { + mylock_lock(&(xstring_table.lock)); + key_del(xstring_table.xstr_table, v); + mylock_unlock(&(xstring_table.lock)); + } + + return; +} + +static int32_t xstring_hash(meta_obj_t* obj) +{ + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + + return priv->hashcode; +} + +static int64_t xstring_length(meta_obj_t* obj) +{ + xstring_private_t* priv = (xstring_private_t*)RTTI_OBJ_TO_PRIV(obj); + + return priv->len; +} + +char* makeString(char* s) +{ + var string; + int rc; + + if (s == NULL) { + errno = EINVAL; + return NULL; + } + + mylock_lock(&(xstring_table.lock)); + rc = key_find(xstring_table.xstr_table, (void*)s, (void**)&string); + if (rc > 0) { + /* add reference */ + reference(string); + } + mylock_unlock(&(xstring_table.lock)); + + if (rc > 0) { + return (char*)string; + } + + string = makeInstance(&xstring_type, s); + if (string == NULL) { + return NULL; + } + + mylock_lock(&(xstring_table.lock)); + rc = key_add(xstring_table.xstr_table, (void*)s, string); + mylock_unlock(&(xstring_table.lock)); + + if (rc < 0) { + destroy_(string, (obj_destroy_fn_t)xstring_destroy); + string = NULL; + errno = -rc; + } + + return (char*)string; +} + +static typeinfo_t xstring_type = { + .name = "xstring", + .privateSize = sizeof(xstring_private_t), + .dataSize = (datasize_fn_t)xstring_datasize, + .init = (obj_init_fn_t)xstring_init, + .destroy = (obj_destroy_fn_t)NULL, /* to disable destroy() */ + .interfaces + = { .reference + = &(intf_reference_t) { .reference = (reference_fn_t)xstring_reference, + .dereference + = (dereference_fn_t)xstring_dereference }, + .hash = &(intf_hash_t) { .hash = (hash_fn_t)xstring_hash }, + .length = &(intf_length_t) { .length = (length_fn_t)xstring_length } } +};