summaryrefslogtreecommitdiffstats
path: root/reftable/record.h
blob: d778133e6ec56ccc1e17ad2d5b0435420dce6e29 (plain)
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
/*
Copyright 2020 Google LLC

Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/

#ifndef RECORD_H
#define RECORD_H

#include "system.h"

#include <stdint.h>

#include "reftable-record.h"

/*
 * A substring of existing string data. This structure takes no responsibility
 * for the lifetime of the data it points to.
 */
struct string_view {
	uint8_t *buf;
	size_t len;
};

/* Advance `s.buf` by `n`, and decrease length. */
static inline void string_view_consume(struct string_view *s, int n)
{
	s->buf += n;
	s->len -= n;
}

/* utilities for de/encoding varints */

int get_var_int(uint64_t *dest, struct string_view *in);
int put_var_int(struct string_view *dest, uint64_t val);

/* Methods for records. */
struct reftable_record_vtable {
	/* encode the key of to a uint8_t strbuf. */
	void (*key)(const void *rec, struct strbuf *dest);

	/* The record type of ('r' for ref). */
	uint8_t type;

	void (*copy_from)(void *dest, const void *src, int hash_size);

	/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
	 * vs ref deletion) */
	uint8_t (*val_type)(const void *rec);

	/* encodes rec into dest, returning how much space was used. */
	int (*encode)(const void *rec, struct string_view dest, int hash_size);

	/* decode data from `src` into the record. */
	int (*decode)(void *rec, struct strbuf key, uint8_t extra,
		      struct string_view src, int hash_size,
		      struct strbuf *scratch);

	/* deallocate and null the record. */
	void (*release)(void *rec);

	/* is this a tombstone? */
	int (*is_deletion)(const void *rec);

	/* Are two records equal? This assumes they have the same type. Returns 0 for non-equal. */
	int (*equal)(const void *a, const void *b, int hash_size);

	/*
	 * Compare keys of two records with each other. The records must have
	 * the same type.
	 */
	int (*cmp)(const void *a, const void *b);

	/* Print on stdout, for debugging. */
	void (*print)(const void *rec, int hash_size);
};

/* returns true for recognized block types. Block start with the block type. */
int reftable_is_block_type(uint8_t typ);

/* Encode `key` into `dest`. Sets `is_restart` to indicate a restart. Returns
 * number of bytes written. */
int reftable_encode_key(int *is_restart, struct string_view dest,
			struct strbuf prev_key, struct strbuf key,
			uint8_t extra);

/* Decode a record's key lengths. */
int reftable_decode_keylen(struct string_view in,
			   uint64_t *prefix_len,
			   uint64_t *suffix_len,
			   uint8_t *extra);

/*
 * Decode into `last_key` and `extra` from `in`. `last_key` is expected to
 * contain the decoded key of the preceding record, if any.
 */
int reftable_decode_key(struct strbuf *last_key, uint8_t *extra,
			struct string_view in);

/* reftable_index_record are used internally to speed up lookups. */
struct reftable_index_record {
	uint64_t offset; /* Offset of block */
	struct strbuf last_key; /* Last key of the block. */
};

/* reftable_obj_record stores an object ID => ref mapping. */
struct reftable_obj_record {
	uint8_t *hash_prefix; /* leading bytes of the object ID */
	int hash_prefix_len; /* number of leading bytes. Constant
			      * across a single table. */
	uint64_t *offsets; /* a vector of file offsets. */
	int offset_len;
};

/* record is a generic wrapper for different types of records. It is normally
 * created on the stack, or embedded within another struct. If the type is
 * known, a fresh instance can be initialized explicitly. Otherwise, use
 * `reftable_record_init()` to initialize generically (as the index_record is
 * not valid as 0-initialized structure)
 */
struct reftable_record {
	uint8_t type;
	union {
		struct reftable_ref_record ref;
		struct reftable_log_record log;
		struct reftable_obj_record obj;
		struct reftable_index_record idx;
	} u;
};

/* Initialize the reftable record for the given type */
void reftable_record_init(struct reftable_record *rec, uint8_t typ);

/* see struct record_vtable */
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
void reftable_record_print(struct reftable_record *rec, int hash_size);
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
void reftable_record_copy_from(struct reftable_record *rec,
			       struct reftable_record *src, int hash_size);
uint8_t reftable_record_val_type(struct reftable_record *rec);
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
			   int hash_size);
int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
			   uint8_t extra, struct string_view src,
			   int hash_size, struct strbuf *scratch);
int reftable_record_is_deletion(struct reftable_record *rec);

static inline uint8_t reftable_record_type(struct reftable_record *rec)
{
	return rec->type;
}

/* frees and zeroes out the embedded record */
void reftable_record_release(struct reftable_record *rec);

/* for qsort. */
int reftable_ref_record_compare_name(const void *a, const void *b);

/* for qsort. */
int reftable_log_record_compare_key(const void *a, const void *b);

#endif