page.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "page.h"
  3. #include "libnetdata/libnetdata.h"
  4. typedef enum __attribute__((packed)) {
  5. PAGE_OPTION_ALL_VALUES_EMPTY = (1 << 0),
  6. } PAGE_OPTIONS;
  7. typedef enum __attribute__((packed)) {
  8. PGD_STATE_CREATED_FROM_COLLECTOR = (1 << 0),
  9. PGD_STATE_CREATED_FROM_DISK = (1 << 1),
  10. PGD_STATE_SCHEDULED_FOR_FLUSHING = (1 << 2),
  11. PGD_STATE_FLUSHED_TO_DISK = (1 << 3),
  12. } PGD_STATES;
  13. typedef struct {
  14. uint8_t *data;
  15. uint32_t size;
  16. } page_raw_t;
  17. typedef struct {
  18. size_t num_buffers;
  19. gorilla_writer_t *writer;
  20. int aral_index;
  21. } page_gorilla_t;
  22. struct pgd {
  23. // the page type
  24. uint8_t type;
  25. // options related to the page
  26. PAGE_OPTIONS options;
  27. PGD_STATES states;
  28. // the uses number of slots in the page
  29. uint32_t used;
  30. // the total number of slots available in the page
  31. uint32_t slots;
  32. union {
  33. page_raw_t raw;
  34. page_gorilla_t gorilla;
  35. };
  36. };
  37. // ----------------------------------------------------------------------------
  38. // memory management
  39. struct {
  40. ARAL *aral_pgd;
  41. ARAL *aral_data[RRD_STORAGE_TIERS];
  42. ARAL *aral_gorilla_buffer[4];
  43. ARAL *aral_gorilla_writer[4];
  44. } pgd_alloc_globals = {};
  45. static ARAL *pgd_aral_data_lookup(size_t size)
  46. {
  47. for (size_t tier = 0; tier < storage_tiers; tier++)
  48. if (size == tier_page_size[tier])
  49. return pgd_alloc_globals.aral_data[tier];
  50. return NULL;
  51. }
  52. void pgd_init_arals(void)
  53. {
  54. // pgd aral
  55. {
  56. char buf[20 + 1];
  57. snprintfz(buf, sizeof(buf) - 1, "pgd");
  58. // FIXME: add stats
  59. pgd_alloc_globals.aral_pgd = aral_create(
  60. buf,
  61. sizeof(struct pgd),
  62. 64,
  63. 512 * (sizeof(struct pgd)),
  64. pgc_aral_statistics(),
  65. NULL, NULL, false, false);
  66. }
  67. // tier page aral
  68. {
  69. for (size_t i = storage_tiers; i > 0 ;i--)
  70. {
  71. size_t tier = storage_tiers - i;
  72. char buf[20 + 1];
  73. snprintfz(buf, sizeof(buf) - 1, "tier%zu-pages", tier);
  74. pgd_alloc_globals.aral_data[tier] = aral_create(
  75. buf,
  76. tier_page_size[tier],
  77. 64,
  78. 512 * (tier_page_size[tier]),
  79. pgc_aral_statistics(),
  80. NULL, NULL, false, false);
  81. }
  82. }
  83. // gorilla buffers aral
  84. for (size_t i = 0; i != 4; i++) {
  85. char buf[20 + 1];
  86. snprintfz(buf, sizeof(buf) - 1, "gbuffer-%zu", i);
  87. // FIXME: add stats
  88. pgd_alloc_globals.aral_gorilla_buffer[i] = aral_create(
  89. buf,
  90. GORILLA_BUFFER_SIZE,
  91. 64,
  92. 512 * GORILLA_BUFFER_SIZE,
  93. pgc_aral_statistics(),
  94. NULL, NULL, false, false);
  95. }
  96. // gorilla writers aral
  97. for (size_t i = 0; i != 4; i++) {
  98. char buf[20 + 1];
  99. snprintfz(buf, sizeof(buf) - 1, "gwriter-%zu", i);
  100. // FIXME: add stats
  101. pgd_alloc_globals.aral_gorilla_writer[i] = aral_create(
  102. buf,
  103. sizeof(gorilla_writer_t),
  104. 64,
  105. 512 * sizeof(gorilla_writer_t),
  106. pgc_aral_statistics(),
  107. NULL, NULL, false, false);
  108. }
  109. }
  110. static void *pgd_data_aral_alloc(size_t size)
  111. {
  112. ARAL *ar = pgd_aral_data_lookup(size);
  113. if (!ar)
  114. return mallocz(size);
  115. else
  116. return aral_mallocz(ar);
  117. }
  118. static void pgd_data_aral_free(void *page, size_t size)
  119. {
  120. ARAL *ar = pgd_aral_data_lookup(size);
  121. if (!ar)
  122. freez(page);
  123. else
  124. aral_freez(ar, page);
  125. }
  126. // ----------------------------------------------------------------------------
  127. // management api
  128. PGD *pgd_create(uint8_t type, uint32_t slots)
  129. {
  130. PGD *pg = aral_mallocz(pgd_alloc_globals.aral_pgd);
  131. pg->type = type;
  132. pg->used = 0;
  133. pg->slots = slots;
  134. pg->options = PAGE_OPTION_ALL_VALUES_EMPTY;
  135. pg->states = PGD_STATE_CREATED_FROM_COLLECTOR;
  136. switch (type) {
  137. case PAGE_METRICS:
  138. case PAGE_TIER: {
  139. uint32_t size = slots * page_type_size[type];
  140. internal_fatal(!size || slots == 1,
  141. "DBENGINE: invalid number of slots (%u) or page type (%u)", slots, type);
  142. pg->raw.size = size;
  143. pg->raw.data = pgd_data_aral_alloc(size);
  144. break;
  145. }
  146. case PAGE_GORILLA_METRICS: {
  147. internal_fatal(slots == 1,
  148. "DBENGINE: invalid number of slots (%u) or page type (%u)", slots, type);
  149. pg->slots = 8 * GORILLA_BUFFER_SLOTS;
  150. // allocate new gorilla writer
  151. pg->gorilla.aral_index = gettid() % 4;
  152. pg->gorilla.writer = aral_mallocz(pgd_alloc_globals.aral_gorilla_writer[pg->gorilla.aral_index]);
  153. // allocate new gorilla buffer
  154. gorilla_buffer_t *gbuf = aral_mallocz(pgd_alloc_globals.aral_gorilla_buffer[pg->gorilla.aral_index]);
  155. memset(gbuf, 0, GORILLA_BUFFER_SIZE);
  156. global_statistics_gorilla_buffer_add_hot();
  157. *pg->gorilla.writer = gorilla_writer_init(gbuf, GORILLA_BUFFER_SLOTS);
  158. pg->gorilla.num_buffers = 1;
  159. break;
  160. }
  161. default:
  162. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, type);
  163. aral_freez(pgd_alloc_globals.aral_pgd, pg);
  164. pg = PGD_EMPTY;
  165. break;
  166. }
  167. return pg;
  168. }
  169. PGD *pgd_create_from_disk_data(uint8_t type, void *base, uint32_t size)
  170. {
  171. if (!size)
  172. return PGD_EMPTY;
  173. if (size < page_type_size[type])
  174. return PGD_EMPTY;
  175. PGD *pg = aral_mallocz(pgd_alloc_globals.aral_pgd);
  176. pg->type = type;
  177. pg->states = PGD_STATE_CREATED_FROM_DISK;
  178. pg->options = ~PAGE_OPTION_ALL_VALUES_EMPTY;
  179. switch (type)
  180. {
  181. case PAGE_METRICS:
  182. case PAGE_TIER:
  183. pg->raw.size = size;
  184. pg->used = size / page_type_size[type];
  185. pg->slots = pg->used;
  186. pg->raw.data = pgd_data_aral_alloc(size);
  187. memcpy(pg->raw.data, base, size);
  188. break;
  189. case PAGE_GORILLA_METRICS:
  190. internal_fatal(size == 0, "Asked to create page with 0 data!!!");
  191. internal_fatal(size % sizeof(uint32_t), "Unaligned gorilla buffer size");
  192. internal_fatal(size % GORILLA_BUFFER_SIZE, "Expected size to be a multiple of %zu-bytes", GORILLA_BUFFER_SIZE);
  193. pg->raw.data = mallocz(size);
  194. pg->raw.size = size;
  195. // TODO: rm this
  196. memset(pg->raw.data, 0, size);
  197. memcpy(pg->raw.data, base, size);
  198. uint32_t total_entries = gorilla_buffer_patch((void *) pg->raw.data);
  199. pg->used = total_entries;
  200. pg->slots = pg->used;
  201. break;
  202. default:
  203. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, type);
  204. aral_freez(pgd_alloc_globals.aral_pgd, pg);
  205. pg = PGD_EMPTY;
  206. break;
  207. }
  208. return pg;
  209. }
  210. void pgd_free(PGD *pg)
  211. {
  212. if (!pg)
  213. return;
  214. if (pg == PGD_EMPTY)
  215. return;
  216. switch (pg->type)
  217. {
  218. case PAGE_METRICS:
  219. case PAGE_TIER:
  220. pgd_data_aral_free(pg->raw.data, pg->raw.size);
  221. break;
  222. case PAGE_GORILLA_METRICS: {
  223. if (pg->states & PGD_STATE_CREATED_FROM_DISK)
  224. {
  225. internal_fatal(pg->raw.data == NULL, "Tried to free gorilla PGD loaded from disk with NULL data");
  226. freez(pg->raw.data);
  227. pg->raw.data = NULL;
  228. }
  229. else if ((pg->states & PGD_STATE_CREATED_FROM_COLLECTOR) ||
  230. (pg->states & PGD_STATE_SCHEDULED_FOR_FLUSHING) ||
  231. (pg->states & PGD_STATE_FLUSHED_TO_DISK))
  232. {
  233. internal_fatal(pg->gorilla.writer == NULL,
  234. "PGD does not have an active gorilla writer");
  235. internal_fatal(pg->gorilla.num_buffers == 0,
  236. "PGD does not have any gorilla buffers allocated");
  237. while (true) {
  238. gorilla_buffer_t *gbuf = gorilla_writer_drop_head_buffer(pg->gorilla.writer);
  239. if (!gbuf)
  240. break;
  241. aral_freez(pgd_alloc_globals.aral_gorilla_buffer[pg->gorilla.aral_index], gbuf);
  242. pg->gorilla.num_buffers -= 1;
  243. }
  244. internal_fatal(pg->gorilla.num_buffers != 0,
  245. "Could not free all gorilla writer buffers");
  246. aral_freez(pgd_alloc_globals.aral_gorilla_writer[pg->gorilla.aral_index], pg->gorilla.writer);
  247. pg->gorilla.writer = NULL;
  248. } else {
  249. fatal("pgd_free() called on gorilla page with unsupported state");
  250. // TODO: should we support any other states?
  251. // if (!(pg->states & PGD_STATE_FLUSHED_TO_DISK))
  252. // fatal("pgd_free() is not supported yet for pages flushed to disk");
  253. }
  254. break;
  255. }
  256. default:
  257. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  258. break;
  259. }
  260. aral_freez(pgd_alloc_globals.aral_pgd, pg);
  261. }
  262. // ----------------------------------------------------------------------------
  263. // utility functions
  264. uint32_t pgd_type(PGD *pg)
  265. {
  266. return pg->type;
  267. }
  268. bool pgd_is_empty(PGD *pg)
  269. {
  270. if (!pg)
  271. return true;
  272. if (pg == PGD_EMPTY)
  273. return true;
  274. if (pg->used == 0)
  275. return true;
  276. if (pg->options & PAGE_OPTION_ALL_VALUES_EMPTY)
  277. return true;
  278. return false;
  279. }
  280. uint32_t pgd_slots_used(PGD *pg)
  281. {
  282. if (!pg)
  283. return 0;
  284. if (pg == PGD_EMPTY)
  285. return 0;
  286. return pg->used;
  287. }
  288. uint32_t pgd_memory_footprint(PGD *pg)
  289. {
  290. if (!pg)
  291. return 0;
  292. if (pg == PGD_EMPTY)
  293. return 0;
  294. size_t footprint = 0;
  295. switch (pg->type) {
  296. case PAGE_METRICS:
  297. case PAGE_TIER:
  298. footprint = sizeof(PGD) + pg->raw.size;
  299. break;
  300. case PAGE_GORILLA_METRICS: {
  301. if (pg->states & PGD_STATE_CREATED_FROM_DISK)
  302. footprint = sizeof(PGD) + pg->raw.size;
  303. else
  304. footprint = sizeof(PGD) + sizeof(gorilla_writer_t) + (pg->gorilla.num_buffers * GORILLA_BUFFER_SIZE);
  305. break;
  306. }
  307. default:
  308. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  309. break;
  310. }
  311. return footprint;
  312. }
  313. uint32_t pgd_disk_footprint(PGD *pg)
  314. {
  315. if (!pgd_slots_used(pg))
  316. return 0;
  317. size_t size = 0;
  318. switch (pg->type) {
  319. case PAGE_METRICS:
  320. case PAGE_TIER: {
  321. uint32_t used_size = pg->used * page_type_size[pg->type];
  322. internal_fatal(used_size > pg->raw.size, "Wrong disk footprint page size");
  323. size = used_size;
  324. break;
  325. }
  326. case PAGE_GORILLA_METRICS: {
  327. if (pg->states & PGD_STATE_CREATED_FROM_COLLECTOR ||
  328. pg->states & PGD_STATE_SCHEDULED_FOR_FLUSHING ||
  329. pg->states & PGD_STATE_FLUSHED_TO_DISK)
  330. {
  331. internal_fatal(!pg->gorilla.writer,
  332. "pgd_disk_footprint() not implemented for NULL gorilla writers");
  333. internal_fatal(pg->gorilla.num_buffers == 0,
  334. "Gorilla writer does not have any buffers");
  335. size = pg->gorilla.num_buffers * GORILLA_BUFFER_SIZE;
  336. if (pg->states & PGD_STATE_CREATED_FROM_COLLECTOR) {
  337. global_statistics_tier0_disk_compressed_bytes(gorilla_writer_nbytes(pg->gorilla.writer));
  338. global_statistics_tier0_disk_uncompressed_bytes(gorilla_writer_entries(pg->gorilla.writer) * sizeof(storage_number));
  339. }
  340. } else if (pg->states & PGD_STATE_CREATED_FROM_DISK) {
  341. size = pg->raw.size;
  342. } else {
  343. fatal("Asked disk footprint on unknown page state");
  344. }
  345. break;
  346. }
  347. default:
  348. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  349. break;
  350. }
  351. internal_fatal(pg->states & PGD_STATE_CREATED_FROM_DISK,
  352. "Disk footprint asked for page created from disk.");
  353. pg->states = PGD_STATE_SCHEDULED_FOR_FLUSHING;
  354. return size;
  355. }
  356. void pgd_copy_to_extent(PGD *pg, uint8_t *dst, uint32_t dst_size)
  357. {
  358. internal_fatal(pgd_disk_footprint(pg) != dst_size, "Wrong disk footprint size requested (need %u, available %u)",
  359. pgd_disk_footprint(pg), dst_size);
  360. switch (pg->type) {
  361. case PAGE_METRICS:
  362. case PAGE_TIER:
  363. memcpy(dst, pg->raw.data, dst_size);
  364. break;
  365. case PAGE_GORILLA_METRICS: {
  366. if ((pg->states & PGD_STATE_SCHEDULED_FOR_FLUSHING) == 0)
  367. fatal("Copying to extent is supported only for PGDs that are scheduled for flushing.");
  368. internal_fatal(!pg->gorilla.writer,
  369. "pgd_copy_to_extent() not implemented for NULL gorilla writers");
  370. internal_fatal(pg->gorilla.num_buffers == 0,
  371. "pgd_copy_to_extent() gorilla writer does not have any buffers");
  372. bool ok = gorilla_writer_serialize(pg->gorilla.writer, dst, dst_size);
  373. UNUSED(ok);
  374. internal_fatal(!ok,
  375. "pgd_copy_to_extent() tried to serialize pg=%p, gw=%p (with dst_size=%u bytes, num_buffers=%zu)",
  376. pg, pg->gorilla.writer, dst_size, pg->gorilla.num_buffers);
  377. break;
  378. }
  379. default:
  380. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  381. break;
  382. }
  383. pg->states = PGD_STATE_FLUSHED_TO_DISK;
  384. }
  385. // ----------------------------------------------------------------------------
  386. // data collection
  387. void pgd_append_point(PGD *pg,
  388. usec_t point_in_time_ut __maybe_unused,
  389. NETDATA_DOUBLE n,
  390. NETDATA_DOUBLE min_value,
  391. NETDATA_DOUBLE max_value,
  392. uint16_t count,
  393. uint16_t anomaly_count,
  394. SN_FLAGS flags,
  395. uint32_t expected_slot)
  396. {
  397. if (unlikely(pg->used >= pg->slots))
  398. fatal("DBENGINE: attempted to write beyond page size (page type %u, slots %u, used %u)",
  399. pg->type, pg->slots, pg->used /* FIXME:, pg->size */);
  400. if (unlikely(pg->used != expected_slot))
  401. fatal("DBENGINE: page is not aligned to expected slot (used %u, expected %u)",
  402. pg->used, expected_slot);
  403. if (!(pg->states & PGD_STATE_CREATED_FROM_COLLECTOR))
  404. fatal("DBENGINE: collection on page not created from a collector");
  405. if (pg->states & PGD_STATE_SCHEDULED_FOR_FLUSHING)
  406. fatal("Data collection on page already scheduled for flushing");
  407. switch (pg->type) {
  408. case PAGE_METRICS: {
  409. storage_number *tier0_metric_data = (storage_number *)pg->raw.data;
  410. storage_number t = pack_storage_number(n, flags);
  411. tier0_metric_data[pg->used++] = t;
  412. if ((pg->options & PAGE_OPTION_ALL_VALUES_EMPTY) && does_storage_number_exist(t))
  413. pg->options &= ~PAGE_OPTION_ALL_VALUES_EMPTY;
  414. break;
  415. }
  416. case PAGE_TIER: {
  417. storage_number_tier1_t *tier12_metric_data = (storage_number_tier1_t *)pg->raw.data;
  418. storage_number_tier1_t t;
  419. t.sum_value = (float) n;
  420. t.min_value = (float) min_value;
  421. t.max_value = (float) max_value;
  422. t.anomaly_count = anomaly_count;
  423. t.count = count;
  424. tier12_metric_data[pg->used++] = t;
  425. if ((pg->options & PAGE_OPTION_ALL_VALUES_EMPTY) && fpclassify(n) != FP_NAN)
  426. pg->options &= ~PAGE_OPTION_ALL_VALUES_EMPTY;
  427. break;
  428. }
  429. case PAGE_GORILLA_METRICS: {
  430. pg->used++;
  431. storage_number t = pack_storage_number(n, flags);
  432. if ((pg->options & PAGE_OPTION_ALL_VALUES_EMPTY) && does_storage_number_exist(t))
  433. pg->options &= ~PAGE_OPTION_ALL_VALUES_EMPTY;
  434. bool ok = gorilla_writer_write(pg->gorilla.writer, t);
  435. if (!ok) {
  436. gorilla_buffer_t *new_buffer = aral_mallocz(pgd_alloc_globals.aral_gorilla_buffer[pg->gorilla.aral_index]);
  437. memset(new_buffer, 0, GORILLA_BUFFER_SIZE);
  438. gorilla_writer_add_buffer(pg->gorilla.writer, new_buffer, GORILLA_BUFFER_SLOTS);
  439. pg->gorilla.num_buffers += 1;
  440. global_statistics_gorilla_buffer_add_hot();
  441. ok = gorilla_writer_write(pg->gorilla.writer, t);
  442. internal_fatal(ok == false, "Failed to writer value in newly allocated gorilla buffer.");
  443. }
  444. break;
  445. }
  446. default:
  447. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  448. break;
  449. }
  450. }
  451. // ----------------------------------------------------------------------------
  452. // querying with cursor
  453. static void pgdc_seek(PGDC *pgdc, uint32_t position)
  454. {
  455. PGD *pg = pgdc->pgd;
  456. switch (pg->type) {
  457. case PAGE_METRICS:
  458. case PAGE_TIER:
  459. pgdc->slots = pgdc->pgd->used;
  460. break;
  461. case PAGE_GORILLA_METRICS: {
  462. if (pg->states & PGD_STATE_CREATED_FROM_DISK) {
  463. pgdc->slots = pgdc->pgd->slots;
  464. pgdc->gr = gorilla_reader_init((void *) pg->raw.data);
  465. } else {
  466. if (!(pg->states & PGD_STATE_CREATED_FROM_COLLECTOR) &&
  467. !(pg->states & PGD_STATE_SCHEDULED_FOR_FLUSHING) &&
  468. !(pg->states & PGD_STATE_FLUSHED_TO_DISK))
  469. fatal("pgdc_seek() currently is not supported for pages created from disk.");
  470. if (!pg->gorilla.writer)
  471. fatal("Seeking from a page without an active gorilla writer is not supported (yet).");
  472. pgdc->slots = gorilla_writer_entries(pg->gorilla.writer);
  473. pgdc->gr = gorilla_writer_get_reader(pg->gorilla.writer);
  474. }
  475. if (position > pgdc->slots)
  476. position = pgdc->slots;
  477. for (uint32_t i = 0; i != position; i++) {
  478. uint32_t value;
  479. bool ok = gorilla_reader_read(&pgdc->gr, &value);
  480. if (!ok) {
  481. // this is fine, the reader will return empty points
  482. break;
  483. }
  484. }
  485. break;
  486. }
  487. default:
  488. netdata_log_error("%s() - Unknown page type: %uc", __FUNCTION__, pg->type);
  489. break;
  490. }
  491. }
  492. void pgdc_reset(PGDC *pgdc, PGD *pgd, uint32_t position)
  493. {
  494. // pgd might be null and position equal to UINT32_MAX
  495. pgdc->pgd = pgd;
  496. pgdc->position = position;
  497. if (!pgd)
  498. return;
  499. if (pgd == PGD_EMPTY)
  500. return;
  501. if (position == UINT32_MAX)
  502. return;
  503. pgdc_seek(pgdc, position);
  504. }
  505. bool pgdc_get_next_point(PGDC *pgdc, uint32_t expected_position __maybe_unused, STORAGE_POINT *sp)
  506. {
  507. if (!pgdc->pgd || pgdc->pgd == PGD_EMPTY || pgdc->position >= pgdc->slots)
  508. {
  509. storage_point_empty(*sp, sp->start_time_s, sp->end_time_s);
  510. return false;
  511. }
  512. internal_fatal(pgdc->position != expected_position, "Wrong expected cursor position");
  513. switch (pgdc->pgd->type)
  514. {
  515. case PAGE_METRICS: {
  516. storage_number *array = (storage_number *) pgdc->pgd->raw.data;
  517. storage_number n = array[pgdc->position++];
  518. sp->min = sp->max = sp->sum = unpack_storage_number(n);
  519. sp->flags = (SN_FLAGS)(n & SN_USER_FLAGS);
  520. sp->count = 1;
  521. sp->anomaly_count = is_storage_number_anomalous(n) ? 1 : 0;
  522. return true;
  523. }
  524. case PAGE_TIER: {
  525. storage_number_tier1_t *array = (storage_number_tier1_t *) pgdc->pgd->raw.data;
  526. storage_number_tier1_t n = array[pgdc->position++];
  527. sp->flags = n.anomaly_count ? SN_FLAG_NONE : SN_FLAG_NOT_ANOMALOUS;
  528. sp->count = n.count;
  529. sp->anomaly_count = n.anomaly_count;
  530. sp->min = n.min_value;
  531. sp->max = n.max_value;
  532. sp->sum = n.sum_value;
  533. return true;
  534. }
  535. case PAGE_GORILLA_METRICS: {
  536. pgdc->position++;
  537. uint32_t n = 666666666;
  538. bool ok = gorilla_reader_read(&pgdc->gr, &n);
  539. if (ok) {
  540. sp->min = sp->max = sp->sum = unpack_storage_number(n);
  541. sp->flags = (SN_FLAGS)(n & SN_USER_FLAGS);
  542. sp->count = 1;
  543. sp->anomaly_count = is_storage_number_anomalous(n) ? 1 : 0;
  544. } else {
  545. storage_point_empty(*sp, sp->start_time_s, sp->end_time_s);
  546. }
  547. return ok;
  548. }
  549. default: {
  550. static bool logged = false;
  551. if (!logged)
  552. {
  553. netdata_log_error("DBENGINE: unknown page type %"PRIu32" found. Cannot decode it. Ignoring its metrics.",
  554. pgd_type(pgdc->pgd));
  555. logged = true;
  556. }
  557. storage_point_empty(*sp, sp->start_time_s, sp->end_time_s);
  558. return false;
  559. }
  560. }
  561. }