master
h 303 lines 10.2 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_JOURNALFILE_H
4 #define NETDATA_JOURNALFILE_H
5
6 #include "rrdengine.h"
7
8 /* Forward declarations */
9 struct rrdengine_instance;
10 struct rrdengine_datafile;
11 struct rrdengine_journalfile;
12
13 #define WALFILE_PREFIX "journalfile-"
14 #define WALFILE_EXTENSION ".njf"
15 #define WALFILE_EXTENSION_V2 ".njfv2"
16
17 #define is_descr_journal_v2(descr) ((descr)->extent_entry != NULL)
18
19 typedef enum __attribute__ ((__packed__)) {
20 JOURNALFILE_FLAG_IS_AVAILABLE = (1 << 0),
21 JOURNALFILE_FLAG_IS_MOUNTED = (1 << 1),
22 JOURNALFILE_FLAG_MOUNTED_FOR_RETENTION = (1 << 2),
23 JOURNALFILE_FLAG_METRIC_CRC_CHECK = (1 << 3),
24 } JOURNALFILE_FLAGS;
25
26 typedef enum __attribute__ ((__packed__)) {
27 JOURNALFILE_V2_ACCESS_AUTO = 0,
28 JOURNALFILE_V2_ACCESS_RANDOM,
29 JOURNALFILE_V2_ACCESS_SEQUENTIAL_DIRECTORY,
30 } JOURNALFILE_V2_ACCESS_HINT;
31
32 struct rrdengine_journalfile {
33 SPINLOCK data_spinlock;
34 struct {
35 void *data; // MMAPed file of journal v2
36 uint32_t size; // Total file size mapped
37 int fd;
38 } mmap;
39
40 struct {
41 JOURNALFILE_FLAGS flags;
42 int32_t refcount;
43 time_t first_time_s;
44 time_t last_time_s;
45 time_t not_needed_since_s;
46 uint32_t size_of_directory;
47 } v2;
48
49 struct {
50 Word_t indexed_as;
51 } njfv2idx;
52
53 struct {
54 SPINLOCK spinlock;
55 uint64_t pos;
56 } unsafe;
57
58 uv_file file;
59 struct rrdengine_datafile *datafile;
60 };
61
62 static inline uint64_t journalfile_current_size(struct rrdengine_journalfile *journalfile) {
63 spinlock_lock(&journalfile->unsafe.spinlock);
64 uint64_t size = journalfile->unsafe.pos;
65 spinlock_unlock(&journalfile->unsafe.spinlock);
66 return size;
67 }
68
69 // Journal v2 structures
70
71 #define JOURVAL_V2_MAGIC (0x01230317)
72 #define JOURVAL_V2_REBUILD_MAGIC (0x00230317)
73 #define JOURVAL_V2_SKIP_MAGIC (0x02230317)
74
75 struct journal_v2_block_trailer {
76 union {
77 uint8_t checksum[CHECKSUM_SZ]; /* CRC32 */
78 uint32_t crc;
79 };
80 };
81
82 /*
83 * Journal File V2 Format
84 *
85 * File Layout:
86 * +------------------------------------------------+
87 * | HEADER SECTION |
88 * | +--------------------------------------------+
89 * | | Header (72 bytes) |
90 * | | - magic, times, counts, offsets |
91 * | +--------------------------------------------+
92 * | | Padding (to 4096 bytes) |
93 * +------------------------------------------------+
94 * | EXTENT SECTION |
95 * | +--------------------------------------------+
96 * | | Extent Items |
97 * | | - Array of Extent Entries (16 bytes each)|
98 * | +--------------------------------------------+
99 * | | Extent Section Trailer (4 bytes CRC) |
100 * +------------------------------------------------+
101 * | METRICS SECTION |
102 * | +--------------------------------------------+
103 * | | Metric List |
104 * | | - Array of Metric Entries (36 bytes each)|
105 * | +--------------------------------------------+
106 * | | Metric List Trailer (4 bytes CRC) |
107 * +------------------------------------------------+
108 * | PAGE DATA SECTION |
109 * | +--------------------------------------------+
110 * | | For each metric: |
111 * | | - Page Header (28 bytes) |
112 * | | - Page Entries (20 bytes each) |
113 * | | - Page Trailer (4 bytes CRC) |
114 * +------------------------------------------------+
115 * | FILE TRAILER |
116 * | - File CRC (4 bytes) |
117 * +------------------------------------------------+
118 *
119 * Data Integrity:
120 * - All sections have CRC32 checksums
121 * - The file header CRC is stored in the file trailer
122 * - Each section (extent list, metric list) has its own trailer with CRC
123 * - Each page header includes a CRC of its content
124 *
125 * Time Representation:
126 * - File-level times are stored in microseconds (start_time_ut, end_time_ut)
127 * - Page-level times are stored as deltas in seconds relative to the journal start time
128 */
129
130 // Journal v2 header (72 bytes)
131 struct journal_v2_header {
132 // File type identifier
133 // - 0x01230317: Normal journal file
134 // - 0x00230317: File needs rebuild
135 // - 0x02230317: File should be skipped
136 uint32_t magic;
137
138 // --- implicit padding of 4-bytes because the struct is not packed ---
139
140 // Mininimum start time in microseconds
141 usec_t start_time_ut;
142 // Maximum end time in microseconds
143 usec_t end_time_ut;
144
145 // Number of extents
146 uint32_t extent_count;
147 // Offset to extents section
148 uint32_t extent_offset;
149
150 // Number of metrics
151 uint32_t metric_count;
152 // Offset to metrics section
153 uint32_t metric_offset;
154
155 // Total count of pages
156 uint32_t page_count;
157 // Offset to page data section
158 uint32_t page_offset;
159
160 // Offset to extents section CRC
161 uint32_t extent_trailer_offset;
162 // Offset to metrics section CRC
163 uint32_t metric_trailer_offset;
164
165 // Size of original journal file
166 uint32_t journal_v1_file_size;
167 // Total file size
168 uint32_t journal_v2_file_size;
169
170 // Pointer used only when writing to build up the memory-mapped file.
171 void *data;
172 };
173
174 // Reserve the first 4 KiB for the journal v2 header
175 #define JOURNAL_V2_HEADER_PADDING_SZ (RRDENG_BLOCK_SIZE - (sizeof(struct journal_v2_header)))
176
177 // Extent section item (16 bytes)
178 struct journal_extent_list {
179 // Extent offset in datafile
180 uint64_t datafile_offset;
181
182 // Size of the extent
183 uint32_t datafile_size;
184
185 // Index of the data file
186 uint16_t file_index;
187
188 // Number of pages in the extent (not all are necesssarily valid)
189 uint8_t pages;
190
191 // --- implicit padding of 1-byte because the struct is not packed ---
192 };
193
194 // Metric section item (36 bytes)
195 struct journal_metric_list {
196 // Unique identifier of the metric
197 nd_uuid_t uuid;
198
199 // Number of pages for this metric
200 uint32_t entries;
201
202 // Offset to the page data section
203 // Points to: journal_page_header + (entries * journal_page_list)
204 uint32_t page_offset;
205
206 // Start time relative to journal start
207 uint32_t delta_start_s;
208
209 // End time relative to journal start
210 uint32_t delta_end_s;
211
212 // Last update every for this metric in this journal (last page collected)
213 uint32_t update_every_s;
214 };
215
216 // Page section item header (28 bytes)
217 struct journal_page_header {
218 // CRC32 of the header
219 union {
220 uint8_t checksum[CHECKSUM_SZ];
221 uint32_t crc;
222 };
223
224 // Offset to corresponding metric in metric list
225 uint32_t uuid_offset;
226
227 // Number of page items that follow
228 uint32_t entries;
229
230 // UUID of the metric
231 nd_uuid_t uuid;
232 };
233
234 // Page section item (20 bytes)
235 struct journal_page_list {
236 // Start time relative to journal start
237 uint32_t delta_start_s;
238
239 // End time relative to journal start
240 uint32_t delta_end_s;
241
242 // Offset into extent section
243 uint32_t extent_index;
244
245 // Update frequency
246 uint32_t update_every_s;
247
248 // Length of the page
249 uint16_t page_length;
250
251 // Page type identifier
252 uint8_t type;
253
254 // --- implicit padding of 1-byte because the struct is not packed ---
255 };
256
257 struct wal;
258
259 void journalfile_v1_generate_path(struct rrdengine_datafile *datafile, char *str, size_t maxlen);
260 void journalfile_v2_generate_path(struct rrdengine_datafile *datafile, char *str, size_t maxlen);
261 struct rrdengine_journalfile *journalfile_alloc_and_init(struct rrdengine_datafile *datafile);
262 int journalfile_v1_extent_write(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile, struct wal *wal);
263 int journalfile_close(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
264 int journalfile_unlink(struct rrdengine_journalfile *journalfile);
265 #define JOURNALFILE_DELETED_V1 (1u << 0) // .njf was deleted
266 #define JOURNALFILE_DELETED_V2 (1u << 1) // .njfv2 was deleted
267 #define JOURNALFILE_DELETED_ALL (JOURNALFILE_DELETED_V1 | JOURNALFILE_DELETED_V2)
268 /*
269 * Destroys the journal file and returns a JOURNALFILE_DELETED_* bitmask
270 * indicating which on-disk journal files were deleted. This is not a
271 * 0 / -errno style status code.
272 */
273 uint8_t journalfile_destroy_unsafe(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
274 int journalfile_create(struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile);
275 int journalfile_load(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile,
276 struct rrdengine_datafile *datafile);
277 void journalfile_v2_populate_retention_to_mrg(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile);
278
279 bool journalfile_migrate_to_v2_callback(Word_t section, unsigned datafile_fileno __maybe_unused, uint8_t type __maybe_unused,
280 Pvoid_t JudyL_metrics, Pvoid_t JudyL_extents_pos,
281 size_t number_of_extents, size_t number_of_metrics, size_t number_of_pages, void *user_data);
282
283
284 bool journalfile_v2_data_available(struct rrdengine_journalfile *journalfile);
285 size_t journalfile_v2_data_size_get(struct rrdengine_journalfile *journalfile);
286 void journalfile_v2_data_set(struct rrdengine_journalfile *journalfile, int fd, void *journal_data, uint32_t journal_data_size);
287 struct journal_v2_header *journalfile_v2_data_acquire(struct rrdengine_journalfile *journalfile, size_t *data_size, time_t wanted_first_time_s, time_t wanted_last_time_s);
288 struct journal_v2_header *journalfile_v2_data_acquire_with_hint(struct rrdengine_journalfile *journalfile, size_t *data_size, time_t wanted_first_time_s, time_t wanted_last_time_s, JOURNALFILE_V2_ACCESS_HINT hint);
289 void journalfile_v2_data_release(struct rrdengine_journalfile *journalfile);
290 void journalfile_v2_data_unmount_cleanup(time_t now_s);
291
292 typedef struct {
293 bool init;
294 Word_t last;
295 time_t wanted_start_time_s;
296 time_t wanted_end_time_s;
297 struct rrdengine_instance *ctx;
298 struct journal_v2_header *j2_header_acquired;
299 } NJFV2IDX_FIND_STATE;
300
301 struct rrdengine_datafile *njfv2idx_find_and_acquire_j2_header(NJFV2IDX_FIND_STATE *s);
302
303 #endif /* NETDATA_JOURNALFILE_H */