mirror of
https://github.com/emqx/neuron.git
synced 2026-10-30 16:09:02 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee9da15891 | ||
|
|
80caae1095 | ||
|
|
ec00415177 | ||
|
|
ae36da9c94 | ||
|
|
2225e71b66 | ||
|
|
1f37d12c8e | ||
|
|
80bdc5bf1e | ||
|
|
c656eb1775 | ||
|
|
77e4cf67d9 | ||
|
|
c5510e22af | ||
|
|
91776516b1 | ||
|
|
46b5a3b61a | ||
|
|
b5bc952543 | ||
|
|
f5976f95dc | ||
|
|
cd9da5afef | ||
|
|
1c7bd2193a | ||
|
|
36b5e491e4 | ||
|
|
642e832d5c | ||
|
|
b46ef37d51 | ||
|
|
04d2a78e7a | ||
|
|
841680a00e | ||
|
|
691c51bcb1 | ||
|
|
2dce709f2d | ||
|
|
d28f4430d9 | ||
|
|
6a810d616b | ||
|
|
801d369d6a | ||
|
|
5179001d32 | ||
|
|
889f69b57d | ||
|
|
7790b2cdd2 | ||
|
|
9ed033ee84 | ||
|
|
fb8463d9bf | ||
|
|
ce8b1612d4 | ||
|
|
8d372d3e13 | ||
|
|
f91b937b18 | ||
|
|
555707c666 | ||
|
|
3ad51811ff | ||
|
|
92d4ee84d9 | ||
|
|
5f5e9ac123 | ||
|
|
0a54b13022 | ||
|
|
527b434374 | ||
|
|
66c373e539 | ||
|
|
2821d91247 | ||
|
|
374dfa13d4 | ||
|
|
45b3aeda9a | ||
|
|
e1429d95c8 | ||
|
|
62da33b352 | ||
|
|
eff4bc7886 | ||
|
|
bef72d2f2b | ||
|
|
a7da8ec66c | ||
|
|
eeeca7144b | ||
|
|
b8890b708a | ||
|
|
f0fbfa6500 | ||
|
|
07ff0444ac | ||
|
|
f9e3e6b9e8 |
@@ -9,16 +9,16 @@ on:
|
||||
|
||||
jobs:
|
||||
clang_format_check:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
# checkout
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Run clang-format style check for C/C++ programs.
|
||||
uses: DoozyX/clang-format-lint-action@v0.12
|
||||
uses: DoozyX/clang-format-lint-action@v0.18
|
||||
with:
|
||||
source: 'src plugins include tests'
|
||||
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h'
|
||||
|
||||
@@ -8,13 +8,13 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.6.6
|
||||
VERSION: 2.6.9
|
||||
UI_VERSION: 2.6.3
|
||||
BRANCH: v2.6
|
||||
|
||||
jobs:
|
||||
cross-build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
@@ -52,14 +52,14 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
name: neuron-sdk-${{ matrix.arch[2] }}
|
||||
path: |
|
||||
neuron-sdk-*.tar.gz
|
||||
|
||||
build-debug-sdk:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
path: |
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ add_library(neuron-base SHARED)
|
||||
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE})
|
||||
target_include_directories(neuron-base
|
||||
PRIVATE include/neuron src)
|
||||
target_link_libraries(neuron-base atomic libssl.a libcrypto.a)
|
||||
target_link_libraries(neuron-base libssl.a libcrypto.a)
|
||||
target_link_libraries(neuron-base nng libzlog.so jansson jwt
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
add_dependencies(neuron-base neuron-version)
|
||||
|
||||
@@ -47,6 +47,7 @@ typedef enum {
|
||||
NEU_ERR_COMMAND_EXECUTION_FAILED = 1014,
|
||||
NEU_ERR_IP_ADDRESS_INVALID = 1015,
|
||||
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
|
||||
NEU_ERR_BODY_TOO_BIG = 1017,
|
||||
|
||||
NEU_ERR_NODE_EXIST = 2002,
|
||||
NEU_ERR_NODE_NOT_EXIST = 2003,
|
||||
|
||||
+219
-18
@@ -26,24 +26,37 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "define.h"
|
||||
#include "type.h"
|
||||
#include "utils/rolling_counter.h"
|
||||
#include "utils/utextend.h"
|
||||
#include "utils/uthash.h"
|
||||
|
||||
extern int64_t global_timestamp;
|
||||
|
||||
typedef enum {
|
||||
NEU_METRIC_TYPE_COUNTER,
|
||||
NEU_METRIC_TYPE_GAUAGE,
|
||||
NEU_METRIC_TYPE_COUNTER_SET,
|
||||
NEU_METRIC_TYPE_ROLLING_COUNTER,
|
||||
|
||||
NEU_METRIC_TYPE_FLAG_NO_RESET = 0x80,
|
||||
} neu_metric_type_e;
|
||||
|
||||
#define NEU_METRIC_TYPE_MASK 0x0F
|
||||
|
||||
// node running state
|
||||
#define NEU_METRIC_RUNNING_STATE "running_state"
|
||||
#define NEU_METRIC_RUNNING_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_RUNNING_STATE_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_RUNNING_STATE_HELP "Node running state"
|
||||
|
||||
// node link state
|
||||
#define NEU_METRIC_LINK_STATE "link_state"
|
||||
#define NEU_METRIC_LINK_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_LINK_STATE_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_LINK_STATE_HELP "Node link state"
|
||||
|
||||
// last round trip time in millisends
|
||||
@@ -79,13 +92,15 @@ typedef enum {
|
||||
// maintained by neuron core
|
||||
// number of tags in group
|
||||
#define NEU_METRIC_TAGS_TOTAL "tags_total"
|
||||
#define NEU_METRIC_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_TAGS_TOTAL_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_TAGS_TOTAL_HELP "Total number of tags in the node"
|
||||
|
||||
// maintained by neuron core
|
||||
// number of tags in group
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL "group_tags_total"
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_HELP "Total number of tags in the group"
|
||||
|
||||
// number of messages sent in last group timer
|
||||
@@ -140,11 +155,12 @@ typedef enum {
|
||||
|
||||
// metric entry
|
||||
typedef struct {
|
||||
const char * name; // NOTE: should points to string literal
|
||||
const char * help; // NOTE: should points to string literal
|
||||
neu_metric_type_e type; //
|
||||
uint64_t value; //
|
||||
UT_hash_handle hh; // ordered by name
|
||||
const char * name; // NOTE: should points to string literal
|
||||
const char * help; // NOTE: should points to string literal
|
||||
neu_metric_type_e type; //
|
||||
uint64_t value; //
|
||||
neu_rolling_counter_t *rcnt; //
|
||||
UT_hash_handle hh; // ordered by name
|
||||
} neu_metric_entry_t;
|
||||
|
||||
// group metrics
|
||||
@@ -156,6 +172,7 @@ typedef struct {
|
||||
|
||||
// node metrics
|
||||
typedef struct {
|
||||
pthread_mutex_t lock; // spin lock
|
||||
neu_node_type_e type; // node type
|
||||
char * name; // node name
|
||||
neu_metric_entry_t * entries; // node metric entries
|
||||
@@ -187,9 +204,34 @@ typedef struct {
|
||||
neu_metric_entry_t *registered_metrics;
|
||||
} neu_metrics_t;
|
||||
|
||||
void neu_metrics_init();
|
||||
void neu_metrics_add_node(const neu_adapter_t *adapter);
|
||||
void neu_metrics_del_node(const neu_adapter_t *adapter);
|
||||
int neu_metrics_register_entry(const char *name, const char *help,
|
||||
neu_metric_type_e type);
|
||||
void neu_metrics_unregister_entry(const char *name);
|
||||
|
||||
typedef void (*neu_metrics_cb_t)(const neu_metrics_t *metrics, void *data);
|
||||
void neu_metrics_visist(neu_metrics_cb_t cb, void *data);
|
||||
|
||||
static inline bool neu_metric_type_is_counter(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_COUNTER == (type & NEU_METRIC_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline bool neu_metric_type_is_rolling_counter(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_ROLLING_COUNTER == (type & NEU_METRIC_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline bool neu_metric_type_no_reset(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_FLAG_NO_RESET & type;
|
||||
}
|
||||
|
||||
static inline const char *neu_metric_type_str(neu_metric_type_e type)
|
||||
{
|
||||
if (NEU_METRIC_TYPE_COUNTER == type) {
|
||||
if (neu_metric_type_is_counter(type)) {
|
||||
return "counter";
|
||||
} else {
|
||||
return "gauge";
|
||||
@@ -202,6 +244,9 @@ int neu_metric_entries_add(neu_metric_entry_t **entries, const char *name,
|
||||
|
||||
static inline void neu_metric_entry_free(neu_metric_entry_t *entry)
|
||||
{
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_free(entry->rcnt);
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
|
||||
@@ -215,22 +260,41 @@ static inline void neu_group_metrics_free(neu_group_metrics_t *group_metrics)
|
||||
HASH_ITER(hh, group_metrics->entries, e, tmp)
|
||||
{
|
||||
HASH_DEL(group_metrics->entries, e);
|
||||
neu_metrics_unregister_entry(e->name);
|
||||
neu_metric_entry_free(e);
|
||||
}
|
||||
free(group_metrics->name);
|
||||
free(group_metrics);
|
||||
}
|
||||
|
||||
static inline neu_node_metrics_t *
|
||||
neu_node_metrics_new(neu_adapter_t *adapter, neu_node_type_e type, char *name)
|
||||
{
|
||||
neu_node_metrics_t *node_metrics =
|
||||
(neu_node_metrics_t *) calloc(1, sizeof(*node_metrics));
|
||||
if (NULL != node_metrics) {
|
||||
pthread_mutex_init(&node_metrics->lock, NULL);
|
||||
node_metrics->type = type;
|
||||
node_metrics->name = name;
|
||||
node_metrics->adapter = adapter;
|
||||
// neu_metrics_add_node(adapter);
|
||||
}
|
||||
return node_metrics;
|
||||
}
|
||||
|
||||
static inline void neu_node_metrics_free(neu_node_metrics_t *node_metrics)
|
||||
{
|
||||
if (NULL == node_metrics) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&node_metrics->lock);
|
||||
|
||||
neu_metric_entry_t *e = NULL, *etmp = NULL;
|
||||
HASH_ITER(hh, node_metrics->entries, e, etmp)
|
||||
{
|
||||
HASH_DEL(node_metrics->entries, e);
|
||||
neu_metrics_unregister_entry(e->name);
|
||||
neu_metric_entry_free(e);
|
||||
}
|
||||
|
||||
@@ -244,15 +308,152 @@ static inline void neu_node_metrics_free(neu_node_metrics_t *node_metrics)
|
||||
free(node_metrics);
|
||||
}
|
||||
|
||||
void neu_metrics_init();
|
||||
void neu_metrics_add_node(const neu_adapter_t *adapter);
|
||||
void neu_metrics_del_node(const neu_adapter_t *adapter);
|
||||
int neu_metrics_register_entry(const char *name, const char *help,
|
||||
neu_metric_type_e type);
|
||||
void neu_metrics_unregister_entry(const char *name);
|
||||
static inline int neu_node_metrics_add(neu_node_metrics_t *node_metrics,
|
||||
const char *group_name, const char *name,
|
||||
const char *help, neu_metric_type_e type,
|
||||
uint64_t init)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
typedef void (*neu_metrics_cb_t)(const neu_metrics_t *metrics, void *data);
|
||||
void neu_metrics_visist(neu_metrics_cb_t cb, void *data);
|
||||
if (0 > neu_metrics_register_entry(name, help, type)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
if (NULL == group_name) {
|
||||
rv = neu_metric_entries_add(&node_metrics->entries, name, help, type,
|
||||
init);
|
||||
} else {
|
||||
neu_group_metrics_t *group_metrics = NULL;
|
||||
HASH_FIND_STR(node_metrics->group_metrics, group_name, group_metrics);
|
||||
if (NULL != group_metrics) {
|
||||
rv = neu_metric_entries_add(&group_metrics->entries, name, help,
|
||||
type, init);
|
||||
} else {
|
||||
group_metrics =
|
||||
(neu_group_metrics_t *) calloc(1, sizeof(*group_metrics));
|
||||
if (NULL != group_metrics &&
|
||||
NULL != (group_metrics->name = strdup(group_name))) {
|
||||
HASH_ADD_STR(node_metrics->group_metrics, name, group_metrics);
|
||||
rv = neu_metric_entries_add(&group_metrics->entries, name, help,
|
||||
type, init);
|
||||
} else {
|
||||
free(group_metrics);
|
||||
rv = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
|
||||
if (0 != rv) {
|
||||
neu_metrics_unregister_entry(name);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline int neu_node_metrics_update(neu_node_metrics_t *node_metrics,
|
||||
const char * group,
|
||||
const char *metric_name, uint64_t n)
|
||||
{
|
||||
neu_metric_entry_t *entry = NULL;
|
||||
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
if (NULL == group) {
|
||||
HASH_FIND_STR(node_metrics->entries, metric_name, entry);
|
||||
} else if (NULL != node_metrics->group_metrics) {
|
||||
neu_group_metrics_t *g = NULL;
|
||||
HASH_FIND_STR(node_metrics->group_metrics, group, g);
|
||||
if (NULL != g) {
|
||||
HASH_FIND_STR(g->entries, metric_name, entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == entry) {
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (neu_metric_type_is_counter(entry->type)) {
|
||||
entry->value += n;
|
||||
} else if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
entry->value =
|
||||
neu_rolling_counter_inc(entry->rcnt, global_timestamp, n);
|
||||
} else {
|
||||
entry->value = n;
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void neu_node_metrics_reset(neu_node_metrics_t *node_metrics)
|
||||
{
|
||||
neu_metric_entry_t *entry = NULL;
|
||||
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_LOOP(hh, node_metrics->entries, entry)
|
||||
{
|
||||
if (!neu_metric_type_no_reset(entry->type)) {
|
||||
entry->value = 0;
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
neu_group_metrics_t *g = NULL;
|
||||
HASH_LOOP(hh, node_metrics->group_metrics, g)
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, entry)
|
||||
{
|
||||
if (!neu_metric_type_no_reset(entry->type)) {
|
||||
entry->value = 0;
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
}
|
||||
|
||||
static inline int
|
||||
neu_node_metrics_update_group(neu_node_metrics_t *node_metrics,
|
||||
const char * group_name,
|
||||
const char * new_group_name)
|
||||
{
|
||||
int rv = -1;
|
||||
neu_group_metrics_t *group_metrics = NULL;
|
||||
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_FIND_STR(node_metrics->group_metrics, group_name, group_metrics);
|
||||
if (NULL != group_metrics) {
|
||||
char *name = strdup(new_group_name);
|
||||
if (NULL != name) {
|
||||
HASH_DEL(node_metrics->group_metrics, group_metrics);
|
||||
free(group_metrics->name);
|
||||
group_metrics->name = name;
|
||||
HASH_ADD_STR(node_metrics->group_metrics, name, group_metrics);
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline void neu_node_metrics_del_group(neu_node_metrics_t *node_metrics,
|
||||
const char * group_name)
|
||||
{
|
||||
neu_group_metrics_t *gm = NULL;
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_FIND_STR(node_metrics->group_metrics, group_name, gm);
|
||||
if (NULL != gm) {
|
||||
HASH_DEL(node_metrics->group_metrics, gm);
|
||||
neu_group_metrics_free(gm);
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -36,6 +36,14 @@ extern "C" {
|
||||
#define NEURON_PLUGIN_VER_1_0 100
|
||||
#define NEURON_PLUGIN_VER_2_0 200
|
||||
|
||||
#define NEU_PLUGIN_REGISTER_METRIC(plugin, name, init) \
|
||||
plugin->common.adapter_callbacks->register_metric( \
|
||||
plugin->common.adapter, name, name##_HELP, name##_TYPE, init)
|
||||
|
||||
#define NEU_PLUGIN_UPDATE_METRIC(plugin, name, val, grp) \
|
||||
plugin->common.adapter_callbacks->update_metric(plugin->common.adapter, \
|
||||
name, val, grp)
|
||||
|
||||
extern int64_t global_timestamp;
|
||||
|
||||
typedef struct neu_plugin_common {
|
||||
@@ -60,6 +68,7 @@ struct neu_plugin_group {
|
||||
|
||||
void * user_data;
|
||||
neu_plugin_group_free group_free;
|
||||
uint32_t interval;
|
||||
};
|
||||
|
||||
typedef int (*neu_plugin_tag_validator_t)(const neu_datatag_t *tag);
|
||||
|
||||
@@ -44,6 +44,10 @@ typedef enum {
|
||||
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL 2,1,4,3
|
||||
NEU_DATATAG_ENDIAN_L64 = 6, // #L 8,7,6,5,4,3,2,1
|
||||
NEU_DATATAG_ENDIAN_B64 = 7, // #B 1,2,3,4,5,6,7,8
|
||||
NEU_DATATAG_ENDIAN_LL64 = 8,
|
||||
NEU_DATATAG_ENDIAN_LB64 = 9,
|
||||
NEU_DATATAG_ENDIAN_BB64 = 10,
|
||||
NEU_DATATAG_ENDIAN_BL64 = 11,
|
||||
} neu_datatag_endian_e;
|
||||
|
||||
typedef enum {
|
||||
@@ -62,6 +66,7 @@ typedef union {
|
||||
} value32;
|
||||
struct {
|
||||
neu_datatag_endian_e endian;
|
||||
bool is_default;
|
||||
} value64;
|
||||
struct {
|
||||
uint16_t length;
|
||||
|
||||
@@ -498,6 +498,42 @@ static inline uint64_t neu_htonll(uint64_t u)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonlb(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[1];
|
||||
out_bytes[1] = in[0];
|
||||
out_bytes[2] = in[3];
|
||||
out_bytes[3] = in[2];
|
||||
out_bytes[4] = in[5];
|
||||
out_bytes[5] = in[4];
|
||||
out_bytes[6] = in[7];
|
||||
out_bytes[7] = in[6];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonbl(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[6];
|
||||
out_bytes[1] = in[7];
|
||||
out_bytes[2] = in[4];
|
||||
out_bytes[3] = in[5];
|
||||
out_bytes[4] = in[2];
|
||||
out_bytes[5] = in[3];
|
||||
out_bytes[6] = in[0];
|
||||
out_bytes[7] = in[1];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_ntohll(uint64_t u)
|
||||
{
|
||||
return neu_htonll(u);
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2024 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
#ifndef NEURON_UTILS_ROLLING_COUNTER_H
|
||||
#define NEURON_UTILS_ROLLING_COUNTER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/** Rolling counter.
|
||||
*
|
||||
* This counter is for counting values within some latest time span, like
|
||||
* network bytes sent within the last 5 seconds etc.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t val; // accumulator
|
||||
uint64_t ts; // head time stamp in milliseconds
|
||||
uint32_t res : 21; // time resolution in milliseconds
|
||||
uint32_t hd : 5; // head position
|
||||
uint32_t n : 6; // number of counters
|
||||
uint32_t counts[]; // bins of counters
|
||||
} neu_rolling_counter_t;
|
||||
|
||||
/** Create rolling counter.
|
||||
*
|
||||
* @param span time span in milliseconds
|
||||
*/
|
||||
static inline neu_rolling_counter_t *neu_rolling_counter_new(unsigned span)
|
||||
{
|
||||
unsigned n = span <= 6000 ? 4 : span <= 32000 ? 8 : span <= 64000 ? 16 : 32;
|
||||
assert(span / n < (1 << 22)); // should not overflow ti
|
||||
|
||||
neu_rolling_counter_t *counter = (neu_rolling_counter_t *) calloc(
|
||||
1, sizeof(*counter) + sizeof(counter->counts[0]) * n);
|
||||
if (counter) {
|
||||
counter->res = span / n;
|
||||
counter->n = n;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/** Destructs the rolling counter.
|
||||
*/
|
||||
static inline void neu_rolling_counter_free(neu_rolling_counter_t *counter)
|
||||
{
|
||||
if (counter) {
|
||||
free(counter);
|
||||
}
|
||||
}
|
||||
|
||||
/** Increment the rolling counter and return the value;
|
||||
*
|
||||
* @param ts time stamp in milliseconds, should be monotonic
|
||||
* @param dt delta value to increment by
|
||||
*/
|
||||
static inline uint64_t neu_rolling_counter_inc(neu_rolling_counter_t *counter,
|
||||
uint64_t ts, unsigned dt)
|
||||
{
|
||||
uint64_t step = (ts - counter->ts) / counter->res;
|
||||
for (unsigned i = 0; i < step && i < counter->n; ++i) {
|
||||
counter->hd = (counter->hd + 1) & (counter->n - 1);
|
||||
counter->val -= counter->counts[counter->hd];
|
||||
counter->counts[counter->hd] = 0;
|
||||
}
|
||||
counter->val += dt;
|
||||
counter->counts[counter->hd] += dt;
|
||||
counter->ts += step * counter->res;
|
||||
return counter->val;
|
||||
}
|
||||
|
||||
/** Reset the counter.
|
||||
*/
|
||||
static inline void neu_rolling_counter_reset(neu_rolling_counter_t *counter)
|
||||
{
|
||||
counter->val = 0;
|
||||
counter->hd = 0;
|
||||
memset(counter->counts, 0, counter->n * sizeof(counter->counts[0]));
|
||||
}
|
||||
|
||||
/** Return the counter value.
|
||||
*
|
||||
* NOTE: may return stale value if the counter is not updated frequent enough.
|
||||
*/
|
||||
static inline uint64_t neu_rolling_counter_value(neu_rolling_counter_t *counter)
|
||||
{
|
||||
return counter->val;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+11
-15
@@ -185,7 +185,8 @@ int json_decode_write_req(char *buf, size_t len, json_write_req_t **result)
|
||||
|
||||
json_obj = neu_json_decode_newb(buf, len);
|
||||
if (NULL == json_obj) {
|
||||
goto decode_fail;
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
@@ -208,27 +209,20 @@ int json_decode_write_req(char *buf, size_t len, json_write_req_t **result)
|
||||
};
|
||||
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
|
||||
req_elems);
|
||||
if (ret != 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
req->node_name = req_elems[0].v.val_str;
|
||||
req->group_name = req_elems[1].v.val_str;
|
||||
req->tag_name = req_elems[2].v.val_str;
|
||||
req->t = req_elems[3].t;
|
||||
req->value = req_elems[3].v;
|
||||
|
||||
*result = req;
|
||||
goto decode_exit;
|
||||
|
||||
decode_fail:
|
||||
free(req);
|
||||
ret = -1;
|
||||
|
||||
decode_exit:
|
||||
if (json_obj != NULL) {
|
||||
neu_json_decode_free(json_obj);
|
||||
if (0 == ret) {
|
||||
*result = req;
|
||||
} else {
|
||||
json_decode_write_req_free(req);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
neu_json_decode_free(json_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -243,6 +237,8 @@ void json_decode_write_req_free(json_write_req_t *req)
|
||||
free(req->tag_name);
|
||||
if (req->t == NEU_JSON_STR) {
|
||||
free(req->value.val_str);
|
||||
} else if (req->t == NEU_JSON_BYTES) {
|
||||
free(req->value.val_bytes.bytes);
|
||||
}
|
||||
|
||||
free(req);
|
||||
|
||||
@@ -114,10 +114,9 @@ static int ekuiper_plugin_uninit(neu_plugin_t *plugin)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_start(neu_plugin_t *plugin)
|
||||
static inline int start(neu_plugin_t *plugin, const char *url)
|
||||
{
|
||||
int rv = 0;
|
||||
char *url = plugin->url ? plugin->url : EKUIPER_PLUGIN_URL; // default url
|
||||
int rv = 0;
|
||||
|
||||
rv = nng_pair0_open(&plugin->sock);
|
||||
if (rv != 0) {
|
||||
@@ -143,16 +142,43 @@ static int ekuiper_plugin_start(neu_plugin_t *plugin)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
while (plugin->receiving) {
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
nng_msleep(10);
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
}
|
||||
plugin->receiving = true;
|
||||
nng_recv_aio(plugin->sock, plugin->recv_aio);
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_start(neu_plugin_t *plugin)
|
||||
{
|
||||
int rv = 0;
|
||||
char *url = plugin->url ? plugin->url : EKUIPER_PLUGIN_URL; // default url
|
||||
|
||||
rv = start(plugin, url);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
plugin->started = true;
|
||||
plog_notice(plugin, "start successfully");
|
||||
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_stop(neu_plugin_t *plugin)
|
||||
static inline void stop(neu_plugin_t *plugin)
|
||||
{
|
||||
nng_close(plugin->sock);
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
stop(plugin);
|
||||
plugin->started = false;
|
||||
plog_notice(plugin, "stop successfully");
|
||||
return NEU_ERR_SUCCESS;
|
||||
@@ -201,41 +227,6 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int check_url_listenable(neu_plugin_t *plugin, const char *url,
|
||||
const char *host, uint16_t port)
|
||||
{
|
||||
if (NULL != plugin->host && // already configured and
|
||||
port == plugin->port && // port is the same, then if
|
||||
(0 == strcmp(plugin->host, host) // 1. host is the same
|
||||
|| 0 == strcmp("0.0.0.0", host) // 2. to bind to any address
|
||||
|| 0 == strcmp("0.0.0.0", plugin->host) // 3. bound to any address
|
||||
)) {
|
||||
// early return, no need check url is listenable
|
||||
return 0;
|
||||
}
|
||||
|
||||
nng_socket sock = NNG_SOCKET_INITIALIZER;
|
||||
int rv = nng_pair0_open(&sock);
|
||||
if (0 != rv) {
|
||||
plog_error(plugin, "nng_pair0_open: %s", nng_strerror(rv));
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 != (rv = nng_listen(sock, url, NULL, 0))) {
|
||||
plog_error(plugin, "nng_listen: %s", nng_strerror(rv));
|
||||
if (NNG_EADDRINVAL == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_INVALID;
|
||||
} else if (NNG_EADDRINUSE == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_IN_USE;
|
||||
} else {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
nng_close(sock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
{
|
||||
int rv = 0;
|
||||
@@ -255,23 +246,31 @@ static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0 != (rv = check_url_listenable(plugin, url, host, port))) {
|
||||
if (plugin->started) {
|
||||
stop(plugin);
|
||||
}
|
||||
|
||||
// check we could start the plugin with the new setting
|
||||
if (0 != (rv = start(plugin, url))) {
|
||||
// recover with old setting
|
||||
if (plugin->started && 0 != start(plugin, plugin->url)) {
|
||||
plog_warn(plugin, "restart host:%s port:%" PRIu16 " fail",
|
||||
plugin->host, plugin->port);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!plugin->started) {
|
||||
stop(plugin);
|
||||
}
|
||||
|
||||
plog_notice(plugin, "config success");
|
||||
|
||||
free(plugin->host);
|
||||
free(plugin->url);
|
||||
plugin->host = host;
|
||||
plugin->port = port;
|
||||
free(plugin->url);
|
||||
plugin->url = url;
|
||||
|
||||
if (plugin->started) {
|
||||
// restart service
|
||||
ekuiper_plugin_stop(plugin);
|
||||
ekuiper_plugin_start(plugin);
|
||||
}
|
||||
plugin->url = url;
|
||||
|
||||
return rv;
|
||||
|
||||
@@ -310,6 +309,9 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NEU_REQRESP_NODE_DELETED: {
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_UPDATE_NODE: {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ struct neu_plugin {
|
||||
nng_socket sock;
|
||||
nng_mtx * mtx;
|
||||
bool started;
|
||||
bool receiving;
|
||||
nng_aio * recv_aio;
|
||||
char * host;
|
||||
uint16_t port;
|
||||
|
||||
@@ -86,6 +86,9 @@ void recv_data_callback(void *arg)
|
||||
rv = nng_aio_result(plugin->recv_aio);
|
||||
if (0 != rv) {
|
||||
plog_error(plugin, "nng_recv error: %s", nng_strerror(rv));
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
plugin->receiving = false;
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -106,6 +106,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -93,6 +93,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -66,6 +66,13 @@ typedef enum modbus_area {
|
||||
MODBUS_AREA_HOLD_REGISTER = 4,
|
||||
} modbus_area_e;
|
||||
|
||||
typedef enum modbus_endianess_64 {
|
||||
MODBUS_LL = 1, // 12 34 56 78
|
||||
MODBUS_LB = 2, // 21 43 65 87
|
||||
MODBUS_BB = 3, // 87 65 43 21
|
||||
MODBUS_BL = 4, // 78 56 34 12
|
||||
} modbus_endianess_64;
|
||||
|
||||
struct modbus_header {
|
||||
uint16_t seq;
|
||||
uint16_t protocol;
|
||||
|
||||
@@ -221,7 +221,8 @@ modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
|
||||
return sort_result;
|
||||
}
|
||||
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option,
|
||||
modbus_endianess_64 endianess_64, bool default_tag_endian_64)
|
||||
{
|
||||
int n = 0;
|
||||
switch (type) {
|
||||
@@ -240,6 +241,9 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (default_tag_endian_64) {
|
||||
modbus_convert_endianess_64(value, endianess_64);
|
||||
}
|
||||
n = sizeof(uint64_t);
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
@@ -273,7 +277,8 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
return n;
|
||||
}
|
||||
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64)
|
||||
{
|
||||
neu_tag_sort_result_t *result =
|
||||
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
|
||||
@@ -295,14 +300,17 @@ modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
utarray_foreach(result->sorts[i].tags, modbus_point_write_t **, tag_s)
|
||||
{
|
||||
if ((*tag_s)->point.area == MODBUS_AREA_COIL) {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64, true);
|
||||
data_bit[k / 8] += ((*tag_s)->value.i8) << k % 8;
|
||||
n_byte += n_byte_tag;
|
||||
k++;
|
||||
} else {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64,
|
||||
(*tag_s)->point.option.value64.is_default);
|
||||
memcpy(sort_result->cmd[i].bytes +
|
||||
2 *
|
||||
((*tag_s)->point.start_address -
|
||||
@@ -512,4 +520,24 @@ static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64)
|
||||
{
|
||||
switch (endianess_64) {
|
||||
case MODBUS_LL:
|
||||
break;
|
||||
case MODBUS_BB:
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
case MODBUS_LB:
|
||||
value->u64 = neu_htonlb(value->u64);
|
||||
break;
|
||||
case MODBUS_BL:
|
||||
value->u64 = neu_htonbl(value->u64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -79,9 +79,13 @@ typedef struct modbus_write_cmd_sort {
|
||||
modbus_write_cmd_t *cmd;
|
||||
} modbus_write_cmd_sort_t;
|
||||
|
||||
modbus_read_cmd_sort_t * modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -402,6 +402,10 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if ((*p_tag)->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&dvalue.value,
|
||||
plugin->endianess_64);
|
||||
}
|
||||
dvalue.value.u64 = neu_ntohll(dvalue.value.u64);
|
||||
break;
|
||||
case NEU_TYPE_BIT: {
|
||||
@@ -476,6 +480,9 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (tag->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&value, plugin->endianess_64);
|
||||
}
|
||||
value.u64 = neu_htonll(value.u64);
|
||||
n_byte = sizeof(uint64_t);
|
||||
break;
|
||||
@@ -543,7 +550,7 @@ int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
|
||||
|
||||
utarray_push_back(gtags->tags, &p);
|
||||
}
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags);
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags, plugin->endianess_64);
|
||||
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
|
||||
uint16_t response_size = 0;
|
||||
|
||||
@@ -698,7 +705,7 @@ static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
}
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, 0, &pbuf);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, slave_id, &pbuf);
|
||||
if (ret_s == MODBUS_DEVICE_ERR) {
|
||||
ret = ret_s;
|
||||
} else {
|
||||
|
||||
@@ -43,6 +43,8 @@ struct neu_plugin {
|
||||
uint16_t interval;
|
||||
uint16_t retry_interval;
|
||||
uint16_t max_retries;
|
||||
|
||||
modbus_endianess_64 endianess_64;
|
||||
};
|
||||
|
||||
void modbus_conn_connected(void *data, int fd);
|
||||
|
||||
@@ -167,6 +167,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
neu_json_elem_t retry_interval = { .name = "retry_interval",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
neu_json_elem_t endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout,
|
||||
&interval);
|
||||
if (ret != 0) {
|
||||
@@ -206,9 +209,16 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
retry_interval.v.val_int = 0;
|
||||
}
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
plugin->max_retries = max_retries.v.val_int;
|
||||
plugin->retry_interval = retry_interval.v.val_int;
|
||||
plugin->endianess_64 = endianess_64.v.val_int;
|
||||
|
||||
if (link.v.val_int == 0) {
|
||||
param.type = NEU_CONN_TTY_CLIENT;
|
||||
|
||||
@@ -84,10 +84,8 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
if (code.slave_id != slave_id) {
|
||||
return -1;
|
||||
}
|
||||
if (code.slave_id != slave_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (code.function) {
|
||||
@@ -102,18 +100,36 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP && data.n_byte == 0xff) {
|
||||
bytes = neu_protocol_unpack_buf(buf,
|
||||
header.len -
|
||||
sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data));
|
||||
stack->value_fn(stack->ctx, code.slave_id,
|
||||
header.len - sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data),
|
||||
bytes, 0);
|
||||
} else {
|
||||
switch (stack->protocol) {
|
||||
case MODBUS_PROTOCOL_TCP:
|
||||
if (data.n_byte == 0xff) {
|
||||
bytes = neu_protocol_unpack_buf(buf,
|
||||
header.len -
|
||||
sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data));
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id,
|
||||
header.len - sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data),
|
||||
bytes, 0);
|
||||
} else {
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes,
|
||||
0);
|
||||
}
|
||||
break;
|
||||
case MODBUS_PROTOCOL_RTU:
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -158,6 +158,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
neu_json_elem_t max_retries = { .name = "max_retries", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t retry_interval = { .name = "retry_interval",
|
||||
.t = NEU_JSON_INT };
|
||||
neu_json_elem_t endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
|
||||
&timeout, &interval);
|
||||
@@ -186,10 +188,17 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
retry_interval.v.val_int = 0;
|
||||
}
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
plugin->interval = interval.v.val_int;
|
||||
plugin->max_retries = max_retries.v.val_int;
|
||||
plugin->retry_interval = retry_interval.v.val_int;
|
||||
plugin->endianess_64 = endianess_64.v.val_int;
|
||||
|
||||
if (mode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_TCP_SERVER;
|
||||
|
||||
@@ -414,7 +414,7 @@ const neu_plugin_module_t neu_plugin_module = {
|
||||
.kind = NEU_PLUGIN_KIND_SYSTEM,
|
||||
.type = NEU_NA_TYPE_APP,
|
||||
.display = true,
|
||||
.single = false,
|
||||
.single = true,
|
||||
.single_name = "monitor",
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "define.h"
|
||||
#include "metrics.h"
|
||||
#include "plugin.h"
|
||||
#include "utils/asprintf.h"
|
||||
#include "utils/http.h"
|
||||
#include "utils/http_handler.h"
|
||||
@@ -155,8 +158,8 @@ static inline void gen_global_metrics(const neu_metrics_t *metrics,
|
||||
metrics->south_disconnected_nodes);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gen_single_node_metrics(const neu_node_metrics_t *node_metrics, FILE *stream)
|
||||
static inline void gen_single_node_metrics(neu_node_metrics_t *node_metrics,
|
||||
FILE * stream)
|
||||
{
|
||||
fprintf(stream,
|
||||
"# HELP node_type Driver(1) or APP(2)\n"
|
||||
@@ -166,8 +169,13 @@ gen_single_node_metrics(const neu_node_metrics_t *node_metrics, FILE *stream)
|
||||
|
||||
neu_metric_entry_t *e = NULL;
|
||||
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_LOOP(hh, node_metrics->entries, e)
|
||||
{
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value = neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
}
|
||||
fprintf(stream,
|
||||
"# HELP %s %s\n# TYPE %s %s\n%s{node=\"%s\"} %" PRIu64 "\n",
|
||||
e->name, e->help, e->name, neu_metric_type_str(e->type),
|
||||
@@ -179,6 +187,11 @@ gen_single_node_metrics(const neu_node_metrics_t *node_metrics, FILE *stream)
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, e)
|
||||
{
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value =
|
||||
neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
}
|
||||
fprintf(stream,
|
||||
"# HELP %s %s\n# TYPE %s %s\n%s{node=\"%s\",group=\"%s\"} "
|
||||
"%" PRIu64 "\n",
|
||||
@@ -186,6 +199,7 @@ gen_single_node_metrics(const neu_node_metrics_t *node_metrics, FILE *stream)
|
||||
e->name, node_metrics->name, g->name, e->value);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&node_metrics->lock);
|
||||
}
|
||||
|
||||
static inline bool has_entry(neu_node_metrics_t *node_metrics, const char *name)
|
||||
@@ -207,7 +221,7 @@ static inline bool has_entry(neu_node_metrics_t *node_metrics, const char *name)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void gen_all_node_metrics(const neu_metrics_t *metrics, int type_filter,
|
||||
static void gen_all_node_metrics(neu_metrics_t *metrics, int type_filter,
|
||||
FILE *stream)
|
||||
{
|
||||
neu_metric_entry_t * e = NULL, *r = NULL;
|
||||
@@ -252,11 +266,18 @@ static void gen_all_node_metrics(const neu_metrics_t *metrics, int type_filter,
|
||||
r->help, r->name, neu_metric_type_str(r->type));
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&n->lock);
|
||||
HASH_FIND_STR(n->entries, r->name, e);
|
||||
if (e) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value =
|
||||
neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
}
|
||||
fprintf(stream, "%s{node=\"%s\"} %" PRIu64 "\n", e->name,
|
||||
n->name, e->value);
|
||||
|
||||
pthread_mutex_unlock(&n->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -264,11 +285,17 @@ static void gen_all_node_metrics(const neu_metrics_t *metrics, int type_filter,
|
||||
{
|
||||
HASH_FIND_STR(g->entries, r->name, e);
|
||||
if (e) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value = neu_rolling_counter_inc(e->rcnt,
|
||||
global_timestamp, 0);
|
||||
}
|
||||
fprintf(stream,
|
||||
"%s{node=\"%s\",group=\"%s\"} %" PRIu64 "\n",
|
||||
e->name, n->name, g->name, e->value);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&n->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,7 +307,7 @@ struct context {
|
||||
const char *node;
|
||||
};
|
||||
|
||||
static void gen_node_metrics(const neu_metrics_t *metrics, struct context *ctx)
|
||||
static void gen_node_metrics(neu_metrics_t *metrics, struct context *ctx)
|
||||
{
|
||||
if (ctx->node[0]) {
|
||||
neu_node_metrics_t *n = NULL;
|
||||
|
||||
@@ -40,7 +40,7 @@ void handle_add_plugin(nng_aio *aio)
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_ADD_PLUGIN;
|
||||
strcpy(cmd.library, req->library);
|
||||
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
|
||||
+26
-128
@@ -373,22 +373,19 @@ static int adapter_register_metric(neu_adapter_t *adapter, const char *name,
|
||||
uint64_t init)
|
||||
{
|
||||
if (NULL == adapter->metrics) {
|
||||
adapter->metrics = calloc(1, sizeof(*adapter->metrics));
|
||||
adapter->metrics =
|
||||
neu_node_metrics_new(adapter, adapter->module->type, adapter->name);
|
||||
if (NULL == adapter->metrics) {
|
||||
return -1;
|
||||
}
|
||||
adapter->metrics->type = adapter->module->type;
|
||||
adapter->metrics->name = adapter->name;
|
||||
adapter->metrics->adapter = adapter;
|
||||
neu_metrics_add_node(adapter);
|
||||
}
|
||||
|
||||
if (0 > neu_metric_entries_add(&adapter->metrics->entries, name, help, type,
|
||||
init)) {
|
||||
if (0 >
|
||||
neu_node_metrics_add(adapter->metrics, NULL, name, help, type, init)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_metrics_register_entry(name, help, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -396,48 +393,11 @@ static int adapter_update_metric(neu_adapter_t *adapter,
|
||||
const char *metric_name, uint64_t n,
|
||||
const char *group)
|
||||
{
|
||||
neu_metric_entry_t *entry = NULL;
|
||||
if (NULL == adapter->metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == group) {
|
||||
HASH_FIND_STR(adapter->metrics->entries, metric_name, entry);
|
||||
} else if (NULL != adapter->metrics->group_metrics) {
|
||||
neu_group_metrics_t *g = NULL;
|
||||
HASH_FIND_STR(adapter->metrics->group_metrics, group, g);
|
||||
if (NULL != g) {
|
||||
HASH_FIND_STR(g->entries, metric_name, entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == entry) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NEU_METRIC_TYPE_COUNTER == entry->type) {
|
||||
entry->value += n;
|
||||
} else {
|
||||
entry->value = n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adapter_reset_metrics(neu_adapter_t *adapter)
|
||||
{
|
||||
neu_metric_entry_t *entry = NULL;
|
||||
if (NULL == adapter->metrics) {
|
||||
return;
|
||||
}
|
||||
|
||||
HASH_LOOP(hh, adapter->metrics->entries, entry) { entry->value = 0; }
|
||||
|
||||
neu_group_metrics_t *g = NULL;
|
||||
HASH_LOOP(hh, adapter->metrics->group_metrics, g)
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, entry) { entry->value = 0; }
|
||||
}
|
||||
return neu_node_metrics_update(adapter->metrics, group, metric_name, n);
|
||||
}
|
||||
|
||||
static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
|
||||
@@ -827,11 +787,13 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
neu_resp_get_node_state_t *resp =
|
||||
(neu_resp_get_node_state_t *) &header[1];
|
||||
|
||||
neu_metric_entry_t *e = NULL;
|
||||
if (NULL != adapter->metrics) {
|
||||
pthread_mutex_lock(&adapter->metrics->lock);
|
||||
neu_metric_entry_t *e = NULL;
|
||||
HASH_FIND_STR(adapter->metrics->entries, NEU_METRIC_LAST_RTT_MS, e);
|
||||
resp->rtt = NULL != e ? e->value : 0;
|
||||
pthread_mutex_unlock(&adapter->metrics->lock);
|
||||
}
|
||||
resp->rtt = NULL != e ? e->value : 0;
|
||||
resp->state = neu_adapter_get_state(adapter);
|
||||
header->type = NEU_RESP_GET_NODE_STATE;
|
||||
neu_msg_exchange(header);
|
||||
@@ -1247,11 +1209,6 @@ void neu_adapter_destroy(neu_adapter_t *adapter)
|
||||
|
||||
if (NULL != adapter->metrics) {
|
||||
neu_metrics_del_node(adapter);
|
||||
neu_metric_entry_t *e = NULL;
|
||||
HASH_LOOP(hh, adapter->metrics->entries, e)
|
||||
{
|
||||
neu_metrics_unregister_entry(e->name);
|
||||
}
|
||||
neu_node_metrics_free(adapter->metrics);
|
||||
}
|
||||
|
||||
@@ -1322,6 +1279,10 @@ int neu_adapter_start(neu_adapter_t *adapter)
|
||||
if (error == NEU_ERR_SUCCESS) {
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_RUNNING;
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
if (NEU_NA_TYPE_DRIVER == neu_adapter_get_type(adapter)) {
|
||||
neu_adapter_driver_start_group_timer(
|
||||
(neu_adapter_driver_t *) adapter);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -1360,7 +1321,11 @@ int neu_adapter_stop(neu_adapter_t *adapter)
|
||||
if (error == NEU_ERR_SUCCESS) {
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_STOPPED;
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
adapter_reset_metrics(adapter);
|
||||
if (NEU_NA_TYPE_DRIVER == neu_adapter_get_type(adapter)) {
|
||||
neu_adapter_driver_stop_group_timer(
|
||||
(neu_adapter_driver_t *) adapter);
|
||||
}
|
||||
neu_adapter_reset_metrics(adapter);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -1439,110 +1404,43 @@ int neu_adapter_register_group_metric(neu_adapter_t *adapter,
|
||||
const char *help, neu_metric_type_e type,
|
||||
uint64_t init)
|
||||
{
|
||||
neu_group_metrics_t *group_metrics = NULL;
|
||||
|
||||
if (NULL == adapter->metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 > neu_metrics_register_entry(name, help, type)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
HASH_FIND_STR(adapter->metrics->group_metrics, group_name, group_metrics);
|
||||
if (NULL == group_metrics) {
|
||||
group_metrics = calloc(1, sizeof(*group_metrics));
|
||||
if (NULL == group_metrics) {
|
||||
return -1;
|
||||
}
|
||||
group_metrics->name = strdup(group_name);
|
||||
if (NULL == group_metrics->name) {
|
||||
free(group_metrics);
|
||||
return -1;
|
||||
}
|
||||
HASH_ADD_STR(adapter->metrics->group_metrics, name, group_metrics);
|
||||
}
|
||||
|
||||
if (0 > neu_metric_entries_add(&group_metrics->entries, name, help, type,
|
||||
init)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return neu_node_metrics_add(adapter->metrics, group_name, name, help, type,
|
||||
init);
|
||||
}
|
||||
|
||||
int neu_adapter_update_group_metric(neu_adapter_t *adapter,
|
||||
const char * group_name,
|
||||
const char *metric_name, uint64_t n)
|
||||
{
|
||||
neu_metric_entry_t * entry = NULL;
|
||||
neu_group_metrics_t *group_metrics = NULL;
|
||||
|
||||
if (NULL == adapter->metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
HASH_FIND_STR(adapter->metrics->group_metrics, group_name, group_metrics);
|
||||
if (NULL == group_metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
HASH_FIND_STR(group_metrics->entries, metric_name, entry);
|
||||
if (NULL == entry) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NEU_METRIC_TYPE_COUNTER == entry->type) {
|
||||
entry->value += n;
|
||||
} else {
|
||||
entry->value = n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return neu_node_metrics_update(adapter->metrics, group_name, metric_name,
|
||||
n);
|
||||
}
|
||||
|
||||
int neu_adapter_metric_update_group_name(neu_adapter_t *adapter,
|
||||
const char * group_name,
|
||||
const char * new_group_name)
|
||||
{
|
||||
neu_group_metrics_t *group_metrics = NULL;
|
||||
|
||||
if (NULL == adapter->metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
HASH_FIND_STR(adapter->metrics->group_metrics, group_name, group_metrics);
|
||||
if (NULL == group_metrics) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *name = strdup(new_group_name);
|
||||
if (NULL == name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
HASH_DEL(adapter->metrics->group_metrics, group_metrics);
|
||||
free(group_metrics->name);
|
||||
group_metrics->name = name;
|
||||
HASH_ADD_STR(adapter->metrics->group_metrics, name, group_metrics);
|
||||
|
||||
return 0;
|
||||
return neu_node_metrics_update_group(adapter->metrics, group_name,
|
||||
new_group_name);
|
||||
}
|
||||
|
||||
void neu_adapter_del_group_metrics(neu_adapter_t *adapter,
|
||||
const char * group_name)
|
||||
{
|
||||
if (NULL == adapter->metrics) {
|
||||
return;
|
||||
}
|
||||
|
||||
neu_group_metrics_t *gm = NULL;
|
||||
HASH_FIND_STR(adapter->metrics->group_metrics, group_name, gm);
|
||||
if (NULL != gm) {
|
||||
HASH_DEL(adapter->metrics->group_metrics, gm);
|
||||
neu_metric_entry_t *e = NULL;
|
||||
HASH_LOOP(hh, gm->entries, e) { neu_metrics_unregister_entry(e->name); }
|
||||
neu_group_metrics_free(gm);
|
||||
if (NULL != adapter->metrics) {
|
||||
neu_node_metrics_del_group(adapter->metrics, group_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,13 @@ neu_node_state_t neu_adapter_get_state(neu_adapter_t *adapter);
|
||||
|
||||
int neu_adapter_validate_tag(neu_adapter_t *adapter, neu_datatag_t *tag);
|
||||
|
||||
static inline void neu_adapter_reset_metrics(neu_adapter_t *adapter)
|
||||
{
|
||||
if (NULL != adapter->metrics) {
|
||||
neu_node_metrics_reset(adapter->metrics);
|
||||
}
|
||||
}
|
||||
|
||||
int neu_adapter_register_group_metric(neu_adapter_t *adapter,
|
||||
const char *group_name, const char *name,
|
||||
const char *help, neu_metric_type_e type,
|
||||
|
||||
+103
-86
@@ -103,8 +103,11 @@ static void update_with_meta(neu_adapter_t *adapter, const char *group,
|
||||
const char *tag, neu_dvalue_t value,
|
||||
neu_tag_meta_t *metas, int n_meta);
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error);
|
||||
static group_t *find_group(neu_adapter_driver_t *driver, const char *name);
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag);
|
||||
static group_t * find_group(neu_adapter_driver_t *driver, const char *name);
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag);
|
||||
static inline void start_group_timer(neu_adapter_driver_t *driver,
|
||||
group_t * grp);
|
||||
static inline void stop_group_timer(neu_adapter_driver_t *driver, group_t *grp);
|
||||
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error)
|
||||
{
|
||||
@@ -324,9 +327,7 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
HASH_DEL(driver->groups, el);
|
||||
|
||||
neu_adapter_driver_try_del_tag(driver, neu_group_tag_size(el->group));
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, el->report);
|
||||
neu_event_del_timer(driver->driver_events, el->read);
|
||||
neu_event_del_timer(driver->driver_events, el->write);
|
||||
stop_group_timer(driver, el);
|
||||
if (el->grp.group_free != NULL) {
|
||||
el->grp.group_free(&el->grp);
|
||||
}
|
||||
@@ -349,34 +350,67 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void start_group_timer(neu_adapter_driver_t *driver, group_t *grp)
|
||||
{
|
||||
uint32_t interval = neu_group_get_interval(grp->group);
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) grp,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
grp->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
grp->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
|
||||
param.second = 0;
|
||||
param.millisecond = 3;
|
||||
param.cb = write_callback;
|
||||
grp->write = neu_event_add_timer(driver->driver_events, param);
|
||||
}
|
||||
|
||||
void neu_adapter_driver_start_group_timer(neu_adapter_driver_t *driver)
|
||||
{
|
||||
group_t *el = NULL, *tmp = NULL;
|
||||
|
||||
HASH_ITER(hh, driver->groups, el, tmp)
|
||||
{
|
||||
uint32_t interval = neu_group_get_interval(el->group);
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = el,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
start_group_timer(driver, el);
|
||||
neu_adapter_update_group_metric(
|
||||
&driver->adapter, neu_group_get_name(el->group),
|
||||
NEU_METRIC_GROUP_TAGS_TOTAL, neu_group_tag_size(el->group));
|
||||
}
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
el->read = neu_event_add_timer(driver->driver_events, param);
|
||||
driver->adapter.cb_funs.update_metric(
|
||||
&driver->adapter, NEU_METRIC_TAGS_TOTAL, driver->tag_cnt, NULL);
|
||||
}
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
el->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
static inline void stop_group_timer(neu_adapter_driver_t *driver, group_t *grp)
|
||||
{
|
||||
if (grp->report) {
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, grp->report);
|
||||
grp->report = NULL;
|
||||
}
|
||||
if (grp->read) {
|
||||
neu_event_del_timer(driver->driver_events, grp->read);
|
||||
grp->read = NULL;
|
||||
}
|
||||
if (grp->write) {
|
||||
neu_event_del_timer(driver->driver_events, grp->write);
|
||||
grp->write = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,13 +418,7 @@ void neu_adapter_driver_stop_group_timer(neu_adapter_driver_t *driver)
|
||||
{
|
||||
group_t *el = NULL, *tmp = NULL;
|
||||
|
||||
HASH_ITER(hh, driver->groups, el, tmp)
|
||||
{
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, el->report);
|
||||
el->report = NULL;
|
||||
neu_event_del_timer(driver->driver_events, el->read);
|
||||
el->read = NULL;
|
||||
}
|
||||
HASH_ITER(hh, driver->groups, el, tmp) { stop_group_timer(driver, el); }
|
||||
}
|
||||
|
||||
void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
|
||||
@@ -546,9 +574,17 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
|
||||
case NEU_TYPE_LWORD:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value->value.u64 = neu_ntohll(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value->value.u64 = neu_htonlb(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value->value.u64 = neu_htonbl(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -887,13 +923,6 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
if (find == NULL) {
|
||||
find = calloc(1, sizeof(group_t));
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) find,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
pthread_mutex_init(&find->wt_mtx, NULL);
|
||||
pthread_mutex_init(&find->apps_mtx, NULL);
|
||||
|
||||
@@ -904,28 +933,13 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
find->name = strdup(name);
|
||||
find->group = neu_group_new(name, interval);
|
||||
find->grp.group_name = strdup(name);
|
||||
find->grp.interval = interval;
|
||||
neu_group_split_static_tags(find->group, &find->static_tags,
|
||||
&find->grp.tags);
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
find->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
find->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
|
||||
param.second = 0;
|
||||
param.millisecond = 3;
|
||||
param.cb = write_callback;
|
||||
find->write = neu_event_add_timer(driver->driver_events, param);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
start_group_timer(driver, find);
|
||||
}
|
||||
|
||||
REGISTER_GROUP_METRIC(&driver->adapter, find->name,
|
||||
NEU_METRIC_GROUP_TAGS_TOTAL,
|
||||
@@ -969,11 +983,14 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
|
||||
return NEU_ERR_GROUP_EXIST;
|
||||
}
|
||||
}
|
||||
} else if (neu_group_get_interval(find->group) == interval) {
|
||||
return 0; // no change
|
||||
}
|
||||
|
||||
// stop the timer first to avoid race condition
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, find->report);
|
||||
neu_event_del_timer(driver->driver_events, find->read);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
stop_group_timer(driver, find);
|
||||
}
|
||||
|
||||
// a diminutive value should keep the interval untouched
|
||||
if (interval < NEU_GROUP_INTERVAL_LIMIT) {
|
||||
@@ -993,7 +1010,6 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
|
||||
find->grp.group_name = new_name_cp2;
|
||||
neu_adapter_metric_update_group_name((neu_adapter_t *) driver, name,
|
||||
new_name);
|
||||
find->timestamp = global_timestamp; // trigger group_change
|
||||
HASH_ADD_STR(driver->groups, name, find);
|
||||
} else {
|
||||
free(new_name_cp1);
|
||||
@@ -1002,31 +1018,14 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
|
||||
}
|
||||
}
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) find,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
find->timestamp = global_timestamp; // trigger group_change
|
||||
find->grp.interval = interval;
|
||||
neu_group_set_interval(find->group, interval);
|
||||
|
||||
// restore the timers
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
find->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
find->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
start_group_timer(driver, find);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1042,9 +1041,10 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
|
||||
|
||||
neu_adapter_driver_try_del_tag(driver, neu_group_tag_size(find->group));
|
||||
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, find->report);
|
||||
neu_event_del_timer(driver->driver_events, find->read);
|
||||
neu_event_del_timer(driver->driver_events, find->write);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
stop_group_timer(driver, find);
|
||||
}
|
||||
|
||||
if (find->grp.group_free != NULL) {
|
||||
find->grp.group_free(&find->grp);
|
||||
}
|
||||
@@ -1569,6 +1569,7 @@ static void group_change(void *arg, int64_t timestamp, UT_array *static_tags,
|
||||
|
||||
neu_plugin_group_t grp = {
|
||||
.group_name = strdup(group->name),
|
||||
.interval = neu_group_get_interval(group->group),
|
||||
.tags = NULL,
|
||||
.group_free = NULL,
|
||||
.user_data = NULL,
|
||||
@@ -1734,9 +1735,17 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1886,9 +1895,17 @@ static void read_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+64
-12
@@ -189,16 +189,17 @@ static unsigned cpu_usage()
|
||||
return (double) work / total * 100.0 * sysconf(_SC_NPROCESSORS_CONF);
|
||||
}
|
||||
|
||||
static bool has_core_dumps()
|
||||
static bool has_core_dump_in_dir(const char *dir, const char *prefix)
|
||||
{
|
||||
DIR *dp = opendir("core");
|
||||
if (NULL == dp) {
|
||||
DIR *dp = opendir(dir);
|
||||
if (dp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (struct dirent *de = NULL; NULL != (de = readdir(dp));) {
|
||||
if (0 == strncmp("core", de->d_name, 4)) {
|
||||
struct dirent *de;
|
||||
bool found = false;
|
||||
while ((de = readdir(dp)) != NULL) {
|
||||
if (strncmp(prefix, de->d_name, strlen(prefix)) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -208,6 +209,46 @@ static bool has_core_dumps()
|
||||
return found;
|
||||
}
|
||||
|
||||
static char *get_core_dir(const char *core_pattern)
|
||||
{
|
||||
char *last_slash = strrchr(core_pattern, '/');
|
||||
if (last_slash != NULL) {
|
||||
static char core_dir[256];
|
||||
ptrdiff_t path_length = last_slash - core_pattern + 1;
|
||||
strncpy(core_dir, core_pattern, path_length);
|
||||
core_dir[path_length] = '\0';
|
||||
return core_dir;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool has_core_dumps()
|
||||
{
|
||||
if (has_core_dump_in_dir("core", "core-neuron")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE *fp = fopen("/proc/sys/kernel/core_pattern", "r");
|
||||
if (fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char core_pattern[256];
|
||||
if (fgets(core_pattern, sizeof(core_pattern), fp) == NULL) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
char *core_dir =
|
||||
(core_pattern[0] == '|') ? "/var/crash/" : get_core_dir(core_pattern);
|
||||
if (core_dir == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return has_core_dump_in_dir(core_dir, "core-neuron");
|
||||
}
|
||||
|
||||
static inline void metrics_unregister_entry(const char *name)
|
||||
{
|
||||
neu_metric_entry_t *e = NULL;
|
||||
@@ -239,10 +280,19 @@ int neu_metric_entries_add(neu_metric_entry_t **entries, const char *name,
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->name = name;
|
||||
entry->type = type;
|
||||
entry->help = help;
|
||||
entry->value = init;
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == type) {
|
||||
// only allocate rolling counter for nonzero time span
|
||||
if (init > 0 && NULL == (entry->rcnt = neu_rolling_counter_new(init))) {
|
||||
free(entry);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
entry->value = init;
|
||||
}
|
||||
|
||||
entry->name = name;
|
||||
entry->type = type;
|
||||
entry->help = help;
|
||||
HASH_ADD_STR(*entries, name, entry);
|
||||
return 0;
|
||||
}
|
||||
@@ -279,9 +329,11 @@ int neu_metrics_register_entry(const char *name, const char *help,
|
||||
neu_metric_entry_t *e = NULL;
|
||||
|
||||
pthread_rwlock_wrlock(&g_metrics_mtx_);
|
||||
// use `value` field as reference counter, initialize to zero
|
||||
// and we don't need to allocate rolling counter for register entries
|
||||
rv = neu_metric_entries_add(&g_metrics_.registered_metrics, name, help,
|
||||
type, 1);
|
||||
if (1 == rv) {
|
||||
type, 0);
|
||||
if (-1 != rv) {
|
||||
HASH_FIND_STR(g_metrics_.registered_metrics, name, e);
|
||||
++e->value;
|
||||
rv = 0;
|
||||
|
||||
+27
-13
@@ -242,21 +242,35 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
case NEU_TYPE_UINT64: {
|
||||
char *op = find_last_character(datatag->address, '#');
|
||||
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = true;
|
||||
if (op != NULL) {
|
||||
char e = 0;
|
||||
sscanf(op, "#%c", &e);
|
||||
char e1 = 0;
|
||||
char e2 = 0;
|
||||
int n = sscanf(op, "#%c%c", &e1, &e2);
|
||||
|
||||
switch (e) {
|
||||
case 'B':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
break;
|
||||
case 'L':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
default:
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
if (n == 2) {
|
||||
if (e1 == 'B' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BB64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'B' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LB64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
} else if (n == 1) {
|
||||
if (e1 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1284,10 +1284,18 @@ int neu_conn_stream_consume(neu_conn_t *conn, void *context,
|
||||
neu_conn_disconnect(conn);
|
||||
break;
|
||||
} else {
|
||||
pthread_mutex_lock(&conn->mtx);
|
||||
if (conn->offset - used < 0) {
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
zlog_warn(conn->param.log, "reset offset: %d, used: %d",
|
||||
conn->offset, used);
|
||||
return -1;
|
||||
}
|
||||
conn->offset -= used;
|
||||
memmove(conn->buf, conn->buf + used, conn->offset);
|
||||
neu_protocol_unpack_buf_init(&protocol_buf, conn->buf,
|
||||
conn->offset);
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1313,10 +1321,18 @@ int neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
|
||||
neu_conn_tcp_server_close_client(conn, fd);
|
||||
break;
|
||||
} else {
|
||||
pthread_mutex_lock(&conn->mtx);
|
||||
if (conn->offset - used < 0) {
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
zlog_warn(conn->param.log, "reset offset: %d, used: %d",
|
||||
conn->offset, used);
|
||||
return -1;
|
||||
}
|
||||
conn->offset -= used;
|
||||
memmove(conn->buf, conn->buf + used, conn->offset);
|
||||
neu_protocol_unpack_buf_init(&protocol_buf, conn->buf,
|
||||
conn->offset);
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,8 +433,10 @@ static void connect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
neu_mqtt_client_t * client = arg;
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
int reason = 0;
|
||||
|
||||
log(notice, "mqtt client connected");
|
||||
nng_pipe_get_int(p, NNG_OPT_MQTT_CONNECT_REASON, &reason);
|
||||
log(notice, "mqtt client connected, reason: %d", reason);
|
||||
|
||||
nng_mtx_lock(client->mtx);
|
||||
// start receiving
|
||||
@@ -459,8 +461,11 @@ static void disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
subscription_t * sub = NULL;
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
int reason = 0;
|
||||
|
||||
nng_pipe_get_int(p, NNG_OPT_MQTT_DISCONNECT_REASON, &reason);
|
||||
log(notice, "mqtt client disconnected, reason: %d", reason);
|
||||
|
||||
log(notice, "mqtt client disconnected");
|
||||
nng_mtx_lock(client->mtx);
|
||||
client->connected = false;
|
||||
cb = client->disconnect_cb;
|
||||
|
||||
+2
-1
@@ -229,7 +229,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (init->state == NEU_NODE_RUNNING_STATE_RUNNING ||
|
||||
if (init->state == NEU_NODE_RUNNING_STATE_READY ||
|
||||
init->state == NEU_NODE_RUNNING_STATE_RUNNING ||
|
||||
init->state == NEU_NODE_RUNNING_STATE_STOPPED) {
|
||||
neu_adapter_t *adapter =
|
||||
neu_node_manager_find(manager->node_manager, init->node);
|
||||
|
||||
@@ -702,9 +702,11 @@ int neu_manager_subscribe(neu_manager_t *manager, const char *app,
|
||||
// guard against empty mqtt topic parameter
|
||||
// this is not an elegant solution due to the current architecture
|
||||
if (params && 0 == strcmp(adapter->module->module_name, "MQTT")) {
|
||||
neu_json_elem_t elem = { .name = "topic", .t = NEU_JSON_STR };
|
||||
neu_parse_param(params, NULL, 1, &elem);
|
||||
if (elem.v.val_str && 0 == strlen(elem.v.val_str)) {
|
||||
neu_json_elem_t elem = { .name = "topic",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = NULL };
|
||||
int ret = neu_parse_param(params, NULL, 1, &elem);
|
||||
if (ret != 0 || (elem.v.val_str && 0 == strlen(elem.v.val_str))) {
|
||||
free(elem.v.val_str);
|
||||
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
}
|
||||
|
||||
+8
-2
@@ -140,9 +140,15 @@ static int decode_object(json_t *root, neu_json_elem_t *ele)
|
||||
case NEU_JSON_INT:
|
||||
ele->v.val_int = json_integer_value(ob);
|
||||
break;
|
||||
case NEU_JSON_STR:
|
||||
ele->v.val_str = strdup(json_string_value(ob));
|
||||
case NEU_JSON_STR: {
|
||||
const char *str = json_string_value(ob);
|
||||
if (str != NULL) {
|
||||
ele->v.val_str = strdup(str);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NEU_JSON_FLOAT:
|
||||
if (json_is_integer(ob)) {
|
||||
ele->v.val_float = (float) json_integer_value(ob);
|
||||
|
||||
@@ -49,10 +49,18 @@ target_include_directories(modbus_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/plugins/modbus)
|
||||
target_link_libraries(modbus_test neuron-base gtest_main gtest pthread zlog)
|
||||
|
||||
add_executable(rolling_counter_test rolling_counter_test.cc)
|
||||
target_include_directories(rolling_counter_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(rolling_counter_test neuron-base gtest_main gtest)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(json_test)
|
||||
gtest_discover_tests(http_test)
|
||||
gtest_discover_tests(jwt_test)
|
||||
gtest_discover_tests(base64_test)
|
||||
gtest_discover_tests(tag_sort_test)
|
||||
gtest_discover_tests(modbus_test)
|
||||
gtest_discover_tests(modbus_test)
|
||||
gtest_discover_tests(rolling_counter_test)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "utils/log.h"
|
||||
#include "utils/rolling_counter.h"
|
||||
|
||||
zlog_category_t *neuron = NULL;
|
||||
TEST(RollingCounterTest, neu_rolling_counter_inc)
|
||||
{
|
||||
uint64_t ts = 0;
|
||||
neu_rolling_counter_t *counter = neu_rolling_counter_new(4000);
|
||||
EXPECT_NE(nullptr, counter);
|
||||
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
ts += 1000;
|
||||
EXPECT_EQ(i, neu_rolling_counter_inc(counter, ts, 1));
|
||||
}
|
||||
|
||||
// wrap around
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
ts += 1000;
|
||||
EXPECT_EQ(4, neu_rolling_counter_inc(counter, ts, 1));
|
||||
}
|
||||
|
||||
// increment without time stamp update
|
||||
EXPECT_EQ(4, neu_rolling_counter_value(counter));
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
EXPECT_EQ(4 + i, neu_rolling_counter_inc(counter, ts, 1));
|
||||
}
|
||||
|
||||
EXPECT_EQ(4 + 10, neu_rolling_counter_value(counter));
|
||||
|
||||
// stale value will be clean
|
||||
ts += 4000;
|
||||
EXPECT_EQ(0, neu_rolling_counter_inc(counter, ts, 0));
|
||||
|
||||
neu_rolling_counter_free(counter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
zlog_init("./config/dev.conf");
|
||||
neuron = zlog_get_category("neuron");
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user