reftable/block: fix binary search over restart counter
[git.git] / reftable / record.c
blob9c31feb35c8232fe7d930ba10ecdebf5f5f95276
1 /*
2 Copyright 2020 Google LLC
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
7 */
9 /* record.c - methods for different types of records. */
11 #include "record.h"
13 #include "system.h"
14 #include "constants.h"
15 #include "reftable-error.h"
16 #include "basics.h"
18 static struct reftable_record_vtable *
19 reftable_record_vtable(struct reftable_record *rec);
20 static void *reftable_record_data(struct reftable_record *rec);
22 int get_var_int(uint64_t *dest, struct string_view *in)
24 int ptr = 0;
25 uint64_t val;
27 if (in->len == 0)
28 return -1;
29 val = in->buf[ptr] & 0x7f;
31 while (in->buf[ptr] & 0x80) {
32 ptr++;
33 if (ptr > in->len) {
34 return -1;
36 val = (val + 1) << 7 | (uint64_t)(in->buf[ptr] & 0x7f);
39 *dest = val;
40 return ptr + 1;
43 int put_var_int(struct string_view *dest, uint64_t val)
45 uint8_t buf[10] = { 0 };
46 int i = 9;
47 int n = 0;
48 buf[i] = (uint8_t)(val & 0x7f);
49 i--;
50 while (1) {
51 val >>= 7;
52 if (!val) {
53 break;
55 val--;
56 buf[i] = 0x80 | (uint8_t)(val & 0x7f);
57 i--;
60 n = sizeof(buf) - i - 1;
61 if (dest->len < n)
62 return -1;
63 memcpy(dest->buf, &buf[i + 1], n);
64 return n;
67 int reftable_is_block_type(uint8_t typ)
69 switch (typ) {
70 case BLOCK_TYPE_REF:
71 case BLOCK_TYPE_LOG:
72 case BLOCK_TYPE_OBJ:
73 case BLOCK_TYPE_INDEX:
74 return 1;
76 return 0;
79 const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec)
81 switch (rec->value_type) {
82 case REFTABLE_REF_VAL1:
83 return rec->value.val1;
84 case REFTABLE_REF_VAL2:
85 return rec->value.val2.value;
86 default:
87 return NULL;
91 const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec)
93 switch (rec->value_type) {
94 case REFTABLE_REF_VAL2:
95 return rec->value.val2.target_value;
96 default:
97 return NULL;
101 static int decode_string(struct strbuf *dest, struct string_view in)
103 int start_len = in.len;
104 uint64_t tsize = 0;
105 int n = get_var_int(&tsize, &in);
106 if (n <= 0)
107 return -1;
108 string_view_consume(&in, n);
109 if (in.len < tsize)
110 return -1;
112 strbuf_reset(dest);
113 strbuf_add(dest, in.buf, tsize);
114 string_view_consume(&in, tsize);
116 return start_len - in.len;
119 static int encode_string(char *str, struct string_view s)
121 struct string_view start = s;
122 int l = strlen(str);
123 int n = put_var_int(&s, l);
124 if (n < 0)
125 return -1;
126 string_view_consume(&s, n);
127 if (s.len < l)
128 return -1;
129 memcpy(s.buf, str, l);
130 string_view_consume(&s, l);
132 return start.len - s.len;
135 int reftable_encode_key(int *restart, struct string_view dest,
136 struct strbuf prev_key, struct strbuf key,
137 uint8_t extra)
139 struct string_view start = dest;
140 int prefix_len = common_prefix_size(&prev_key, &key);
141 uint64_t suffix_len = key.len - prefix_len;
142 int n = put_var_int(&dest, (uint64_t)prefix_len);
143 if (n < 0)
144 return -1;
145 string_view_consume(&dest, n);
147 *restart = (prefix_len == 0);
149 n = put_var_int(&dest, suffix_len << 3 | (uint64_t)extra);
150 if (n < 0)
151 return -1;
152 string_view_consume(&dest, n);
154 if (dest.len < suffix_len)
155 return -1;
156 memcpy(dest.buf, key.buf + prefix_len, suffix_len);
157 string_view_consume(&dest, suffix_len);
159 return start.len - dest.len;
162 int reftable_decode_key(struct strbuf *key, uint8_t *extra,
163 struct strbuf last_key, struct string_view in)
165 int start_len = in.len;
166 uint64_t prefix_len = 0;
167 uint64_t suffix_len = 0;
168 int n = get_var_int(&prefix_len, &in);
169 if (n < 0)
170 return -1;
171 string_view_consume(&in, n);
173 if (prefix_len > last_key.len)
174 return -1;
176 n = get_var_int(&suffix_len, &in);
177 if (n <= 0)
178 return -1;
179 string_view_consume(&in, n);
181 *extra = (uint8_t)(suffix_len & 0x7);
182 suffix_len >>= 3;
184 if (in.len < suffix_len)
185 return -1;
187 strbuf_reset(key);
188 strbuf_add(key, last_key.buf, prefix_len);
189 strbuf_add(key, in.buf, suffix_len);
190 string_view_consume(&in, suffix_len);
192 return start_len - in.len;
195 static void reftable_ref_record_key(const void *r, struct strbuf *dest)
197 const struct reftable_ref_record *rec =
198 (const struct reftable_ref_record *)r;
199 strbuf_reset(dest);
200 strbuf_addstr(dest, rec->refname);
203 static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
204 int hash_size)
206 struct reftable_ref_record *ref = rec;
207 const struct reftable_ref_record *src = src_rec;
208 assert(hash_size > 0);
210 /* This is simple and correct, but we could probably reuse the hash
211 * fields. */
212 reftable_ref_record_release(ref);
213 if (src->refname) {
214 ref->refname = xstrdup(src->refname);
216 ref->update_index = src->update_index;
217 ref->value_type = src->value_type;
218 switch (src->value_type) {
219 case REFTABLE_REF_DELETION:
220 break;
221 case REFTABLE_REF_VAL1:
222 memcpy(ref->value.val1, src->value.val1, hash_size);
223 break;
224 case REFTABLE_REF_VAL2:
225 memcpy(ref->value.val2.value, src->value.val2.value, hash_size);
226 memcpy(ref->value.val2.target_value,
227 src->value.val2.target_value, hash_size);
228 break;
229 case REFTABLE_REF_SYMREF:
230 ref->value.symref = xstrdup(src->value.symref);
231 break;
235 static char hexdigit(int c)
237 if (c <= 9)
238 return '0' + c;
239 return 'a' + (c - 10);
242 static void hex_format(char *dest, const unsigned char *src, int hash_size)
244 assert(hash_size > 0);
245 if (src) {
246 int i = 0;
247 for (i = 0; i < hash_size; i++) {
248 dest[2 * i] = hexdigit(src[i] >> 4);
249 dest[2 * i + 1] = hexdigit(src[i] & 0xf);
251 dest[2 * hash_size] = 0;
255 static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
256 int hash_size)
258 char hex[GIT_MAX_HEXSZ + 1] = { 0 }; /* BUG */
259 printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
260 switch (ref->value_type) {
261 case REFTABLE_REF_SYMREF:
262 printf("=> %s", ref->value.symref);
263 break;
264 case REFTABLE_REF_VAL2:
265 hex_format(hex, ref->value.val2.value, hash_size);
266 printf("val 2 %s", hex);
267 hex_format(hex, ref->value.val2.target_value,
268 hash_size);
269 printf("(T %s)", hex);
270 break;
271 case REFTABLE_REF_VAL1:
272 hex_format(hex, ref->value.val1, hash_size);
273 printf("val 1 %s", hex);
274 break;
275 case REFTABLE_REF_DELETION:
276 printf("delete");
277 break;
279 printf("}\n");
282 void reftable_ref_record_print(const struct reftable_ref_record *ref,
283 uint32_t hash_id) {
284 reftable_ref_record_print_sz(ref, hash_size(hash_id));
287 static void reftable_ref_record_release_void(void *rec)
289 reftable_ref_record_release(rec);
292 void reftable_ref_record_release(struct reftable_ref_record *ref)
294 switch (ref->value_type) {
295 case REFTABLE_REF_SYMREF:
296 reftable_free(ref->value.symref);
297 break;
298 case REFTABLE_REF_VAL2:
299 break;
300 case REFTABLE_REF_VAL1:
301 break;
302 case REFTABLE_REF_DELETION:
303 break;
304 default:
305 abort();
308 reftable_free(ref->refname);
309 memset(ref, 0, sizeof(struct reftable_ref_record));
312 static uint8_t reftable_ref_record_val_type(const void *rec)
314 const struct reftable_ref_record *r =
315 (const struct reftable_ref_record *)rec;
316 return r->value_type;
319 static int reftable_ref_record_encode(const void *rec, struct string_view s,
320 int hash_size)
322 const struct reftable_ref_record *r =
323 (const struct reftable_ref_record *)rec;
324 struct string_view start = s;
325 int n = put_var_int(&s, r->update_index);
326 assert(hash_size > 0);
327 if (n < 0)
328 return -1;
329 string_view_consume(&s, n);
331 switch (r->value_type) {
332 case REFTABLE_REF_SYMREF:
333 n = encode_string(r->value.symref, s);
334 if (n < 0) {
335 return -1;
337 string_view_consume(&s, n);
338 break;
339 case REFTABLE_REF_VAL2:
340 if (s.len < 2 * hash_size) {
341 return -1;
343 memcpy(s.buf, r->value.val2.value, hash_size);
344 string_view_consume(&s, hash_size);
345 memcpy(s.buf, r->value.val2.target_value, hash_size);
346 string_view_consume(&s, hash_size);
347 break;
348 case REFTABLE_REF_VAL1:
349 if (s.len < hash_size) {
350 return -1;
352 memcpy(s.buf, r->value.val1, hash_size);
353 string_view_consume(&s, hash_size);
354 break;
355 case REFTABLE_REF_DELETION:
356 break;
357 default:
358 abort();
361 return start.len - s.len;
364 static int reftable_ref_record_decode(void *rec, struct strbuf key,
365 uint8_t val_type, struct string_view in,
366 int hash_size)
368 struct reftable_ref_record *r = rec;
369 struct string_view start = in;
370 uint64_t update_index = 0;
371 int n = get_var_int(&update_index, &in);
372 if (n < 0)
373 return n;
374 string_view_consume(&in, n);
376 reftable_ref_record_release(r);
378 assert(hash_size > 0);
380 r->refname = reftable_malloc(key.len + 1);
381 memcpy(r->refname, key.buf, key.len);
382 r->refname[key.len] = 0;
384 r->update_index = update_index;
385 r->value_type = val_type;
386 switch (val_type) {
387 case REFTABLE_REF_VAL1:
388 if (in.len < hash_size) {
389 return -1;
392 memcpy(r->value.val1, in.buf, hash_size);
393 string_view_consume(&in, hash_size);
394 break;
396 case REFTABLE_REF_VAL2:
397 if (in.len < 2 * hash_size) {
398 return -1;
401 memcpy(r->value.val2.value, in.buf, hash_size);
402 string_view_consume(&in, hash_size);
404 memcpy(r->value.val2.target_value, in.buf, hash_size);
405 string_view_consume(&in, hash_size);
406 break;
408 case REFTABLE_REF_SYMREF: {
409 struct strbuf dest = STRBUF_INIT;
410 int n = decode_string(&dest, in);
411 if (n < 0) {
412 return -1;
414 string_view_consume(&in, n);
415 r->value.symref = dest.buf;
416 } break;
418 case REFTABLE_REF_DELETION:
419 break;
420 default:
421 abort();
422 break;
425 return start.len - in.len;
428 static int reftable_ref_record_is_deletion_void(const void *p)
430 return reftable_ref_record_is_deletion(
431 (const struct reftable_ref_record *)p);
434 static int reftable_ref_record_equal_void(const void *a,
435 const void *b, int hash_size)
437 struct reftable_ref_record *ra = (struct reftable_ref_record *) a;
438 struct reftable_ref_record *rb = (struct reftable_ref_record *) b;
439 return reftable_ref_record_equal(ra, rb, hash_size);
442 static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
444 const struct reftable_ref_record *a = _a;
445 const struct reftable_ref_record *b = _b;
446 return strcmp(a->refname, b->refname);
449 static void reftable_ref_record_print_void(const void *rec,
450 int hash_size)
452 reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
455 static struct reftable_record_vtable reftable_ref_record_vtable = {
456 .key = &reftable_ref_record_key,
457 .type = BLOCK_TYPE_REF,
458 .copy_from = &reftable_ref_record_copy_from,
459 .val_type = &reftable_ref_record_val_type,
460 .encode = &reftable_ref_record_encode,
461 .decode = &reftable_ref_record_decode,
462 .release = &reftable_ref_record_release_void,
463 .is_deletion = &reftable_ref_record_is_deletion_void,
464 .equal = &reftable_ref_record_equal_void,
465 .cmp = &reftable_ref_record_cmp_void,
466 .print = &reftable_ref_record_print_void,
469 static void reftable_obj_record_key(const void *r, struct strbuf *dest)
471 const struct reftable_obj_record *rec =
472 (const struct reftable_obj_record *)r;
473 strbuf_reset(dest);
474 strbuf_add(dest, rec->hash_prefix, rec->hash_prefix_len);
477 static void reftable_obj_record_release(void *rec)
479 struct reftable_obj_record *obj = rec;
480 FREE_AND_NULL(obj->hash_prefix);
481 FREE_AND_NULL(obj->offsets);
482 memset(obj, 0, sizeof(struct reftable_obj_record));
485 static void reftable_obj_record_print(const void *rec, int hash_size)
487 const struct reftable_obj_record *obj = rec;
488 char hex[GIT_MAX_HEXSZ + 1] = { 0 };
489 struct strbuf offset_str = STRBUF_INIT;
490 int i;
492 for (i = 0; i < obj->offset_len; i++)
493 strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
494 hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
495 printf("prefix %s (len %d), offsets [%s]\n",
496 hex, obj->hash_prefix_len, offset_str.buf);
497 strbuf_release(&offset_str);
500 static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
501 int hash_size)
503 struct reftable_obj_record *obj = rec;
504 const struct reftable_obj_record *src =
505 (const struct reftable_obj_record *)src_rec;
507 reftable_obj_record_release(obj);
509 REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
510 obj->hash_prefix_len = src->hash_prefix_len;
511 if (src->hash_prefix_len)
512 memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
514 REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
515 obj->offset_len = src->offset_len;
516 COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
519 static uint8_t reftable_obj_record_val_type(const void *rec)
521 const struct reftable_obj_record *r = rec;
522 if (r->offset_len > 0 && r->offset_len < 8)
523 return r->offset_len;
524 return 0;
527 static int reftable_obj_record_encode(const void *rec, struct string_view s,
528 int hash_size)
530 const struct reftable_obj_record *r = rec;
531 struct string_view start = s;
532 int i = 0;
533 int n = 0;
534 uint64_t last = 0;
535 if (r->offset_len == 0 || r->offset_len >= 8) {
536 n = put_var_int(&s, r->offset_len);
537 if (n < 0) {
538 return -1;
540 string_view_consume(&s, n);
542 if (r->offset_len == 0)
543 return start.len - s.len;
544 n = put_var_int(&s, r->offsets[0]);
545 if (n < 0)
546 return -1;
547 string_view_consume(&s, n);
549 last = r->offsets[0];
550 for (i = 1; i < r->offset_len; i++) {
551 int n = put_var_int(&s, r->offsets[i] - last);
552 if (n < 0) {
553 return -1;
555 string_view_consume(&s, n);
556 last = r->offsets[i];
558 return start.len - s.len;
561 static int reftable_obj_record_decode(void *rec, struct strbuf key,
562 uint8_t val_type, struct string_view in,
563 int hash_size)
565 struct string_view start = in;
566 struct reftable_obj_record *r = rec;
567 uint64_t count = val_type;
568 int n = 0;
569 uint64_t last;
570 int j;
572 reftable_obj_record_release(r);
574 REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
575 memcpy(r->hash_prefix, key.buf, key.len);
576 r->hash_prefix_len = key.len;
578 if (val_type == 0) {
579 n = get_var_int(&count, &in);
580 if (n < 0) {
581 return n;
584 string_view_consume(&in, n);
587 r->offsets = NULL;
588 r->offset_len = 0;
589 if (count == 0)
590 return start.len - in.len;
592 REFTABLE_ALLOC_ARRAY(r->offsets, count);
593 r->offset_len = count;
595 n = get_var_int(&r->offsets[0], &in);
596 if (n < 0)
597 return n;
598 string_view_consume(&in, n);
600 last = r->offsets[0];
601 j = 1;
602 while (j < count) {
603 uint64_t delta = 0;
604 int n = get_var_int(&delta, &in);
605 if (n < 0) {
606 return n;
608 string_view_consume(&in, n);
610 last = r->offsets[j] = (delta + last);
611 j++;
613 return start.len - in.len;
616 static int not_a_deletion(const void *p)
618 return 0;
621 static int reftable_obj_record_equal_void(const void *a, const void *b, int hash_size)
623 struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
624 struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
626 if (ra->hash_prefix_len != rb->hash_prefix_len
627 || ra->offset_len != rb->offset_len)
628 return 0;
630 if (ra->hash_prefix_len &&
631 memcmp(ra->hash_prefix, rb->hash_prefix, ra->hash_prefix_len))
632 return 0;
633 if (ra->offset_len &&
634 memcmp(ra->offsets, rb->offsets, ra->offset_len * sizeof(uint64_t)))
635 return 0;
637 return 1;
640 static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
642 const struct reftable_obj_record *a = _a;
643 const struct reftable_obj_record *b = _b;
644 int cmp;
646 cmp = memcmp(a->hash_prefix, b->hash_prefix,
647 a->hash_prefix_len > b->hash_prefix_len ?
648 a->hash_prefix_len : b->hash_prefix_len);
649 if (cmp)
650 return cmp;
653 * When the prefix is the same then the object record that is longer is
654 * considered to be bigger.
656 return a->hash_prefix_len - b->hash_prefix_len;
659 static struct reftable_record_vtable reftable_obj_record_vtable = {
660 .key = &reftable_obj_record_key,
661 .type = BLOCK_TYPE_OBJ,
662 .copy_from = &reftable_obj_record_copy_from,
663 .val_type = &reftable_obj_record_val_type,
664 .encode = &reftable_obj_record_encode,
665 .decode = &reftable_obj_record_decode,
666 .release = &reftable_obj_record_release,
667 .is_deletion = &not_a_deletion,
668 .equal = &reftable_obj_record_equal_void,
669 .cmp = &reftable_obj_record_cmp_void,
670 .print = &reftable_obj_record_print,
673 static void reftable_log_record_print_sz(struct reftable_log_record *log,
674 int hash_size)
676 char hex[GIT_MAX_HEXSZ + 1] = { 0 };
678 switch (log->value_type) {
679 case REFTABLE_LOG_DELETION:
680 printf("log{%s(%" PRIu64 ") delete\n", log->refname,
681 log->update_index);
682 break;
683 case REFTABLE_LOG_UPDATE:
684 printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
685 log->refname, log->update_index,
686 log->value.update.name ? log->value.update.name : "",
687 log->value.update.email ? log->value.update.email : "",
688 log->value.update.time,
689 log->value.update.tz_offset);
690 hex_format(hex, log->value.update.old_hash, hash_size);
691 printf("%s => ", hex);
692 hex_format(hex, log->value.update.new_hash, hash_size);
693 printf("%s\n\n%s\n}\n", hex,
694 log->value.update.message ? log->value.update.message : "");
695 break;
699 void reftable_log_record_print(struct reftable_log_record *log,
700 uint32_t hash_id)
702 reftable_log_record_print_sz(log, hash_size(hash_id));
705 static void reftable_log_record_key(const void *r, struct strbuf *dest)
707 const struct reftable_log_record *rec =
708 (const struct reftable_log_record *)r;
709 int len = strlen(rec->refname);
710 uint8_t i64[8];
711 uint64_t ts = 0;
712 strbuf_reset(dest);
713 strbuf_add(dest, (uint8_t *)rec->refname, len + 1);
715 ts = (~ts) - rec->update_index;
716 put_be64(&i64[0], ts);
717 strbuf_add(dest, i64, sizeof(i64));
720 static void reftable_log_record_copy_from(void *rec, const void *src_rec,
721 int hash_size)
723 struct reftable_log_record *dst = rec;
724 const struct reftable_log_record *src =
725 (const struct reftable_log_record *)src_rec;
727 reftable_log_record_release(dst);
728 *dst = *src;
729 if (dst->refname) {
730 dst->refname = xstrdup(dst->refname);
732 switch (dst->value_type) {
733 case REFTABLE_LOG_DELETION:
734 break;
735 case REFTABLE_LOG_UPDATE:
736 if (dst->value.update.email) {
737 dst->value.update.email =
738 xstrdup(dst->value.update.email);
740 if (dst->value.update.name) {
741 dst->value.update.name =
742 xstrdup(dst->value.update.name);
744 if (dst->value.update.message) {
745 dst->value.update.message =
746 xstrdup(dst->value.update.message);
749 if (dst->value.update.new_hash) {
750 REFTABLE_ALLOC_ARRAY(dst->value.update.new_hash, hash_size);
751 memcpy(dst->value.update.new_hash,
752 src->value.update.new_hash, hash_size);
754 if (dst->value.update.old_hash) {
755 REFTABLE_ALLOC_ARRAY(dst->value.update.old_hash, hash_size);
756 memcpy(dst->value.update.old_hash,
757 src->value.update.old_hash, hash_size);
759 break;
763 static void reftable_log_record_release_void(void *rec)
765 struct reftable_log_record *r = rec;
766 reftable_log_record_release(r);
769 void reftable_log_record_release(struct reftable_log_record *r)
771 reftable_free(r->refname);
772 switch (r->value_type) {
773 case REFTABLE_LOG_DELETION:
774 break;
775 case REFTABLE_LOG_UPDATE:
776 reftable_free(r->value.update.new_hash);
777 reftable_free(r->value.update.old_hash);
778 reftable_free(r->value.update.name);
779 reftable_free(r->value.update.email);
780 reftable_free(r->value.update.message);
781 break;
783 memset(r, 0, sizeof(struct reftable_log_record));
786 static uint8_t reftable_log_record_val_type(const void *rec)
788 const struct reftable_log_record *log =
789 (const struct reftable_log_record *)rec;
791 return reftable_log_record_is_deletion(log) ? 0 : 1;
794 static uint8_t zero[GIT_SHA256_RAWSZ] = { 0 };
796 static int reftable_log_record_encode(const void *rec, struct string_view s,
797 int hash_size)
799 const struct reftable_log_record *r = rec;
800 struct string_view start = s;
801 int n = 0;
802 uint8_t *oldh = NULL;
803 uint8_t *newh = NULL;
804 if (reftable_log_record_is_deletion(r))
805 return 0;
807 oldh = r->value.update.old_hash;
808 newh = r->value.update.new_hash;
809 if (!oldh) {
810 oldh = zero;
812 if (!newh) {
813 newh = zero;
816 if (s.len < 2 * hash_size)
817 return -1;
819 memcpy(s.buf, oldh, hash_size);
820 memcpy(s.buf + hash_size, newh, hash_size);
821 string_view_consume(&s, 2 * hash_size);
823 n = encode_string(r->value.update.name ? r->value.update.name : "", s);
824 if (n < 0)
825 return -1;
826 string_view_consume(&s, n);
828 n = encode_string(r->value.update.email ? r->value.update.email : "",
830 if (n < 0)
831 return -1;
832 string_view_consume(&s, n);
834 n = put_var_int(&s, r->value.update.time);
835 if (n < 0)
836 return -1;
837 string_view_consume(&s, n);
839 if (s.len < 2)
840 return -1;
842 put_be16(s.buf, r->value.update.tz_offset);
843 string_view_consume(&s, 2);
845 n = encode_string(
846 r->value.update.message ? r->value.update.message : "", s);
847 if (n < 0)
848 return -1;
849 string_view_consume(&s, n);
851 return start.len - s.len;
854 static int reftable_log_record_decode(void *rec, struct strbuf key,
855 uint8_t val_type, struct string_view in,
856 int hash_size)
858 struct string_view start = in;
859 struct reftable_log_record *r = rec;
860 uint64_t max = 0;
861 uint64_t ts = 0;
862 struct strbuf dest = STRBUF_INIT;
863 int n;
865 if (key.len <= 9 || key.buf[key.len - 9] != 0)
866 return REFTABLE_FORMAT_ERROR;
868 r->refname = reftable_realloc(r->refname, key.len - 8);
869 memcpy(r->refname, key.buf, key.len - 8);
870 ts = get_be64(key.buf + key.len - 8);
872 r->update_index = (~max) - ts;
874 if (val_type != r->value_type) {
875 switch (r->value_type) {
876 case REFTABLE_LOG_UPDATE:
877 FREE_AND_NULL(r->value.update.old_hash);
878 FREE_AND_NULL(r->value.update.new_hash);
879 FREE_AND_NULL(r->value.update.message);
880 FREE_AND_NULL(r->value.update.email);
881 FREE_AND_NULL(r->value.update.name);
882 break;
883 case REFTABLE_LOG_DELETION:
884 break;
888 r->value_type = val_type;
889 if (val_type == REFTABLE_LOG_DELETION)
890 return 0;
892 if (in.len < 2 * hash_size)
893 return REFTABLE_FORMAT_ERROR;
895 r->value.update.old_hash =
896 reftable_realloc(r->value.update.old_hash, hash_size);
897 r->value.update.new_hash =
898 reftable_realloc(r->value.update.new_hash, hash_size);
900 memcpy(r->value.update.old_hash, in.buf, hash_size);
901 memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
903 string_view_consume(&in, 2 * hash_size);
905 n = decode_string(&dest, in);
906 if (n < 0)
907 goto done;
908 string_view_consume(&in, n);
910 r->value.update.name =
911 reftable_realloc(r->value.update.name, dest.len + 1);
912 memcpy(r->value.update.name, dest.buf, dest.len);
913 r->value.update.name[dest.len] = 0;
915 strbuf_reset(&dest);
916 n = decode_string(&dest, in);
917 if (n < 0)
918 goto done;
919 string_view_consume(&in, n);
921 r->value.update.email =
922 reftable_realloc(r->value.update.email, dest.len + 1);
923 memcpy(r->value.update.email, dest.buf, dest.len);
924 r->value.update.email[dest.len] = 0;
926 ts = 0;
927 n = get_var_int(&ts, &in);
928 if (n < 0)
929 goto done;
930 string_view_consume(&in, n);
931 r->value.update.time = ts;
932 if (in.len < 2)
933 goto done;
935 r->value.update.tz_offset = get_be16(in.buf);
936 string_view_consume(&in, 2);
938 strbuf_reset(&dest);
939 n = decode_string(&dest, in);
940 if (n < 0)
941 goto done;
942 string_view_consume(&in, n);
944 r->value.update.message =
945 reftable_realloc(r->value.update.message, dest.len + 1);
946 memcpy(r->value.update.message, dest.buf, dest.len);
947 r->value.update.message[dest.len] = 0;
949 strbuf_release(&dest);
950 return start.len - in.len;
952 done:
953 strbuf_release(&dest);
954 return REFTABLE_FORMAT_ERROR;
957 static int null_streq(char *a, char *b)
959 char *empty = "";
960 if (!a)
961 a = empty;
963 if (!b)
964 b = empty;
966 return 0 == strcmp(a, b);
969 static int zero_hash_eq(uint8_t *a, uint8_t *b, int sz)
971 if (!a)
972 a = zero;
974 if (!b)
975 b = zero;
977 return !memcmp(a, b, sz);
980 static int reftable_log_record_equal_void(const void *a,
981 const void *b, int hash_size)
983 return reftable_log_record_equal((struct reftable_log_record *) a,
984 (struct reftable_log_record *) b,
985 hash_size);
988 static int reftable_log_record_cmp_void(const void *_a, const void *_b)
990 const struct reftable_log_record *a = _a;
991 const struct reftable_log_record *b = _b;
992 int cmp = strcmp(a->refname, b->refname);
993 if (cmp)
994 return cmp;
997 * Note that the comparison here is reversed. This is because the
998 * update index is reversed when comparing keys. For reference, see how
999 * we handle this in reftable_log_record_key()`.
1001 return b->update_index - a->update_index;
1004 int reftable_log_record_equal(const struct reftable_log_record *a,
1005 const struct reftable_log_record *b, int hash_size)
1007 if (!(null_streq(a->refname, b->refname) &&
1008 a->update_index == b->update_index &&
1009 a->value_type == b->value_type))
1010 return 0;
1012 switch (a->value_type) {
1013 case REFTABLE_LOG_DELETION:
1014 return 1;
1015 case REFTABLE_LOG_UPDATE:
1016 return null_streq(a->value.update.name, b->value.update.name) &&
1017 a->value.update.time == b->value.update.time &&
1018 a->value.update.tz_offset == b->value.update.tz_offset &&
1019 null_streq(a->value.update.email,
1020 b->value.update.email) &&
1021 null_streq(a->value.update.message,
1022 b->value.update.message) &&
1023 zero_hash_eq(a->value.update.old_hash,
1024 b->value.update.old_hash, hash_size) &&
1025 zero_hash_eq(a->value.update.new_hash,
1026 b->value.update.new_hash, hash_size);
1029 abort();
1032 static int reftable_log_record_is_deletion_void(const void *p)
1034 return reftable_log_record_is_deletion(
1035 (const struct reftable_log_record *)p);
1038 static void reftable_log_record_print_void(const void *rec, int hash_size)
1040 reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
1043 static struct reftable_record_vtable reftable_log_record_vtable = {
1044 .key = &reftable_log_record_key,
1045 .type = BLOCK_TYPE_LOG,
1046 .copy_from = &reftable_log_record_copy_from,
1047 .val_type = &reftable_log_record_val_type,
1048 .encode = &reftable_log_record_encode,
1049 .decode = &reftable_log_record_decode,
1050 .release = &reftable_log_record_release_void,
1051 .is_deletion = &reftable_log_record_is_deletion_void,
1052 .equal = &reftable_log_record_equal_void,
1053 .cmp = &reftable_log_record_cmp_void,
1054 .print = &reftable_log_record_print_void,
1057 static void reftable_index_record_key(const void *r, struct strbuf *dest)
1059 const struct reftable_index_record *rec = r;
1060 strbuf_reset(dest);
1061 strbuf_addbuf(dest, &rec->last_key);
1064 static void reftable_index_record_copy_from(void *rec, const void *src_rec,
1065 int hash_size)
1067 struct reftable_index_record *dst = rec;
1068 const struct reftable_index_record *src = src_rec;
1070 strbuf_reset(&dst->last_key);
1071 strbuf_addbuf(&dst->last_key, &src->last_key);
1072 dst->offset = src->offset;
1075 static void reftable_index_record_release(void *rec)
1077 struct reftable_index_record *idx = rec;
1078 strbuf_release(&idx->last_key);
1081 static uint8_t reftable_index_record_val_type(const void *rec)
1083 return 0;
1086 static int reftable_index_record_encode(const void *rec, struct string_view out,
1087 int hash_size)
1089 const struct reftable_index_record *r =
1090 (const struct reftable_index_record *)rec;
1091 struct string_view start = out;
1093 int n = put_var_int(&out, r->offset);
1094 if (n < 0)
1095 return n;
1097 string_view_consume(&out, n);
1099 return start.len - out.len;
1102 static int reftable_index_record_decode(void *rec, struct strbuf key,
1103 uint8_t val_type, struct string_view in,
1104 int hash_size)
1106 struct string_view start = in;
1107 struct reftable_index_record *r = rec;
1108 int n = 0;
1110 strbuf_reset(&r->last_key);
1111 strbuf_addbuf(&r->last_key, &key);
1113 n = get_var_int(&r->offset, &in);
1114 if (n < 0)
1115 return n;
1117 string_view_consume(&in, n);
1118 return start.len - in.len;
1121 static int reftable_index_record_equal(const void *a, const void *b, int hash_size)
1123 struct reftable_index_record *ia = (struct reftable_index_record *) a;
1124 struct reftable_index_record *ib = (struct reftable_index_record *) b;
1126 return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
1129 static int reftable_index_record_cmp(const void *_a, const void *_b)
1131 const struct reftable_index_record *a = _a;
1132 const struct reftable_index_record *b = _b;
1133 return strbuf_cmp(&a->last_key, &b->last_key);
1136 static void reftable_index_record_print(const void *rec, int hash_size)
1138 const struct reftable_index_record *idx = rec;
1139 /* TODO: escape null chars? */
1140 printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
1143 static struct reftable_record_vtable reftable_index_record_vtable = {
1144 .key = &reftable_index_record_key,
1145 .type = BLOCK_TYPE_INDEX,
1146 .copy_from = &reftable_index_record_copy_from,
1147 .val_type = &reftable_index_record_val_type,
1148 .encode = &reftable_index_record_encode,
1149 .decode = &reftable_index_record_decode,
1150 .release = &reftable_index_record_release,
1151 .is_deletion = &not_a_deletion,
1152 .equal = &reftable_index_record_equal,
1153 .cmp = &reftable_index_record_cmp,
1154 .print = &reftable_index_record_print,
1157 void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
1159 reftable_record_vtable(rec)->key(reftable_record_data(rec), dest);
1162 uint8_t reftable_record_type(struct reftable_record *rec)
1164 return rec->type;
1167 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
1168 int hash_size)
1170 return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
1171 dest, hash_size);
1174 void reftable_record_copy_from(struct reftable_record *rec,
1175 struct reftable_record *src, int hash_size)
1177 assert(src->type == rec->type);
1179 reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
1180 reftable_record_data(src),
1181 hash_size);
1184 uint8_t reftable_record_val_type(struct reftable_record *rec)
1186 return reftable_record_vtable(rec)->val_type(reftable_record_data(rec));
1189 int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
1190 uint8_t extra, struct string_view src, int hash_size)
1192 return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
1193 key, extra, src, hash_size);
1196 void reftable_record_release(struct reftable_record *rec)
1198 reftable_record_vtable(rec)->release(reftable_record_data(rec));
1201 int reftable_record_is_deletion(struct reftable_record *rec)
1203 return reftable_record_vtable(rec)->is_deletion(
1204 reftable_record_data(rec));
1207 int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
1209 if (a->type != b->type)
1210 BUG("cannot compare reftable records of different type");
1211 return reftable_record_vtable(a)->cmp(
1212 reftable_record_data(a), reftable_record_data(b));
1215 int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
1217 if (a->type != b->type)
1218 return 0;
1219 return reftable_record_vtable(a)->equal(
1220 reftable_record_data(a), reftable_record_data(b), hash_size);
1223 static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_size)
1225 if (a && b)
1226 return !memcmp(a, b, hash_size);
1228 return a == b;
1231 int reftable_ref_record_equal(const struct reftable_ref_record *a,
1232 const struct reftable_ref_record *b, int hash_size)
1234 assert(hash_size > 0);
1235 if (!null_streq(a->refname, b->refname))
1236 return 0;
1238 if (a->update_index != b->update_index ||
1239 a->value_type != b->value_type)
1240 return 0;
1242 switch (a->value_type) {
1243 case REFTABLE_REF_SYMREF:
1244 return !strcmp(a->value.symref, b->value.symref);
1245 case REFTABLE_REF_VAL2:
1246 return hash_equal(a->value.val2.value, b->value.val2.value,
1247 hash_size) &&
1248 hash_equal(a->value.val2.target_value,
1249 b->value.val2.target_value, hash_size);
1250 case REFTABLE_REF_VAL1:
1251 return hash_equal(a->value.val1, b->value.val1, hash_size);
1252 case REFTABLE_REF_DELETION:
1253 return 1;
1254 default:
1255 abort();
1259 int reftable_ref_record_compare_name(const void *a, const void *b)
1261 return strcmp(((struct reftable_ref_record *)a)->refname,
1262 ((struct reftable_ref_record *)b)->refname);
1265 int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
1267 return ref->value_type == REFTABLE_REF_DELETION;
1270 int reftable_log_record_compare_key(const void *a, const void *b)
1272 const struct reftable_log_record *la = a;
1273 const struct reftable_log_record *lb = b;
1275 int cmp = strcmp(la->refname, lb->refname);
1276 if (cmp)
1277 return cmp;
1278 if (la->update_index > lb->update_index)
1279 return -1;
1280 return (la->update_index < lb->update_index) ? 1 : 0;
1283 int reftable_log_record_is_deletion(const struct reftable_log_record *log)
1285 return (log->value_type == REFTABLE_LOG_DELETION);
1288 void string_view_consume(struct string_view *s, int n)
1290 s->buf += n;
1291 s->len -= n;
1294 static void *reftable_record_data(struct reftable_record *rec)
1296 switch (rec->type) {
1297 case BLOCK_TYPE_REF:
1298 return &rec->u.ref;
1299 case BLOCK_TYPE_LOG:
1300 return &rec->u.log;
1301 case BLOCK_TYPE_INDEX:
1302 return &rec->u.idx;
1303 case BLOCK_TYPE_OBJ:
1304 return &rec->u.obj;
1306 abort();
1309 static struct reftable_record_vtable *
1310 reftable_record_vtable(struct reftable_record *rec)
1312 switch (rec->type) {
1313 case BLOCK_TYPE_REF:
1314 return &reftable_ref_record_vtable;
1315 case BLOCK_TYPE_LOG:
1316 return &reftable_log_record_vtable;
1317 case BLOCK_TYPE_INDEX:
1318 return &reftable_index_record_vtable;
1319 case BLOCK_TYPE_OBJ:
1320 return &reftable_obj_record_vtable;
1322 abort();
1325 void reftable_record_init(struct reftable_record *rec, uint8_t typ)
1327 memset(rec, 0, sizeof(*rec));
1328 rec->type = typ;
1330 switch (typ) {
1331 case BLOCK_TYPE_REF:
1332 case BLOCK_TYPE_LOG:
1333 case BLOCK_TYPE_OBJ:
1334 return;
1335 case BLOCK_TYPE_INDEX:
1336 strbuf_init(&rec->u.idx.last_key, 0);
1337 return;
1338 default:
1339 BUG("unhandled record type");
1343 void reftable_record_print(struct reftable_record *rec, int hash_size)
1345 printf("'%c': ", rec->type);
1346 reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);