master
h 272 lines 9.69 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 #ifndef DBENGINE_CACHE_H
3 #define DBENGINE_CACHE_H
4
5 #include "datafile.h"
6 #include "../rrd.h"
7
8 // CACHE COMPILE TIME CONFIGURATION
9 // #define PGC_COUNT_POINTS_COLLECTED 1
10
11 typedef struct pgc PGC;
12 typedef struct pgc_page PGC_PAGE;
13 #define PGC_NAME_MAX 23
14
15 typedef enum __attribute__ ((__packed__)) {
16 PGC_OPTIONS_NONE = 0,
17 PGC_OPTIONS_EVICT_PAGES_NO_INLINE = (1 << 0),
18 PGC_OPTIONS_FLUSH_PAGES_NO_INLINE = (1 << 1),
19 PGC_OPTIONS_AUTOSCALE = (1 << 2),
20 } PGC_OPTIONS;
21
22 #define PGC_OPTIONS_DEFAULT (PGC_OPTIONS_EVICT_PAGES_NO_INLINE | PGC_OPTIONS_AUTOSCALE)
23
24 typedef struct pgc_entry {
25 Word_t section; // the section this belongs to
26 Word_t metric_id; // the metric this belongs to
27 time_t start_time_s; // the start time of the page
28 time_t end_time_s; // the end time of the page
29 size_t size; // the size in bytes of the allocation, outside the cache
30 void *data; // a pointer to data outside the cache
31 uint32_t update_every_s; // the update every of the page
32 bool hot; // true if this entry is currently being collected
33 uint8_t *custom_data;
34 } PGC_ENTRY;
35
36 struct pgc_size_histogram_entry {
37 size_t upto;
38 size_t count;
39 };
40
41 #define PGC_SIZE_HISTOGRAM_ENTRIES 15
42 #define PGC_QUEUE_HOT 0
43 #define PGC_QUEUE_DIRTY 1
44 #define PGC_QUEUE_CLEAN 2
45
46 struct pgc_size_histogram {
47 struct pgc_size_histogram_entry array[PGC_SIZE_HISTOGRAM_ENTRIES];
48 };
49
50 struct pgc_queue_statistics {
51 struct pgc_size_histogram size_histogram;
52
53 PAD64(size_t) entries;
54 PAD64(int64_t) size;
55
56 PAD64(size_t) max_entries;
57 PAD64(int64_t) max_size;
58
59 PAD64(size_t) added_entries;
60 PAD64(int64_t) added_size;
61
62 PAD64(size_t) removed_entries;
63 PAD64(int64_t) removed_size;
64 };
65
66 struct pgc_statistics {
67 PAD64(int64_t) wanted_cache_size;
68 PAD64(int64_t) current_cache_size;
69
70 // ----------------------------------------------------------------------------------------------------------------
71 // volume
72
73 PAD64(size_t) entries; // all the entries (includes clean, dirty, hot)
74 PAD64(int64_t) size; // all the entries (includes clean, dirty, hot)
75
76 PAD64(size_t) referenced_entries; // all the entries currently referenced
77 PAD64(int64_t) referenced_size; // all the entries currently referenced
78
79 PAD64(size_t) added_entries;
80 PAD64(int64_t) added_size;
81
82 PAD64(size_t) removed_entries;
83 PAD64(int64_t) removed_size;
84
85 #ifdef PGC_COUNT_POINTS_COLLECTED
86 PAD64(size_t) points_collected;
87 #endif
88
89 // ----------------------------------------------------------------------------------------------------------------
90 // migrations
91
92 PAD64(size_t) evicting_entries;
93 PAD64(int64_t) evicting_size;
94
95 PAD64(size_t) flushing_entries;
96 PAD64(int64_t) flushing_size;
97
98 PAD64(size_t) hot2dirty_entries;
99 PAD64(int64_t) hot2dirty_size;
100
101 PAD64(size_t) hot_empty_pages_evicted_immediately;
102 PAD64(size_t) hot_empty_pages_evicted_later;
103
104 // ----------------------------------------------------------------------------------------------------------------
105 // workload
106
107 PAD64(size_t) acquires;
108 PAD64(size_t) releases;
109
110 PAD64(size_t) acquires_for_deletion;
111
112 PAD64(size_t) searches_exact;
113 PAD64(size_t) searches_exact_hits;
114 PAD64(size_t) searches_exact_misses;
115
116 PAD64(size_t) searches_closest;
117 PAD64(size_t) searches_closest_hits;
118 PAD64(size_t) searches_closest_misses;
119
120 PAD64(size_t) flushes_completed;
121 PAD64(int64_t) flushes_completed_size;
122 PAD64(int64_t) flushes_cancelled_size;
123
124 // ----------------------------------------------------------------------------------------------------------------
125 // critical events
126
127 PAD64(size_t) events_cache_under_severe_pressure;
128 PAD64(size_t) events_cache_needs_space_aggressively;
129 PAD64(size_t) events_flush_critical;
130
131 // ----------------------------------------------------------------------------------------------------------------
132 // worker threads
133
134 PAD64(size_t) p2_workers_search;
135 PAD64(size_t) p2_workers_add;
136 PAD64(size_t) p0_workers_evict; // priority 0, we always need this when inline evictions are enabled
137 PAD64(size_t) p2_workers_flush;
138 PAD64(size_t) p2_workers_jv2_flush;
139 PAD64(size_t) p2_workers_hot2dirty;
140
141 // ----------------------------------------------------------------------------------------------------------------
142 // waste events
143
144 // waste events - spins
145 PAD64(size_t) p2_waste_insert_spins;
146 PAD64(size_t) p2_waste_evict_useless_spins;
147
148 // waste events - eviction
149 PAD64(size_t) p2_waste_evict_relocated;
150 PAD64(size_t) p2_waste_evict_thread_signals;
151 PAD64(size_t) p2_waste_evictions_inline_on_add;
152 PAD64(size_t) p2_waste_evictions_inline_on_release;
153
154 // waste events - flushing
155 PAD64(size_t) p2_waste_flush_on_add;
156 PAD64(size_t) p2_waste_flush_on_release;
157 PAD64(size_t) p2_waste_flushes_cancelled;
158
159 // ----------------------------------------------------------------------------------------------------------------
160 // per queue statistics
161
162 struct pgc_queue_statistics queues[3];
163 };
164
165 typedef void (*free_clean_page_callback)(PGC *cache, PGC_ENTRY entry);
166 typedef void (*save_dirty_page_callback)(PGC *cache, PGC_ENTRY *entries_array, PGC_PAGE **pages_array, size_t entries);
167 typedef void (*save_dirty_init_callback)(PGC *cache, Word_t section);
168 // create a cache
169 PGC *pgc_create(const char *name,
170 size_t clean_size_bytes, free_clean_page_callback pgc_free_clean_cb,
171 size_t max_dirty_pages_per_flush, save_dirty_init_callback pgc_save_init_cb, save_dirty_page_callback pgc_save_dirty_cb,
172 size_t max_pages_per_inline_eviction, size_t max_inline_evictors,
173 size_t max_skip_pages_per_inline_eviction,
174 size_t max_flushes_inline,
175 PGC_OPTIONS options, size_t partitions, size_t additional_bytes_per_page);
176
177 // destroy the cache
178 void pgc_destroy(PGC *cache, bool flush);
179
180 #define PGC_SECTION_ALL ((Word_t)0)
181 void pgc_flush_dirty_pages(PGC *cache, Word_t section);
182 void pgc_flush_all_hot_and_dirty_pages(PGC *cache, Word_t section);
183
184 // add a page to the cache and return a pointer to it
185 PGC_PAGE *pgc_page_add_and_acquire(PGC *cache, PGC_ENTRY entry, bool *added);
186
187 // get another reference counter on an already referenced page
188 PGC_PAGE *pgc_page_dup(PGC *cache, PGC_PAGE *page);
189
190 // release a page (all pointers to it are now invalid)
191 void pgc_page_release(PGC *cache, PGC_PAGE *page);
192
193 // mark a hot page dirty, and release it
194 void pgc_page_hot_to_dirty_and_release(PGC *cache, PGC_PAGE *page, bool never_flush);
195
196 // find a page from the cache
197 typedef enum {
198 PGC_SEARCH_EXACT,
199 PGC_SEARCH_CLOSEST,
200 PGC_SEARCH_FIRST,
201 PGC_SEARCH_NEXT,
202 PGC_SEARCH_LAST,
203 PGC_SEARCH_PREV,
204 } PGC_SEARCH;
205
206 PGC_PAGE *pgc_page_get_and_acquire(PGC *cache, Word_t section, Word_t metric_id, time_t start_time_s, PGC_SEARCH method);
207
208 // get information from an acquired page
209 Word_t pgc_page_section(PGC_PAGE *page);
210 Word_t pgc_page_metric(PGC_PAGE *page);
211 time_t pgc_page_start_time_s(PGC_PAGE *page);
212 time_t pgc_page_end_time_s(PGC_PAGE *page);
213 uint32_t pgc_page_update_every_s(PGC_PAGE *page);
214 uint32_t pgc_page_fix_update_every(PGC_PAGE *page, uint32_t update_every_s);
215 time_t pgc_page_fix_end_time_s(PGC_PAGE *page, time_t end_time_s);
216 void *pgc_page_data(PGC_PAGE *page);
217 void *pgc_page_custom_data(PGC *cache, PGC_PAGE *page);
218 size_t pgc_page_data_size(PGC *cache, PGC_PAGE *page);
219 bool pgc_is_page_hot(PGC_PAGE *page);
220 bool pgc_is_page_dirty(PGC_PAGE *page);
221 bool pgc_is_page_clean(PGC_PAGE *page);
222 void pgc_reset_hot_max(PGC *cache);
223 int64_t pgc_get_current_cache_size(PGC *cache);
224 int64_t pgc_get_wanted_cache_size(PGC *cache);
225
226 // resetting the end time of a hot page
227 void pgc_page_hot_set_end_time_s(PGC *cache, PGC_PAGE *page, time_t end_time_s, size_t additional_bytes);
228 bool pgc_page_to_clean_evict_or_release(PGC *cache, PGC_PAGE *page);
229
230 typedef bool (*migrate_to_v2_callback)(Word_t section, unsigned datafile_fileno, uint8_t type, Pvoid_t JudyL_metrics, Pvoid_t JudyL_extents_pos, size_t count_of_unique_extents, size_t count_of_unique_metrics, size_t count_of_unique_pages, void *data);
231 void pgc_open_cache_to_journal_v2(
232 PGC *cache,
233 Word_t section,
234 unsigned datafile_fileno,
235 uint8_t type,
236 migrate_to_v2_callback cb,
237 void *data,
238 bool startup);
239 void pgc_open_evict_clean_pages_of_datafile(PGC *cache, struct rrdengine_datafile *datafile);
240 size_t pgc_count_clean_pages_having_data_ptr(PGC *cache, Word_t section, void *ptr);
241 size_t pgc_count_hot_pages_having_data_ptr(PGC *cache, Word_t section, void *ptr);
242
243 typedef int64_t (*dynamic_target_cache_size_callback)(void);
244 void pgc_set_dynamic_target_cache_size_callback(PGC *cache, dynamic_target_cache_size_callback callback);
245
246 typedef size_t (*nominal_page_size_callback)(void *);
247 void pgc_set_nominal_page_size_callback(PGC *cache, nominal_page_size_callback callback);
248
249 // return true when there is more work to do
250 bool pgc_evict_pages(PGC *cache, size_t max_skip, size_t max_evict);
251 bool pgc_flush_pages(PGC *cache);
252
253 struct pgc_statistics pgc_get_statistics(PGC *cache);
254 size_t pgc_hot_and_dirty_entries(PGC *cache);
255
256 struct aral_statistics *pgc_aral_stats(void);
257
258 static inline size_t indexing_partition(Word_t ptr, Word_t modulo) __attribute__((const));
259 static inline size_t indexing_partition(Word_t ptr, Word_t modulo) {
260 XXH64_hash_t hash = XXH3_64bits(&ptr, sizeof(ptr));
261 return hash % modulo;
262 }
263
264 static inline size_t pgc_max_evictors(void) {
265 return 1 + netdata_conf_cpus() / 2;
266 }
267
268 static inline size_t pgc_max_flushers(void) {
269 return netdata_conf_cpus();
270 }
271
272 #endif // DBENGINE_CACHE_H