[go: up one dir, main page]

File: vy_log.h

package info (click to toggle)
tarantool 2.6.0-1.4
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 85,412 kB
  • sloc: ansic: 513,775; cpp: 69,493; sh: 25,650; python: 19,190; perl: 14,973; makefile: 4,178; yacc: 1,329; sql: 1,074; pascal: 620; ruby: 190; awk: 18; lisp: 7
file content (808 lines) | stat: -rw-r--r-- 22,863 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
#ifndef INCLUDES_TARANTOOL_BOX_VY_LOG_H
#define INCLUDES_TARANTOOL_BOX_VY_LOG_H
/*
 * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <small/rlist.h>

#include "salad/stailq.h"

/*
 * Data stored in vinyl is organized in ranges and runs.
 * Runs correspond to data files written to disk, while
 * ranges are used to group runs together. Sometimes, we
 * need to manipulate several ranges or runs atomically,
 * e.g. on compaction several runs are replaced with a
 * single one. To reflect events like this on disk and be
 * able to recover to a consistent state after restart, we
 * need to log all metadata changes. This module implements
 * the infrastructure necessary for such logging as well
 * as recovery.
 */

#if defined(__cplusplus)
extern "C" {
#endif /* defined(__cplusplus) */

struct xlog;
struct vclock;
struct key_def;
struct key_part_def;
struct mh_i64ptr_t;

/** Type of a metadata log record. */
enum vy_log_record_type {
	/**
	 * Create a new LSM tree.
	 * Requires vy_log_record::lsm_id, create_lsn.
	 * After rotation, it also stores space_id, index_id, group_id,
	 * key_def, create_lsn, modify_lsn, dump_lsn.
	 */
	VY_LOG_CREATE_LSM		= 0,
	/**
	 * Drop an LSM tree.
	 * Requires vy_log_record::lsm_id, drop_lsn.
	 */
	VY_LOG_DROP_LSM			= 1,
	/**
	 * Insert a new range into an LSM tree.
	 * Requires vy_log_record::lsm_id, range_id, begin, end.
	 */
	VY_LOG_INSERT_RANGE		= 2,
	/**
	 * Delete a vinyl range and all its runs.
	 * Requires vy_log_record::range_id.
	 */
	VY_LOG_DELETE_RANGE		= 3,
	/**
	 * Prepare a vinyl run file.
	 * Requires vy_log_record::lsm_id, run_id.
	 *
	 * Record of this type is written before creating a run file.
	 * It is needed to keep track of unfinished due to errors run
	 * files so that we could remove them after recovery.
	 */
	VY_LOG_PREPARE_RUN		= 4,
	/**
	 * Commit a vinyl run file creation.
	 * Requires vy_log_record::lsm_id, run_id, dump_lsn, dump_count.
	 *
	 * Written after a run file was successfully created.
	 */
	VY_LOG_CREATE_RUN		= 5,
	/**
	 * Drop a vinyl run.
	 * Requires vy_log_record::run_id, gc_lsn.
	 *
	 * A record of this type indicates that the run is not in use
	 * any more and its files can be safely removed. When the log
	 * is recovered from, this only marks the run as deleted,
	 * because we still need it for garbage collection. A run is
	 * actually freed by VY_LOG_FORGET_RUN. Runs that were
	 * deleted, but not "forgotten" are not expunged from the log
	 * on rotation.
	 */
	VY_LOG_DROP_RUN			= 6,
	/**
	 * Forget a vinyl run.
	 * Requires vy_log_record::run_id.
	 *
	 * A record of this type is written after all files left from
	 * an unused run have been successfully removed. On recovery,
	 * this results in freeing all structures associated with the
	 * run. Information about "forgotten" runs is not included in
	 * the new log on rotation.
	 */
	VY_LOG_FORGET_RUN		= 7,
	/**
	 * Insert a run slice into a range.
	 * Requires vy_log_record::range_id, run_id, slice_id, begin, end.
	 */
	VY_LOG_INSERT_SLICE		= 8,
	/**
	 * Delete a run slice.
	 * Requires vy_log_record::slice_id.
	 */
	VY_LOG_DELETE_SLICE		= 9,
	/**
	 * Log LSM tree dump. Used to update max LSN stored on disk.
	 * Requires vy_log_record::lsm_id, dump_lsn.
	 */
	VY_LOG_DUMP_LSM			= 10,
	/**
	 * We don't split vylog into snapshot and log - all records
	 * are written to the same file. Since we need to load a
	 * consistent view from a given checkpoint (for replication
	 * and backup), we write a marker after the last record
	 * corresponding to the snapshot. The following record
	 * represents the marker.
	 *
	 * See also: @only_checkpoint argument of vy_recovery_new().
	 */
	VY_LOG_SNAPSHOT			= 11,
	/**
	 * When we used LSN for identifying LSM trees in vylog, we
	 * couldn't simply recreate an LSM tree on space truncation,
	 * because in case the space had more than one LSM tree, we
	 * wouldn't be able to distinguish them after truncation.
	 * So we wrote special 'truncate' record.
	 *
	 * Now, we assign a unique id to each LSM tree and so we don't
	 * need a special record type for space truncation. If we
	 * are recovering from an old vylog, we simply ignore all
	 * 'truncate' records - this will result in replay of all
	 * WAL records written after truncation.
	 */
	VY_LOG_TRUNCATE_LSM		= 12,
	/**
	 * Modify key definition of an LSM tree.
	 * Requires vy_log_record::lsm_id, key_def, modify_lsn.
	 */
	VY_LOG_MODIFY_LSM		= 13,
	/**
	 * Forget an LSM tree.
	 * Requires vy_log_record::lsm_id.
	 *
	 * A record of this type indicates that all objects associated
	 * with the given LSM tree have been cleaned up from vylog and
	 * so the LSM tree is not needed any longer and can be removed
	 * from vylog on the next rotation.
	 */
	VY_LOG_FORGET_LSM		= 14,
	/**
	 * Prepare a new LSM tree for building.
	 * Requires vy_log_record::lsm_id, index_id, space_id, group_id,
	 * key_def.
	 *
	 * Index ALTER operation consists of two stages. First, we
	 * build a new LSM tree, checking constraints if necessary.
	 * This is done before writing the operation to WAL. Then,
	 * provided the first stage succeeded, we commit the LSM
	 * tree to the metadata log.
	 *
	 * The following record is used to prepare a new LSM tree
	 * for building. Once the index has been built, we write
	 * a VY_LOG_CREATE_LSM record to commit it.
	 */
	VY_LOG_PREPARE_LSM		= 15,
	/**
	 * This record denotes the beginning of a rebootstrap section.
	 * A rebootstrap section ends either by another record of this
	 * type or by VY_LOG_ABORT_REBOOTSTRAP or at the end of the file.
	 * All objects created between a VY_LOG_REBOOTSTRAP record and
	 * VY_LOG_ABORT_REBOOTSTRAP or another VY_LOG_REBOOTSTRAP are
	 * considered to be garbage and marked as dropped on recovery.
	 *
	 * We write a record of this type if a vylog file already exists
	 * at bootstrap time, which means we are going to rebootstrap.
	 * If rebootstrap succeeds, we rotate the vylog on checkpoint and
	 * mark all objects written before the last VY_LOG_REBOOTSTRAP
	 * record as dropped in the rotated vylog. If rebootstrap fails,
	 * we write VY_LOG_ABORT_REBOOTSTRAP on recovery.
	 */
	VY_LOG_REBOOTSTRAP		= 16,
	/**
	 * This record is written on recovery if rebootstrap failed.
	 * See also VY_LOG_REBOOTSTRAP.
	 */
	VY_LOG_ABORT_REBOOTSTRAP	= 17,

	vy_log_record_type_MAX
};

/**
 * Special value of vy_log_record::gc_lsn replaced with the signature
 * of the vylog file the record will be written to. We need it so as
 * to make sure we write the current vylog signature (not the previous
 * one) when compaction completion races with vylog rotation. Writing
 * the previous vylog signature would result in premature run file
 * collection.
 */
enum { VY_LOG_GC_LSN_CURRENT = -1 };

/** Record in the metadata log. */
struct vy_log_record {
	/** Type of the record. */
	enum vy_log_record_type type;
	/** Unique ID of the vinyl LSM tree. */
	int64_t lsm_id;
	/** Unique ID of the vinyl range. */
	int64_t range_id;
	/** Unique ID of the vinyl run. */
	int64_t run_id;
	/** Unique ID of the run slice. */
	int64_t slice_id;
	/**
	 * Msgpack key for start of the range/slice.
	 * NULL if the range/slice starts from -inf.
	 */
	const char *begin;
	/**
	 * Msgpack key for end of the range/slice.
	 * NULL if the range/slice ends with +inf.
	 */
	const char *end;
	/** Ordinal index number in the space. */
	uint32_t index_id;
	/** Space ID. */
	uint32_t space_id;
	/** Replication group ID. */
	uint32_t group_id;
	/** Index key definition, as defined by the user. */
	const struct key_def *key_def;
	/** Array of key part definitions. */
	struct key_part_def *key_parts;
	/** Number of key parts. */
	uint32_t key_part_count;
	/** LSN of the WAL row that created the LSM tree. */
	int64_t create_lsn;
	/** LSN of the WAL row that last modified the LSM tree. */
	int64_t modify_lsn;
	/**
	 * LSN of the WAL row that dropped the LSM tree or -1
	 * if the tree is still active.
	 */
	int64_t drop_lsn;
	/** Max LSN stored on disk. */
	int64_t dump_lsn;
	/**
	 * For deleted runs: LSN of the last checkpoint
	 * that uses this run.
	 */
	int64_t gc_lsn;
	/** For runs: number of dumps it took to create the run. */
	uint32_t dump_count;
	/** Link in vy_log_tx::records. */
	struct stailq_entry in_tx;
};

/** Recovery context. */
struct vy_recovery {
	/**
	 * List of all LSM trees stored in the recovery context,
	 * linked by vy_lsm_recovery_info::in_recovery.
	 */
	struct rlist lsms;
	/** space_id, index_id -> vy_lsm_recovery_info. */
	struct mh_i64ptr_t *index_id_hash;
	/** ID -> vy_lsm_recovery_info. */
	struct mh_i64ptr_t *lsm_hash;
	/** ID -> vy_range_recovery_info. */
	struct mh_i64ptr_t *range_hash;
	/** ID -> vy_run_recovery_info. */
	struct mh_i64ptr_t *run_hash;
	/** ID -> vy_slice_recovery_info. */
	struct mh_i64ptr_t *slice_hash;
	/**
	 * Maximal vinyl object ID, according to the metadata log,
	 * or -1 in case no vinyl objects were recovered.
	 */
	int64_t max_id;
	/**
	 * Set if we are currently processing a rebootstrap section,
	 * i.e. we encountered a VY_LOG_REBOOTSTRAP record and haven't
	 * seen matching VY_LOG_ABORT_REBOOTSTRAP.
	 */
	bool in_rebootstrap;
};

/** LSM tree info stored in a recovery context. */
struct vy_lsm_recovery_info {
	/** Link in vy_recovery::lsms. */
	struct rlist in_recovery;
	/** ID of the LSM tree. */
	int64_t id;
	/** Ordinal index number in the space. */
	uint32_t index_id;
	/** Space ID. */
	uint32_t space_id;
	/** Replication group ID. */
	uint32_t group_id;
	/** Array of key part definitions. */
	struct key_part_def *key_parts;
	/** Number of key parts. */
	uint32_t key_part_count;
	/**
	 * LSN of the WAL row that created the LSM tree,
	 * or -1 if the LSM tree was not committed to WAL
	 * (that is there was an VY_LOG_PREPARE_LSM record
	 * but no VY_LOG_CREATE_LSM).
	 */
	int64_t create_lsn;
	/** LSN of the WAL row that last modified the LSM tree. */
	int64_t modify_lsn;
	/**
	 * LSN of the WAL row that dropped the LSM tree or -1
	 * if the tree is still active.
	 */
	int64_t drop_lsn;
	/** Max LSN stored on disk. */
	int64_t dump_lsn;
	/**
	 * List of all ranges in the LSM tree, linked by
	 * vy_range_recovery_info::in_lsm.
	 */
	struct rlist ranges;
	/**
	 * List of all runs created for the LSM tree
	 * (both committed and not), linked by
	 * vy_run_recovery_info::in_lsm.
	 */
	struct rlist runs;
	/**
	 * Pointer to an LSM tree that is going to replace
	 * this one after successful ALTER.
	 */
	struct vy_lsm_recovery_info *prepared;
	/** Set if this LSM tree was created during rebootstrap. */
	bool in_rebootstrap;
};

/** Vinyl range info stored in a recovery context. */
struct vy_range_recovery_info {
	/** Link in vy_lsm_recovery_info::ranges. */
	struct rlist in_lsm;
	/** ID of the range. */
	int64_t id;
	/** Start of the range, stored in MsgPack array. */
	char *begin;
	/** End of the range, stored in MsgPack array. */
	char *end;
	/**
	 * List of all slices in the range, linked by
	 * vy_slice_recovery_info::in_range.
	 *
	 * Newer slices are closer to the head.
	 */
	struct rlist slices;
};

/** Run info stored in a recovery context. */
struct vy_run_recovery_info {
	/** Link in vy_lsm_recovery_info::runs. */
	struct rlist in_lsm;
	/** ID of the run. */
	int64_t id;
	/** Max LSN stored on disk. */
	int64_t dump_lsn;
	/**
	 * For deleted runs: LSN of the last checkpoint
	 * that uses this run.
	 */
	int64_t gc_lsn;
	/** Number of dumps it took to create the run. */
	uint32_t dump_count;
	/**
	 * True if the run was not committed (there's
	 * VY_LOG_PREPARE_RUN, but no VY_LOG_CREATE_RUN).
	 */
	bool is_incomplete;
	/** True if the run was dropped (VY_LOG_DROP_RUN). */
	bool is_dropped;
	/*
	 * The following field is initialized to NULL and
	 * ignored by vy_log subsystem. It may be used by
	 * the caller to store some extra information.
	 *
	 * During recovery, we store a pointer to vy_run
	 * corresponding to this object.
	 */
	void *data;
};

/** Slice info stored in a recovery context. */
struct vy_slice_recovery_info {
	/** Link in vy_range_recovery_info::slices. */
	struct rlist in_range;
	/** ID of the slice. */
	int64_t id;
	/** Run this slice was created for. */
	struct vy_run_recovery_info *run;
	/** Start of the slice, stored in MsgPack array. */
	char *begin;
	/** End of the slice, stored in MsgPack array. */
	char *end;
};

/**
 * Initialize the metadata log.
 * @dir is the directory where log files are stored.
 */
void
vy_log_init(const char *dir);

/**
 * Destroy the metadata log.
 */
void
vy_log_free(void);

/**
 * Open current vy_log file.
 */
int
vy_log_open(struct xlog *xlog);

/**
 * Rotate the metadata log. This function creates a new
 * xlog file in the log directory having vclock @vclock
 * and writes records required to recover active LSM trees.
 * The goal of log rotation is to compact the log file by
 * discarding records cancelling each other and records left
 * from dropped LSM trees.
 *
 * Returns 0 on success, -1 on failure.
 */
int
vy_log_rotate(const struct vclock *vclock);

/**
 * Remove metadata log files that are not needed to recover
 * from checkpoint @vclock.
 */
void
vy_log_collect_garbage(const struct vclock *vclock);

/**
 * Return the signature of the newest vylog to the time.
 */
int64_t
vy_log_signature(void);

/**
 * Return the path to the log file that needs to be backed up
 * in order to recover to checkpoint @vclock.
 */
const char *
vy_log_backup_path(const struct vclock *vclock);

/** Allocate a unique ID for a vinyl object. */
int64_t
vy_log_next_id(void);

/**
 * Begin a transaction in the metadata log.
 *
 * To commit the transaction, call vy_log_tx_commit() or
 * vy_log_tx_try_commit().
 */
void
vy_log_tx_begin(void);

/**
 * Commit a transaction started with vy_log_tx_begin().
 *
 * This function flushes all buffered records to disk. If it fails,
 * all records of the current transaction are discarded.
 *
 * See also vy_log_tx_try_commit().
 *
 * Returns 0 on success, -1 on failure.
 */
int
vy_log_tx_commit(void);

/**
 * Try to commit a transaction started with vy_log_tx_begin().
 *
 * Similarly to vy_log_tx_commit(), this function tries to write all
 * buffered records to disk, but in case of failure pending records
 * are not expunged from the buffer, so that the next transaction
 * will retry to flush them.
 *
 * In contrast to vy_log_tx_commit(), this function doesn't yield.
 */
void
vy_log_tx_try_commit(void);

/**
 * Write a record to the metadata log.
 *
 * This function simply appends the record to the internal buffer.
 * It must be called inside a vy_log_tx_begin/commit block, and it
 * is up to vy_log_tx_commit() to actually write the record to disk.
 *
 * Returns 0 on success, -1 on failure.
 */
void
vy_log_write(const struct vy_log_record *record);

/**
 * Bootstrap vy_log.
 */
int
vy_log_bootstrap(void);

/**
 * Prepare the metadata log for recovery from the file having
 * vclock @vclock and return the recovery context.
 *
 * After this function is called, LSM trees may be recovered from
 * the log using vy_recovery methods. When recovery is complete,
 * one must call vy_log_end_recovery(). After that the recovery context
 * may be deleted with vy_recovery_delete().
 *
 * Returns NULL on failure.
 */
struct vy_recovery *
vy_log_begin_recovery(const struct vclock *vclock);

/**
 * Finish recovery from the metadata log.
 *
 * This function destroys the recovery context that was created by
 * vy_log_begin_recovery(), opens the log file for appending, and
 * flushes all records written to the log buffer during recovery.
 *
 * Return 0 on success, -1 on failure.
 */
int
vy_log_end_recovery(void);

/** Flags passed to vy_recovery_new(). */
enum vy_recovery_flag {
	/**
	 * Do not load records written to the log after checkpoint,
	 * i.e. get a consistent view of vinyl database at the time
	 * of the last checkpoint.
	 */
	VY_RECOVERY_LOAD_CHECKPOINT	= 1 << 0,
	/**
	 * Consider the last attempt to rebootstrap aborted even if
	 * there's no VY_LOG_ABORT_REBOOTSTRAP record.
	 */
	VY_RECOVERY_ABORT_REBOOTSTRAP	= 1 << 1,
};

/**
 * Create a recovery context from the metadata log created
 * by checkpoint with the given signature.
 *
 * For valid values of @flags, see vy_recovery_flag.
 *
 * Returns NULL on failure.
 */
struct vy_recovery *
vy_recovery_new(int64_t signature, int flags);

/**
 * Free a recovery context created by vy_recovery_new().
 */
void
vy_recovery_delete(struct vy_recovery *recovery);

/**
 * Look up the last incarnation of an LSM tree stored in a recovery context.
 *
 * Returns NULL if the LSM tree was not found.
 */
struct vy_lsm_recovery_info *
vy_recovery_lsm_by_index_id(struct vy_recovery *recovery,
			    uint32_t space_id, uint32_t index_id);

/**
 * Initialize a log record with default values.
 * Note, a key is only written to the log file
 * if its value is different from default.
 */
static inline void
vy_log_record_init(struct vy_log_record *record)
{
	memset(record, 0, sizeof(*record));
}

/** Helper to log a vinyl LSM tree preparation. */
static inline void
vy_log_prepare_lsm(int64_t id, uint32_t space_id, uint32_t index_id,
		   uint32_t group_id, const struct key_def *key_def)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_PREPARE_LSM;
	record.lsm_id = id;
	record.space_id = space_id;
	record.index_id = index_id;
	record.group_id = group_id;
	record.key_def = key_def;
	vy_log_write(&record);
}

