#include "metric.h"
typedef int32_t REFCOUNT;
#define REFCOUNT_DELETING (-100)
typedef enum __attribute__ ((__packed__)) {
METRIC_FLAG_HAS_RETENTION = (1 << 0),
} METRIC_FLAGS;
struct metric {
uuid_t uuid; // never changes
Word_t section; // never changes
time_t first_time_s; //
time_t latest_time_s_clean; // archived pages latest time
time_t latest_time_s_hot; // latest time of the currently collected page
uint32_t latest_update_every_s; //
pid_t writer;
METRIC_FLAGS flags;
REFCOUNT refcount;
SPINLOCK spinlock; // protects all variable members
// THIS IS allocated with malloc()
// YOU HAVE TO INITIALIZE IT YOURSELF !
};
struct mrg {
ARAL *aral[MRG_PARTITIONS];
struct pgc_index {
netdata_rwlock_t rwlock;
Pvoid_t uuid_judy; // each UUID has a JudyL of sections (tiers)
} index[MRG_PARTITIONS];
struct mrg_statistics stats;
size_t entries_per_partition[MRG_PARTITIONS];
};
static inline void MRG_STATS_DUPLICATE_ADD(MRG *mrg) {
__atomic_add_fetch(&mrg->stats.additions_duplicate, 1, __ATOMIC_RELAXED);
}
static inline void MRG_STATS_ADDED_METRIC(MRG *mrg, size_t partition) {
__atomic_add_fetch(&mrg->stats.entries, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&mrg->stats.additions, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&mrg->stats.size, sizeof(METRIC), __ATOMIC_RELAXED);
__atomic_add_fetch(&mrg->entries_per_partition[partition], 1, __ATOMIC_RELAXED);
}
static inline void MRG_STATS_DELETED_METRIC(MRG *mrg, size_t partition) {
__atomic_sub_fetch(&mrg->stats.entries, 1, __ATOMIC_RELAXED);
__atomic_sub_fetch(&mrg->stats.size, sizeof(METRIC), __ATOMIC_RELAXED);
__atomic_add_fetch(&mrg->stats.deletions, 1, __ATOMIC_RELAXED);
__atomic_sub_fetch(&mrg->entries_per_partition[partition], 1, __ATOMIC_RELAXED);
}
static inline void MRG_STATS_SEARCH_HIT(MRG *mrg) {
__atomic_add_fetch(&mrg->stats.search_hits, 1, __ATOMIC_RELAXED);
}
static inline void MRG_STATS_SEARCH_MISS(MRG *mrg) {
__atomic_add_fetch(&mrg->stats.search_misses, 1, __ATOMIC_RELAXED);
}
static inline void MRG_STATS_DELETE_MISS(MRG *mrg) {
__atomic_add_fetch(&mrg->stats.delete_misses, 1, __ATOMIC_RELAXED);
}
static inline void mrg_index_read_lock(MRG *mrg, size_t partition) {
netdata_rwlock_rdlock(&mrg->index[partition].rwlock);
}
static inline void mrg_index_read_unlock(MRG *mrg, size_t partition) {
netdata_rwlock_unlock(&mrg->index[partition].rwlock);
}
static inline void mrg_index_write_lock(MRG *mrg, size_t partition) {
netdata_rwlock_wrlock(&mrg->index[partition].rwlock);
}
static inline void mrg_index_write_unlock(MRG *mrg, size_t partition) {
netdata_rwlock_unlock(&mrg->index[partition].rwlock);
}
static inline void mrg_stats_size_judyl_change(MRG *mrg, size_t mem_before_judyl, size_t mem_after_judyl) {
if(mem_after_judyl > mem_before_judyl)
__atomic_add_fetch(&mrg->stats.size, mem_after_judyl - mem_before_judyl, __ATOMIC_RELAXED);
else if(mem_after_judyl < mem_before_judyl)
__atomic_sub_fetch(&mrg->stats.size, mem_before_judyl - mem_after_judyl, __ATOMIC_RELAXED);
}
static inline void mrg_stats_size_judyhs_added_uuid(MRG *mrg) {
__atomic_add_fetch(&mrg->stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
}
static inline void mrg_stats_size_judyhs_removed_uuid(MRG *mrg) {
__atomic_sub_fetch(&mrg->stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
}
static inline size_t uuid_partition(MRG *mrg __maybe_unused, uuid_t *uuid) {
uint8_t *u = (uint8_t *)uuid;
return u[UUID_SZ - 1] % MRG_PARTITIONS;
}
static inline bool metric_has_retention_unsafe(MRG *mrg __maybe_unused, METRIC *metric) {
bool has_retention = (metric->first_time_s || metric->latest_time_s_clean || metric->latest_time_s_hot);
if(has_retention && !(metric->flags & METRIC_FLAG_HAS_RETENTION)) {
metric->flags |= METRI