Fill missing removed events after a crash (#12803)
* inject removed events when missing from sqlite * pass flag * remove log message
Emmanuel Vasilakis committed
May 5, 2022 at 12:08 UTC
5148e510178967bd138b68cbaa2612a6ca6b7ce7
1 file changed
+164
database/sqlite/sqlite_health.c
+164
@@ -433,6 +433,168 @@ void sql_health_alarm_log_count(RRDHOST *host) {
433
info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", host->hostname, uuid_str, host->health_log_entries_written);
434
}
435
436
+#define SQL_INJECT_REMOVED(guid, guid2) "insert into health_log_%s (hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, " \
437
+"delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type) " \
438
+"select hostname, ?1, ?2, ?3, config_hash_id, 0, ?4, strftime('%%s'), 0, 0, flags, exec_run_timestamp, " \
439
+"strftime('%%s'), name, chart, family, exec, recipient, source, units, info, exec_code, -2, new_status, delay, NULL, new_value, 0, class, component, type " \
440
+"from health_log_%s where unique_id = ?5", guid, guid2
441
+#define SQL_INJECT_REMOVED_UPDATE(guid) "update health_log_%s set flags = flags | ?1, updated_by_id = ?2 where unique_id = ?3; ", guid
442
+void sql_inject_removed_status(char *uuid_str, uint32_t alarm_id, uint32_t alarm_event_id, uint32_t unique_id, uint32_t max_unique_id)
443
+{
444
+ int rc = 0;
445
+ char command[MAX_HEALTH_SQL_SIZE + 1];
446
+
447
+ if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id)
448
+ return;
449
+
450
+ sqlite3_stmt *res = NULL;
451
+
452
+ snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED(uuid_str, uuid_str));
453
+ rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
454
+ if (rc != SQLITE_OK) {
455
+ error_report("Failed to prepare statement when trying to inject removed event");
456
+ return;
457
+ }
458
+
459
+ rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) max_unique_id);
460
+ if (unlikely(rc != SQLITE_OK)) {
461
+ error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED");
462
+ goto failed;
463
+ }
464
+
465
+ rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) alarm_id);
466
+ if (unlikely(rc != SQLITE_OK)) {
467
+ error_report("Failed to bind alarm_id parameter for SQL_INJECT_REMOVED");
468
+ goto failed;
469
+ }
470
+
471
+ rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) alarm_event_id + 1);
472
+ if (unlikely(rc != SQLITE_OK)) {
473
+ error_report("Failed to bind alarm_event_id parameter for SQL_INJECT_REMOVED");
474
+ goto failed;
475
+ }
476
+
477
+ rc = sqlite3_bind_int64(res, 4, (sqlite3_int64) unique_id);
478
+ if (unlikely(rc != SQLITE_OK)) {
479
+ error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED");
480
+ goto failed;
481
+ }
482
+
483
+ rc = sqlite3_bind_int64(res, 5, (sqlite3_int64) unique_id);
484
+ if (unlikely(rc != SQLITE_OK)) {
485
+ error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED");
486
+ goto failed;
487
+ }
488
+
489
+ rc = execute_insert(res);
490
+ if (unlikely(rc != SQLITE_DONE)) {
491
+ error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED, rc = %d", rc);
492
+ goto failed;
493
+ }
494
+
495
+ if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
496
+ error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
497
+
498
+ //update the old entry
499
+ snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_INJECT_REMOVED_UPDATE(uuid_str));
500
+ rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
501
+ if (rc != SQLITE_OK) {
502
+ error_report("Failed to prepare statement when trying to update during inject removed event");
503
+ return;
504
+ }
505
+
506
+ rc = sqlite3_bind_int64(res, 1, (sqlite3_int64) HEALTH_ENTRY_FLAG_UPDATED);
507
+ if (unlikely(rc != SQLITE_OK)) {
508
+ error_report("Failed to bind flags parameter for SQL_INJECT_REMOVED (update)");
509
+ goto failed;
510
+ }
511
+
512
+ rc = sqlite3_bind_int64(res, 2, (sqlite3_int64) max_unique_id);
513
+ if (unlikely(rc != SQLITE_OK)) {
514
+ error_report("Failed to bind max_unique_id parameter for SQL_INJECT_REMOVED (update)");
515
+ goto failed;
516
+ }
517
+
518
+ rc = sqlite3_bind_int64(res, 3, (sqlite3_int64) unique_id);
519
+ if (unlikely(rc != SQLITE_OK)) {
520
+ error_report("Failed to bind unique_id parameter for SQL_INJECT_REMOVED (update)");
521
+ goto failed;
522
+ }
523
+
524
+ rc = execute_insert(res);
525
+ if (unlikely(rc != SQLITE_DONE)) {
526
+ error_report("HEALTH [N/A]: Failed to execute SQL_INJECT_REMOVED_UPDATE, rc = %d", rc);
527
+ goto failed;
528
+ }
529
+
530
+failed:
531
+ if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
532
+ error_report("HEALTH [N/A]: Failed to finalize the prepared statement for injecting removed event.");
533
+ return;
534
+
535
+}
536
+
537
+#define SQL_SELECT_MAX_UNIQUE_ID(guid) "SELECT MAX(unique_id) from health_log_%s", guid
538
+uint32_t sql_get_max_unique_id (char *uuid_str)
539
+{
540
+ int rc = 0;
541
+ char command[MAX_HEALTH_SQL_SIZE + 1];
542
+ uint32_t max_unique_id = 0;
543
+
544
+ sqlite3_stmt *res = NULL;
545
+
546
+ snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_MAX_UNIQUE_ID(uuid_str));
547
+ rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
548
+ if (rc != SQLITE_OK) {
549
+ error_report("Failed to prepare statement when trying to get max unique id");
550
+ return 0;
551
+ }
552
+
553
+ while (sqlite3_step(res) == SQLITE_ROW) {
554
+ max_unique_id = (uint32_t) sqlite3_column_int64(res, 0);
555
+ }
556
+
557
+ rc = sqlite3_finalize(res);
558
+ if (unlikely(rc != SQLITE_OK))
559
+ error_report("Failed to finalize the statement");
560
+
561
+ return max_unique_id;
562
+}
563
+
564
+#define SQL_SELECT_LAST_STATUSES(guid) "SELECT new_status, unique_id, alarm_id, alarm_event_id from health_log_%s group by alarm_id having max(alarm_event_id)", guid
565
+void sql_check_removed_alerts_state(char *uuid_str)
566
+{
567
+ int rc = 0;
568
+ char command[MAX_HEALTH_SQL_SIZE + 1];
569
+ RRDCALC_STATUS status;
570
+ uint32_t alarm_id = 0, alarm_event_id = 0, unique_id = 0, max_unique_id = 0;
571
+
572
+ sqlite3_stmt *res = NULL;
573
+
574
+ snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_SELECT_LAST_STATUSES(uuid_str));
575
+ rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
576
+ if (rc != SQLITE_OK) {
577
+ error_report("Failed to prepare statement when trying to check removed statuses");
578
+ return;
579
+ }
580
+
581
+ while (sqlite3_step(res) == SQLITE_ROW) {
582
+ status = (RRDCALC_STATUS) sqlite3_column_int(res, 0);
583
+ unique_id = (uint32_t) sqlite3_column_int64(res, 1);
584
+ alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
585
+ alarm_event_id = (uint32_t) sqlite3_column_int64(res, 3);
586
+ if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
587
+ if (unlikely(!max_unique_id))
588
+ max_unique_id = sql_get_max_unique_id (uuid_str);
589
+ sql_inject_removed_status (uuid_str, alarm_id, alarm_event_id, unique_id, ++max_unique_id);
590
+ }
591
+ }
592
+
593
+ rc = sqlite3_finalize(res);
594
+ if (unlikely(rc != SQLITE_OK))
595
+ error_report("Failed to finalize the statement");
596
+}
597
+
598
/* Health related SQL queries
599
Load from the health log table
600
*/
@@ -454,6 +616,8 @@ void sql_health_alarm_log_load(RRDHOST *host) {
616
char uuid_str[GUID_LEN + 1];
617
uuid_unparse_lower_fix(&host->host_uuid, uuid_str);
618
619
+ sql_check_removed_alerts_state(uuid_str);
620
+
621
snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str, host->health_log.max));
622
623
rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);