/** Helper to log a vinyl LSM tree creation. */
static inline void
vy_log_create_lsm(int64_t id, int64_t create_lsn)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_CREATE_LSM;
	record.lsm_id = id;
	record.create_lsn = create_lsn;
	vy_log_write(&record);
}

/** Helper to log a vinyl LSM tree modification. */
static inline void
vy_log_modify_lsm(int64_t id, const struct key_def *key_def, int64_t modify_lsn)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_MODIFY_LSM;
	record.lsm_id = id;
	record.key_def = key_def;
	record.modify_lsn = modify_lsn;
	vy_log_write(&record);
}

/** Helper to log  a vinyl LSM tree cleanup. */
static inline void
vy_log_forget_lsm(int64_t id)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_FORGET_LSM;
	record.lsm_id = id;
	vy_log_write(&record);
}

/** Helper to log a vinyl LSM tree drop. */
static inline void
vy_log_drop_lsm(int64_t id, int64_t drop_lsn)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_DROP_LSM;
	record.lsm_id = id;
	record.drop_lsn = drop_lsn;
	vy_log_write(&record);
}

/** Helper to log a vinyl range insertion. */
static inline void
vy_log_insert_range(int64_t lsm_id, int64_t range_id,
		    const char *begin, const char *end)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_INSERT_RANGE;
	record.lsm_id = lsm_id;
	record.range_id = range_id;
	record.begin = begin;
	record.end = end;
	vy_log_write(&record);
}

