Applied with cosmetic block-comment "style guide" adjustment On Wed, 2019-08-07 at 11:58 +0200, Michał Lowas-Rzechonek wrote: > This confines sequence overcommit logic in mesh-config-json, as other > storages might use a different mechanism to ensure reliability. > > Also, refactored logic to calculate overcommit value to avoid division > by zero when messages are sent too fast. > --- > mesh/mesh-config-json.c | 70 +++++++++++++++++++++++++++++++++++++++-- > mesh/mesh-config.h | 3 +- > mesh/net.c | 18 +++-------- > mesh/node.c | 56 +++------------------------------ > mesh/node.h | 6 ---- > 5 files changed, 78 insertions(+), 75 deletions(-) > > diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c > index d49f5226a..e3a804d35 100644 > --- a/mesh/mesh-config-json.c > +++ b/mesh/mesh-config-json.c > @@ -31,6 +31,8 @@ > #include <string.h> > #include <unistd.h> > > +#include <sys/time.h> > + > #include <ell/ell.h> > #include <json-c/json.h> > > @@ -38,12 +40,19 @@ > #include "mesh/util.h" > #include "mesh/mesh-config.h" > > +/* To prevent local node JSON cache thrashing, minimum update times */ > +#define MIN_SEQ_CACHE_TRIGGER 32 > +#define MIN_SEQ_CACHE_VALUE (2 * 32) > +#define MIN_SEQ_CACHE_TIME (5 * 60) > + > #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095)) > > struct mesh_config { > json_object *jnode; > char *node_dir_path; > uint8_t uuid[16]; > + uint32_t write_seq; > + struct timeval write_time; > }; > > struct write_info { > @@ -1708,6 +1717,8 @@ static struct mesh_config *create_config(const char *cfg_path, > cfg->jnode = jnode; > memcpy(cfg->uuid, uuid, 16); > cfg->node_dir_path = l_strdup(cfg_path); > + cfg->write_seq = node->seq_number; > + gettimeofday(&cfg->write_time, NULL); > > return cfg; > } > @@ -2020,12 +2031,59 @@ bool mesh_config_model_sub_del_all(struct mesh_config *cfg, uint16_t addr, > return save_config(cfg->jnode, cfg->node_dir_path); > } > > -bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq) > +bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, > + bool cache) > { > - if (!cfg || !write_int(cfg->jnode, "sequenceNumber", seq)) > + int value; > + uint32_t cached = 0; > + > + if (!cfg) > return false; > > - mesh_config_save(cfg, false, NULL, NULL); > + if (!cache) { > + if (!write_int(cfg->jnode, "sequenceNumber", seq)) > + return false; > + > + return mesh_config_save(cfg, true, NULL, NULL); > + } > + > + if (get_int(cfg->jnode, "sequenceNumber", &value)) > + cached = (uint32_t)value; > + > + /* > + * When sequence number approaches value stored on disk, calculate > + * average time between sequence number updates, then overcommit the > + * sequence number by MIN_SEQ_CACHE_TIME seconds worth of traffic or > + * MIN_SEQ_CACHE_VALUE (whichever is greater) to avoid frequent writes > + * to disk and to protect against crashes. > + * > + * The real value will be saved when daemon shuts down properly. > + */ > + if (seq + MIN_SEQ_CACHE_TRIGGER >= cached) { > + struct timeval now; > + struct timeval elapsed; > + uint64_t elapsed_ms; > + > + gettimeofday(&now, NULL); > + timersub(&now, &cfg->write_time, &elapsed); > + elapsed_ms = elapsed.tv_sec * 1000 + elapsed.tv_usec / 1000; > + > + cached = seq + (seq - cfg->write_seq) * > + 1000 * MIN_SEQ_CACHE_TIME / elapsed_ms; > + > + if (cached < seq + MIN_SEQ_CACHE_VALUE) > + cached = seq + MIN_SEQ_CACHE_VALUE; > + > + l_debug("Seq Cache: %d -> %d", seq, cached); > + > + cfg->write_seq = seq; > + > + if (!write_int(cfg->jnode, "sequenceNumber", cached)) > + return false; > + > + return mesh_config_save(cfg, false, NULL, NULL); > + } > + > return true; > } > > @@ -2089,6 +2147,9 @@ static bool load_node(const char *fname, const uint8_t uuid[16], > cfg->jnode = jnode; > memcpy(cfg->uuid, uuid, 16); > cfg->node_dir_path = l_strdup(fname); > + cfg->write_seq = node.seq_number; > + gettimeofday(&cfg->write_time, NULL); > + > result = cb(&node, uuid, cfg, user_data); > > if (!result) { > @@ -2147,10 +2208,13 @@ static void idle_save_config(void *user_data) > l_free(fname_tmp); > l_free(fname_bak); > > + gettimeofday(&info->cfg->write_time, NULL); > + > if (info->cb) > info->cb(info->user_data, result); > > l_free(info); > + > } > > bool mesh_config_save(struct mesh_config *cfg, bool no_wait, > diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h > index 44e3b3ad6..4172e794b 100644 > --- a/mesh/mesh-config.h > +++ b/mesh/mesh-config.h > @@ -128,7 +128,8 @@ bool mesh_config_write_network_key(struct mesh_config *cfg, uint16_t idx, > uint8_t *key, uint8_t *new_key, int phase); > bool mesh_config_write_app_key(struct mesh_config *cfg, uint16_t net_idx, > uint16_t app_idx, uint8_t *key, uint8_t *new_key); > -bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq); > +bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, > + bool cache); > bool mesh_config_write_unicast(struct mesh_config *cfg, uint16_t unicast); > bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode, > uint8_t count, uint16_t interval); > diff --git a/mesh/net.c b/mesh/net.c > index 7c92cfd5e..7c4049e0e 100644 > --- a/mesh/net.c > +++ b/mesh/net.c > @@ -133,7 +133,6 @@ struct mesh_net { > uint32_t instant; /* Controller Instant of recent Rx */ > uint32_t iv_index; > uint32_t seq_num; > - uint32_t cached_seq_num; > uint16_t src_addr; > uint16_t last_addr; > uint16_t friend_addr; > @@ -503,17 +502,8 @@ void mesh_friend_sub_del(struct mesh_net *net, uint16_t lpn, > > uint32_t mesh_net_next_seq_num(struct mesh_net *net) > { > - uint32_t seq = net->seq_num; > - > - net->seq_num++; > - > - /* Periodically store advanced sequence number */ > - if (net->seq_num + MIN_SEQ_TRIGGER >= net->cached_seq_num) { > - net->cached_seq_num = net->seq_num + > - node_seq_cache(net->node); > - node_set_sequence_number(net->node, net->cached_seq_num); > - } > - > + uint32_t seq = net->seq_num++; > + node_set_sequence_number(net->node, net->seq_num); > return seq; > } > > @@ -722,12 +712,12 @@ void mesh_net_free(struct mesh_net *net) > l_free(net); > } > > -bool mesh_net_set_seq_num(struct mesh_net *net, uint32_t number) > +bool mesh_net_set_seq_num(struct mesh_net *net, uint32_t seq) > { > if (!net) > return false; > > - net->cached_seq_num = net->seq_num = number; > + net->seq_num = seq; > > return true; > } > diff --git a/mesh/node.c b/mesh/node.c > index bff73cfc7..e7e58d9a7 100644 > --- a/mesh/node.c > +++ b/mesh/node.c > @@ -25,8 +25,6 @@ > #include <dirent.h> > #include <stdio.h> > > -#include <sys/time.h> > - > #include <ell/ell.h> > > #include "mesh/mesh-defs.h" > @@ -90,9 +88,7 @@ struct mesh_node { > struct mesh_config *cfg; > char *storage_dir; > uint32_t disc_watch; > - time_t upd_sec; > uint32_t seq_number; > - uint32_t seq_min_cache; > bool provisioner; > uint16_t primary; > struct node_composition *comp; > @@ -560,15 +556,11 @@ static void cleanup_node(void *data) > struct mesh_node *node = data; > struct mesh_net *net = node->net; > > - /* Save local node configuration */ > - if (node->cfg) { > - > - /* Preserve the last sequence number */ > + /* Preserve the last sequence number */ > + if (node->cfg) > mesh_config_write_seq_number(node->cfg, > - mesh_net_get_seq_num(net)); > - > - mesh_config_save(node->cfg, true, NULL, NULL); > - } > + mesh_net_get_seq_num(net), > + false); > > free_node_resources(node); > } > @@ -704,42 +696,12 @@ bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl) > > bool node_set_sequence_number(struct mesh_node *node, uint32_t seq) > { > - struct timeval write_time; > - > if (!node) > return false; > > node->seq_number = seq; > > - /* > - * Holistically determine worst case 5 minute sequence consumption > - * so that we typically (once we reach a steady state) rewrite the > - * local node file with a new seq cache value no more than once every > - * five minutes (or more) > - */ > - gettimeofday(&write_time, NULL); > - if (node->upd_sec) { > - uint32_t elapsed = write_time.tv_sec - node->upd_sec; > - > - if (elapsed < MIN_SEQ_CACHE_TIME) { > - uint32_t ideal = node->seq_min_cache; > - > - l_debug("Old Seq Cache: %d", node->seq_min_cache); > - > - ideal *= (MIN_SEQ_CACHE_TIME / elapsed); > - > - if (ideal > node->seq_min_cache + MIN_SEQ_CACHE) > - node->seq_min_cache = ideal; > - else > - node->seq_min_cache += MIN_SEQ_CACHE; > - > - l_debug("New Seq Cache: %d", node->seq_min_cache); > - } > - } > - > - node->upd_sec = write_time.tv_sec; > - > - return mesh_config_write_seq_number(node->cfg, seq); > + return mesh_config_write_seq_number(node->cfg, node->seq_number, true); > } > > uint32_t node_get_sequence_number(struct mesh_node *node) > @@ -750,14 +712,6 @@ uint32_t node_get_sequence_number(struct mesh_node *node) > return node->seq_number; > } > > -uint32_t node_seq_cache(struct mesh_node *node) > -{ > - if (node->seq_min_cache < MIN_SEQ_CACHE) > - node->seq_min_cache = MIN_SEQ_CACHE; > - > - return node->seq_min_cache; > -} > - > int node_get_element_idx(struct mesh_node *node, uint16_t ele_addr) > { > uint16_t addr; > diff --git a/mesh/node.h b/mesh/node.h > index a4cac028d..be57d5e67 100644 > --- a/mesh/node.h > +++ b/mesh/node.h > @@ -24,11 +24,6 @@ struct mesh_agent; > struct mesh_config; > struct mesh_config_node; > > -/* To prevent local node JSON cache thrashing, minimum update times */ > -#define MIN_SEQ_TRIGGER 32 > -#define MIN_SEQ_CACHE (2*MIN_SEQ_TRIGGER) > -#define MIN_SEQ_CACHE_TIME (5*60) > - > typedef void (*node_ready_func_t) (void *user_data, int status, > struct mesh_node *node); > > @@ -82,7 +77,6 @@ bool node_beacon_mode_set(struct mesh_node *node, bool enable); > uint8_t node_beacon_mode_get(struct mesh_node *node); > bool node_friend_mode_set(struct mesh_node *node, bool enable); > uint8_t node_friend_mode_get(struct mesh_node *node); > -uint32_t node_seq_cache(struct mesh_node *node); > const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx); > const char *node_get_owner(struct mesh_node *node); > const char *node_get_app_path(struct mesh_node *node);