@cryptotaxi247 / netdata-1 / commits / 81e2f8da6

Reuse the SN_EXISTS bit to track anomaly status. (#11154)

* Replace all usages of SN_EXISTS with SN_DEFAULT_FLAGS. * Remove references to SN_NOT_EXISTS in comments. * Replace raw zero constant with SN_EMPTY_SLOT. * Use get_storage_number_flags only in storage_number.{c,h} * Compare against SN_EMPTY_SLOT to check if a storage_number exists. This is safe because: 1. rrdset_done_interpolate() is the only place where we call store_metric(), 2. All store_metric() calls, except for one, store an SN_EMPTY_SLOT value. 3. When we are not storing an SN_EMPTY_SLOT value, the flags that we pass to pack_storage_number() can be either SN_EXISTS *or* SN_EXISTS_RESET. * Compare only the SN_EXISTS_RESET bit to find reset values. * Remove get_storage_number_flags from storage_number.h * Do not set storage_number flags outside of rrdset_done_interpolate(). This is a NFC intended to limit the scope of storage_number flags processing to just one function. * Set reset bit without overwriting the rest of the flags. * Rename SN_EXISTS to SN_ANOMALY_BIT. * Use GOTOs in pack_storage_number to return from a single place. * Teach pack_storage_number how to handle anomalous zero values. Up until now, a storage_number had always either the SN_EXISTS or SN_EXISTS_RESET bit set. This meant that it was not possible for any packed storage_number to compare equal to the SN_EMPTY_SLOT. However, the SN_ANOMALY_BIT can be set to zero. This is fine for every value other than the anomalous 0 value, because it would compare equal to SN_EMPTY_SLOT. We address this issue by mapping the anomalous zero value to SN_EXISTS_100 (a number which was not possible to generate with the previous versions of the agent, ie. it won't exist in older dbengine files). This change was tested manually by intentionally flipping the anomaly bit for odd/even iterations in rrdset_done_interpolate. Prior to this change, charts whose dimensions had 0 values, where showing up in the dashboard as gaps (SN_EMPTY_SLOT), whereas with this commit the values are displayed correctly.

vkalintiris committed Oct 22, 2021 at 17:35 UTC 81e2f8da6513143f59cf0b8b6b0c0370302fc376
8 files changed +65 -57
daemon/unit_test.c
+10 -23
@@ -97,7 +97,7 @@ static int check_rrdcalc_comparisons(void) {
97
98 int check_storage_number(calculated_number n, int debug) {
99 char buffer[100];
100 - uint32_t flags = SN_EXISTS;
100 + uint32_t flags = SN_DEFAULT_FLAGS;
101
102 storage_number s = pack_storage_number(n, flags);
103 calculated_number d = unpack_storage_number(s);
@@ -150,7 +150,7 @@ calculated_number storage_number_min(calculated_number n) {
150 do {
151 last = n;
152 n /= 2.0;
153 - storage_number t = pack_storage_number(n, SN_EXISTS);
153 + storage_number t = pack_storage_number(n, SN_DEFAULT_FLAGS);
154 r = unpack_storage_number(t);
155 } while(r != 0.0 && r != last);
156
@@ -263,7 +263,7 @@ void benchmark_storage_number(int loop, int multiplier) {
263 n *= multiplier;
264 if(n > storage_number_positive_max) n = storage_number_positive_min;
265
266 - s = pack_storage_number(n, SN_EXISTS);
266 + s = pack_storage_number(n, SN_DEFAULT_FLAGS);
267 d = unpack_storage_number(s);
268 print_calculated_number(buffer, d);
269 }
@@ -289,25 +289,12 @@ void benchmark_storage_number(int loop, int multiplier) {
289 }
290
291 static int check_storage_number_exists() {
292 - uint32_t flags;
293 -
294 -
295 - for(flags = 0; flags < 7 ; flags++) {
296 - if(get_storage_number_flags(flags << 24) != flags << 24) {
297 - fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
298 - return 1;
299 - }
300 - }
301 -
302 - flags = SN_EXISTS;
292 + uint32_t flags = SN_DEFAULT_FLAGS;
293 calculated_number n = 0.0;
294
295 storage_number s = pack_storage_number(n, flags);
296 calculated_number d = unpack_storage_number(s);
307 - if(get_storage_number_flags(s) != flags) {
308 - fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
309 - return 1;
310 - }
297 +
298 if(n != d) {
299 fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
300 return 1;
@@ -1192,7 +1179,7 @@ int run_test(struct test *test)
1179 unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
1180 for(c = 0 ; c < max ; c++) {
1181 calculated_number v = unpack_storage_number(rd->values[c]);
1195 - calculated_number n = unpack_storage_number(pack_storage_number(test->results[c], SN_EXISTS));
1182 + calculated_number n = unpack_storage_number(pack_storage_number(test->results[c], SN_DEFAULT_FLAGS));
1183 int same = (calculated_number_round(v * 10000000.0) == calculated_number_round(n * 10000000.0))?1:0;
1184 fprintf(stderr, " %s/%s: checking position %lu (at %lu secs), expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n",
1185 test->name, rd->name, c+1,
@@ -1667,7 +1654,7 @@ static int test_dbengine_check_metrics(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DI
1654 for (k = 0; k < QUERY_BATCH; ++k) {
1655 last = ((collected_number)i * DIMS) * REGION_POINTS[current_region] +
1656 j * REGION_POINTS[current_region] + c + k;
1670 - expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_EXISTS));
1657 + expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_DEFAULT_FLAGS));
1658
1659 n = rd[i][j]->state->query_ops.next_metric(&handle, &time_retrieved);
1660 value = unpack_storage_number(n);
@@ -1725,7 +1712,7 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
1712 assert(rd[i][j] == d);
1713
1714 last = i * DIMS * REGION_POINTS[current_region] + j * REGION_POINTS[current_region] + c;
1728 - expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_EXISTS));
1715 + expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_DEFAULT_FLAGS));
1716
1717 same = (calculated_number_round(value) == calculated_number_round(expected)) ? 1 : 0;
1718 if(!same) {
@@ -1847,7 +1834,7 @@ int test_dbengine(void)
1834 assert(rd[i][j] == d);
1835
1836 collected_number last = i * DIMS * REGION_POINTS[current_region] + j * REGION_POINTS[current_region] + c - point_offset;
1850 - calculated_number expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_EXISTS));
1837 + calculated_number expected = unpack_storage_number(pack_storage_number((calculated_number)last, SN_DEFAULT_FLAGS));
1838
1839 uint8_t same = (calculated_number_round(value) == calculated_number_round(expected)) ? 1 : 0;
1840 if(!same) {
@@ -2076,7 +2063,7 @@ static void query_dbengine_chart(void *arg)
2063 ++thread_info->queries_nr;
2064 for (time_now = time_after ; time_now <= time_before ; time_now += update_every) {
2065 generatedv = generate_dbengine_chart_value(i, j, time_now);
2079 - expected = unpack_storage_number(pack_storage_number((calculated_number) generatedv, SN_EXISTS));
2066 + expected = unpack_storage_number(pack_storage_number((calculated_number) generatedv, SN_DEFAULT_FLAGS));
2067
2068 if (unlikely(rd->state->query_ops.is_finished(&handle))) {
2069 if (!thread_info->delete_old_data) { /* data validation only when we don't delete */
database/engine/rrdengine.c
+1 -1
@@ -336,7 +336,7 @@ after_crc_check:
336 /* care, we don't hold the descriptor mutex */
337 if (have_read_error) {
338 /* Applications should make sure NULL values match 0 as does SN_EMPTY_SLOT */
339 - memset(page, 0, descr->page_length);
339 + memset(page, SN_EMPTY_SLOT, descr->page_length);
340 } else if (RRD_NO_COMPRESSION == header->compression_algorithm) {
341 (void) memcpy(page, xt_io_descr->buf + payload_offset + page_offset, descr->page_length);
342 } else {
database/rrddim.c
+1 -1
@@ -119,7 +119,7 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
119 // RRDDIM legacy data collection functions
120
121 static void rrddim_collect_init(RRDDIM *rd) {
122 - rd->values[rd->rrdset->current_entry] = SN_EMPTY_SLOT; // pack_storage_number(0, SN_NOT_EXISTS);
122 + rd->values[rd->rrdset->current_entry] = SN_EMPTY_SLOT;
123 }
124 static void rrddim_collect_store_metric(RRDDIM *rd, usec_t point_in_time, storage_number number) {
125 (void)point_in_time;
database/rrdset.c
+16 -12
@@ -1120,7 +1120,7 @@ static inline size_t rrdset_done_interpolate(
1120 , usec_t last_collect_ut
1121 , usec_t now_collect_ut
1122 , char store_this_entry
1123 - , uint32_t storage_flags
1123 + , uint32_t has_reset_value
1124 ) {
1125 RRDDIM *rd;
1126
@@ -1135,6 +1135,11 @@ static inline size_t rrdset_done_interpolate(
1135 size_t counter = st->counter;
1136 long current_entry = st->current_entry;
1137
1138 + uint32_t storage_flags = SN_DEFAULT_FLAGS;
1139 +
1140 + if (has_reset_value)
1141 + storage_flags |= SN_EXISTS_RESET;
1142 +
1143 for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
1144
1145 #ifdef NETDATA_INTERNAL_CHECKS
@@ -1232,8 +1237,8 @@ static inline size_t rrdset_done_interpolate(
1237 }
1238
1239 if(unlikely(!store_this_entry)) {
1235 - rd->state->collect_ops.store_metric(rd, next_store_ut, SN_EMPTY_SLOT); //pack_storage_number(0, SN_NOT_EXISTS)
1236 -// rd->values[current_entry] = SN_EMPTY_SLOT; //pack_storage_number(0, SN_NOT_EXISTS);
1240 + rd->state->collect_ops.store_metric(rd, next_store_ut, SN_EMPTY_SLOT);
1241 +// rd->values[current_entry] = SN_EMPTY_SLOT;
1242 continue;
1243 }
1244
@@ -1261,8 +1266,8 @@ static inline size_t rrdset_done_interpolate(
1266 );
1267 #endif
1268
1264 -// rd->values[current_entry] = SN_EMPTY_SLOT; // pack_storage_number(0, SN_NOT_EXISTS);
1265 - rd->state->collect_ops.store_metric(rd, next_store_ut, SN_EMPTY_SLOT); //pack_storage_number(0, SN_NOT_EXISTS)
1269 +// rd->values[current_entry] = SN_EMPTY_SLOT;
1270 + rd->state->collect_ops.store_metric(rd, next_store_ut, SN_EMPTY_SLOT);
1271 rd->last_stored_value = NAN;
1272 }
1273
@@ -1274,11 +1279,10 @@ static inline size_t rrdset_done_interpolate(
1279 calculated_number t2 = unpack_storage_number(rd->values[current_entry]);
1280
1281 calculated_number accuracy = accuracy_loss(t1, t2);
1277 - debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
1282 + debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
1283 , st->id, rd->name
1284 , current_entry
1285 , t2
1281 - , get_storage_number_flags(rd->values[current_entry])
1286 , t1
1287 , accuracy
1288 , (accuracy > ACCURACY_LOSS_ACCEPTED_PERCENT) ? " **TOO BIG** " : ""
@@ -1300,7 +1304,7 @@ static inline size_t rrdset_done_interpolate(
1304 #endif
1305 }
1306 // reset the storage flags for the next point, if any;
1303 - storage_flags = SN_EXISTS;
1307 + storage_flags = SN_DEFAULT_FLAGS;
1308
1309 st->counter = ++counter;
1310 st->current_entry = current_entry = ((current_entry + 1) >= st->entries) ? 0 : current_entry + 1;
@@ -1540,7 +1544,7 @@ after_first_database_work:
1544 st->collected_total += rd->collected_value;
1545 }
1546
1543 - uint32_t storage_flags = SN_EXISTS;
1547 + uint32_t has_reset_value = 0;
1548
1549 // process all dimensions to calculate their values
1550 // based on the collected figures only
@@ -1637,7 +1641,7 @@ after_first_database_work:
1641 , rd->collected_value);
1642
1643 if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
1640 - storage_flags = SN_EXISTS_RESET;
1644 + has_reset_value = 1;
1645
1646 uint64_t last = (uint64_t)rd->last_collected_value;
1647 uint64_t new = (uint64_t)rd->collected_value;
@@ -1708,7 +1712,7 @@ after_first_database_work:
1712 );
1713
1714 if(!(rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)))
1711 - storage_flags = SN_EXISTS_RESET;
1715 + has_reset_value = 1;
1716
1717 rd->last_collected_value = rd->collected_value;
1718 }
@@ -1787,7 +1791,7 @@ after_first_database_work:
1791 , last_collect_ut
1792 , now_collect_ut
1793 , store_this_entry
1790 - , storage_flags
1794 + , has_reset_value
1795 );
1796
1797 after_second_database_work:
exporting/tests/test_exporting_engine.c
+10 -10
@@ -312,12 +312,12 @@ static void test_exporting_calculate_value_from_stored_data(void **state)
312 expect_function_call(__mock_rrddim_query_is_finished);
313 will_return(__mock_rrddim_query_is_finished, 0);
314 expect_function_call(__mock_rrddim_query_next_metric);
315 - will_return(__mock_rrddim_query_next_metric, pack_storage_number(27, SN_EXISTS));
315 + will_return(__mock_rrddim_query_next_metric, pack_storage_number(27, SN_DEFAULT_FLAGS));
316
317 expect_function_call(__mock_rrddim_query_is_finished);
318 will_return(__mock_rrddim_query_is_finished, 0);
319 expect_function_call(__mock_rrddim_query_next_metric);
320 - will_return(__mock_rrddim_query_next_metric, pack_storage_number(45, SN_EXISTS));
320 + will_return(__mock_rrddim_query_next_metric, pack_storage_number(45, SN_DEFAULT_FLAGS));
321
322 expect_function_call(__mock_rrddim_query_is_finished);
323 will_return(__mock_rrddim_query_is_finished, 1);
@@ -431,7 +431,7 @@ static void test_format_dimension_stored_graphite_plaintext(void **state)
431 struct engine *engine = *state;
432
433 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
434 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
434 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
435
436 RRDDIM *rd = localhost->rrdset_root->dimensions;
437 assert_int_equal(format_dimension_stored_graphite_plaintext(engine->instance_root, rd), 0);
@@ -459,7 +459,7 @@ static void test_format_dimension_stored_json_plaintext(void **state)
459 struct engine *engine = *state;
460
461 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
462 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
462 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
463
464 RRDDIM *rd = localhost->rrdset_root->dimensions;
465 assert_int_equal(format_dimension_stored_json_plaintext(engine->instance_root, rd), 0);
@@ -487,7 +487,7 @@ static void test_format_dimension_stored_opentsdb_telnet(void **state)
487 struct engine *engine = *state;
488
489 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
490 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
490 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
491
492 RRDDIM *rd = localhost->rrdset_root->dimensions;
493 assert_int_equal(format_dimension_stored_opentsdb_telnet(engine->instance_root, rd), 0);
@@ -515,7 +515,7 @@ static void test_format_dimension_stored_opentsdb_http(void **state)
515 struct engine *engine = *state;
516
517 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
518 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
518 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
519
520 RRDDIM *rd = localhost->rrdset_root->dimensions;
521 assert_int_equal(format_dimension_stored_opentsdb_http(engine->instance_root, rd), 0);
@@ -1070,7 +1070,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1070 will_return(__wrap_now_realtime_sec, 2);
1071
1072 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1073 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1073 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
1074
1075 rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(localhost, buffer, "test_server", "test_prefix", 0, 0);
1076
@@ -1087,7 +1087,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1087 will_return(__wrap_now_realtime_sec, 2);
1088
1089 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1090 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1090 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
1091
1092 rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
1093 localhost, buffer, "test_server", "test_prefix", 0, PROMETHEUS_OUTPUT_NAMES | PROMETHEUS_OUTPUT_TYPES);
@@ -1106,7 +1106,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1106 will_return(__wrap_now_realtime_sec, 2);
1107
1108 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1109 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1109 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
1110
1111 rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(localhost, buffer, "test_server", "test_prefix", 0, 0);
1112
@@ -1265,7 +1265,7 @@ static void test_format_dimension_prometheus_remote_write(void **state)
1265 RRDDIM *rd = localhost->rrdset_root->dimensions;
1266
1267 expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1268 - will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1268 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_DEFAULT_FLAGS));
1269
1270 expect_function_call(__wrap_add_metric);
1271 expect_value(__wrap_add_metric, write_request_p, 0xff);
libnetdata/storage_number/storage_number.c
+14 -4
@@ -2,17 +2,23 @@
2
3 #include "../libnetdata.h"
4
5 +#define get_storage_number_flags(value) \
6 + ((((storage_number)(value)) & (1 << 24)) | \
7 + (((storage_number)(value)) & (1 << 25)) | \
8 + (((storage_number)(value)) & (1 << 26)))
9 +
10 storage_number pack_storage_number(calculated_number value, uint32_t flags) {
11 // bit 32 = sign 0:positive, 1:negative
12 // bit 31 = 0:divide, 1:multiply
13 // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
14 // bit 27 SN_EXISTS_100
15 // bit 26 SN_EXISTS_RESET
11 - // bit 25 SN_EXISTS
16 + // bit 25 SN_ANOMALY_BIT = 0: anomalous, 1: not anomalous
17 // bit 24 to bit 1 = the value
18
19 storage_number r = get_storage_number_flags(flags);
15 - if(!value) return r;
20 + if(!value)
21 + goto RET_SN;
22
23 int m = 0;
24 calculated_number n = value, factor = 10;
@@ -47,7 +53,7 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags) {
53 error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
54 #endif
55 r += 0x00ffffff;
50 - return r;
56 + goto RET_SN;
57 }
58 }
59 else {
@@ -78,6 +84,10 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags) {
84 r += (storage_number)n;
85 #endif
86
87 +RET_SN:
88 + if (r == SN_EMPTY_SLOT)
89 + r = SN_ANOMALOUS_ZERO;
90 +
91 return r;
92 }
93
@@ -100,7 +110,7 @@ calculated_number unpack_storage_number(storage_number value) {
110 factor = 100;
111
112 // bit 26 SN_EXISTS_RESET
103 - // bit 25 SN_EXISTS
113 + // bit 25 SN_ANOMALY_BIT
114
115 // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
116 int mul = (value & ((1<<29)|(1<<28)|(1<<27))) >> 27;
libnetdata/storage_number/storage_number.h
+12 -5
@@ -60,17 +60,24 @@ typedef long double collected_number;
60 typedef uint32_t storage_number;
61 #define STORAGE_NUMBER_FORMAT "%u"
62
63 -#define SN_EXISTS (1 << 24) // the value exists
63 +#define SN_ANOMALY_BIT (1 << 24) // the anomaly bit of the value
64 #define SN_EXISTS_RESET (1 << 25) // the value has been overflown
65 #define SN_EXISTS_100 (1 << 26) // very large value (multiplier is 100 instead of 10)
66
67 -// extract the flags
68 -#define get_storage_number_flags(value) ((((storage_number)(value)) & (1 << 24)) | (((storage_number)(value)) & (1 << 25)) | (((storage_number)(value)) & (1 << 26)))
67 +#define SN_DEFAULT_FLAGS SN_ANOMALY_BIT
68 +
69 #define SN_EMPTY_SLOT 0x00000000
70
71 +// When the calculated number is zero and the value is anomalous (ie. it's bit
72 +// is zero) we want to return a storage_number representation that is
73 +// different from the empty slot. We achieve this by mapping zero to
74 +// SN_EXISTS_100. Unpacking the SN_EXISTS_100 value will return zero because
75 +// its fraction field (as well as its exponent factor field) will be zero.
76 +#define SN_ANOMALOUS_ZERO SN_EXISTS_100
77 +
78 // checks
72 -#define does_storage_number_exist(value) ((get_storage_number_flags(value) != 0)?1:0)
73 -#define did_storage_number_reset(value) ((get_storage_number_flags(value) == SN_EXISTS_RESET)?1:0)
79 +#define does_storage_number_exist(value) (((storage_number) (value)) != SN_EMPTY_SLOT)
80 +#define did_storage_number_reset(value) ((((storage_number) (value)) & SN_EXISTS_RESET) != 0)
81
82 storage_number pack_storage_number(calculated_number value, uint32_t flags);
83 calculated_number unpack_storage_number(storage_number value);
libnetdata/storage_number/tests/test_storage_number.c
+1 -1
@@ -38,7 +38,7 @@ static void test_number_printing(void **state)
38 print_calculated_number(value, -9999.9999999);
39 assert_string_equal(value, "-9999.9999999");
40
41 - print_calculated_number(value, unpack_storage_number(pack_storage_number(16.777218L, SN_EXISTS)));
41 + print_calculated_number(value, unpack_storage_number(pack_storage_number(16.777218L, SN_DEFAULT_FLAGS)));
42 assert_string_equal(value, "16.77722");
43 }
44