/** Helper to log a vinyl range deletion. */
static inline void
vy_log_delete_range(int64_t range_id)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_DELETE_RANGE;
	record.range_id = range_id;
	vy_log_write(&record);
}

/** Helper to log a vinyl run file creation. */
static inline void
vy_log_prepare_run(int64_t lsm_id, int64_t run_id)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_PREPARE_RUN;
	record.lsm_id = lsm_id;
	record.run_id = run_id;
	vy_log_write(&record);
}

/** Helper to log a vinyl run creation. */
static inline void
vy_log_create_run(int64_t lsm_id, int64_t run_id,
		  int64_t dump_lsn, uint32_t dump_count)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_CREATE_RUN;
	record.lsm_id = lsm_id;
	record.run_id = run_id;
	record.dump_lsn = dump_lsn;
	record.dump_count = dump_count;
	vy_log_write(&record);
}

/** Helper to log a run deletion. */
static inline void
vy_log_drop_run(int64_t run_id, int64_t gc_lsn)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_DROP_RUN;
	record.run_id = run_id;
	record.gc_lsn = gc_lsn;
	vy_log_write(&record);
}

/** Helper to log a run cleanup. */
static inline void
vy_log_forget_run(int64_t run_id)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_FORGET_RUN;
	record.run_id = run_id;
	vy_log_write(&record);
}

/** Helper to log creation of a run slice. */
static inline void
vy_log_insert_slice(int64_t range_id, int64_t run_id, int64_t slice_id,
		    const char *begin, const char *end)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_INSERT_SLICE;
	record.range_id = range_id;
	record.run_id = run_id;
	record.slice_id = slice_id;
	record.begin = begin;
	record.end = end;
	vy_log_write(&record);
}

/** Helper to log deletion of a run slice. */
static inline void
vy_log_delete_slice(int64_t slice_id)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_DELETE_SLICE;
	record.slice_id = slice_id;
	vy_log_write(&record);
}

/** Helper to log LSM tree dump. */
static inline void
vy_log_dump_lsm(int64_t id, int64_t dump_lsn)
{
	struct vy_log_record record;
	vy_log_record_init(&record);
	record.type = VY_LOG_DUMP_LSM;
	record.lsm_id = id;
	record.dump_lsn = dump_lsn;
	vy_log_write(&record);
}

#if defined(__cplusplus)
} /* extern "C" */
#endif /* defined(__cplusplus) */

#endif /* INCLUDES_TARANTOOL_BOX_VY_LOG_H */