diff options
author | MichaĆ Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com> | 2019-08-07 11:58:31 +0200 |
---|---|---|
committer | Brian Gix <brian.gix@intel.com> | 2019-08-08 15:17:37 -0400 |
commit | bdd0e6c521e89c2bdd64a0708803d4ad266d1586 (patch) | |
tree | f4371349b89f4fc0ffe72a9a4ded6436d4ef91f8 /mesh/mesh-config-json.c | |
parent | 7de0eb5686223e8f8ba80984973a08a2781d3650 (diff) | |
download | bluez-bdd0e6c521e89c2bdd64a0708803d4ad266d1586.tar.gz |
mesh: Move sequence number overcommit to mesh-config-json
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.
Diffstat (limited to 'mesh/mesh-config-json.c')
-rw-r--r-- | mesh/mesh-config-json.c | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c index d49f5226a..036ec9017 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, |