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
9 /* record.c - methods for different types of records. */
14 #include "constants.h"
15 #include "reftable-error.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
)
29 val
= in
->buf
[ptr
] & 0x7f;
31 while (in
->buf
[ptr
] & 0x80) {
36 val
= (val
+ 1) << 7 | (uint64_t)(in
->buf
[ptr
] & 0x7f);
43 int put_var_int(struct string_view
*dest
, uint64_t val
)
45 uint8_t buf
[10] = { 0 };
48 buf
[i
] = (uint8_t)(val
& 0x7f);
56 buf
[i
] = 0x80 | (uint8_t)(val
& 0x7f);
60 n
= sizeof(buf
) - i
- 1;
63 memcpy(dest
->buf
, &buf
[i
+ 1], n
);
67 int reftable_is_block_type(uint8_t typ
)
73 case BLOCK_TYPE_INDEX
:
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
;
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
;
101 static int decode_string(struct strbuf
*dest
, struct string_view in
)
103 int start_len
= in
.len
;
105 int n
= get_var_int(&tsize
, &in
);
108 string_view_consume(&in
, n
);
113 strbuf_add(dest
, in
.buf
, tsize
);
114 string_view_consume(&in
, tsize
);
116 return start_len
- in
.len
;
119 static int encode_string(const char *str
, struct string_view s
)
121 struct string_view start
= s
;
123 int n
= put_var_int(&s
, l
);
126 string_view_consume(&s
, n
);
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
,
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
);
145 string_view_consume(&dest
, n
);
147 *restart
= (prefix_len
== 0);
149 n
= put_var_int(&dest
, suffix_len
<< 3 | (uint64_t)extra
);
152 string_view_consume(&dest
, n
);
154 if (dest
.len
< suffix_len
)
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_keylen(struct string_view in
,
163 uint64_t *prefix_len
,
164 uint64_t *suffix_len
,
167 size_t start_len
= in
.len
;
170 n
= get_var_int(prefix_len
, &in
);
173 string_view_consume(&in
, n
);
175 n
= get_var_int(suffix_len
, &in
);
178 string_view_consume(&in
, n
);
180 *extra
= (uint8_t)(*suffix_len
& 0x7);
183 return start_len
- in
.len
;
186 int reftable_decode_key(struct strbuf
*last_key
, uint8_t *extra
,
187 struct string_view in
)
189 int start_len
= in
.len
;
190 uint64_t prefix_len
= 0;
191 uint64_t suffix_len
= 0;
194 n
= reftable_decode_keylen(in
, &prefix_len
, &suffix_len
, extra
);
197 string_view_consume(&in
, n
);
199 if (in
.len
< suffix_len
||
200 prefix_len
> last_key
->len
)
203 strbuf_setlen(last_key
, prefix_len
);
204 strbuf_add(last_key
, in
.buf
, suffix_len
);
205 string_view_consume(&in
, suffix_len
);
207 return start_len
- in
.len
;
210 static void reftable_ref_record_key(const void *r
, struct strbuf
*dest
)
212 const struct reftable_ref_record
*rec
=
213 (const struct reftable_ref_record
*)r
;
215 strbuf_addstr(dest
, rec
->refname
);
218 static void reftable_ref_record_copy_from(void *rec
, const void *src_rec
,
221 struct reftable_ref_record
*ref
= rec
;
222 const struct reftable_ref_record
*src
= src_rec
;
223 char *refname
= NULL
;
224 size_t refname_cap
= 0;
226 assert(hash_size
> 0);
228 SWAP(refname
, ref
->refname
);
229 SWAP(refname_cap
, ref
->refname_cap
);
230 reftable_ref_record_release(ref
);
231 SWAP(ref
->refname
, refname
);
232 SWAP(ref
->refname_cap
, refname_cap
);
235 size_t refname_len
= strlen(src
->refname
);
237 REFTABLE_ALLOC_GROW(ref
->refname
, refname_len
+ 1,
239 memcpy(ref
->refname
, src
->refname
, refname_len
);
240 ref
->refname
[refname_len
] = 0;
243 ref
->update_index
= src
->update_index
;
244 ref
->value_type
= src
->value_type
;
245 switch (src
->value_type
) {
246 case REFTABLE_REF_DELETION
:
248 case REFTABLE_REF_VAL1
:
249 memcpy(ref
->value
.val1
, src
->value
.val1
, hash_size
);
251 case REFTABLE_REF_VAL2
:
252 memcpy(ref
->value
.val2
.value
, src
->value
.val2
.value
, hash_size
);
253 memcpy(ref
->value
.val2
.target_value
,
254 src
->value
.val2
.target_value
, hash_size
);
256 case REFTABLE_REF_SYMREF
:
257 ref
->value
.symref
= xstrdup(src
->value
.symref
);
262 static void reftable_ref_record_release_void(void *rec
)
264 reftable_ref_record_release(rec
);
267 void reftable_ref_record_release(struct reftable_ref_record
*ref
)
269 switch (ref
->value_type
) {
270 case REFTABLE_REF_SYMREF
:
271 reftable_free(ref
->value
.symref
);
273 case REFTABLE_REF_VAL2
:
275 case REFTABLE_REF_VAL1
:
277 case REFTABLE_REF_DELETION
:
283 reftable_free(ref
->refname
);
284 memset(ref
, 0, sizeof(struct reftable_ref_record
));
287 static uint8_t reftable_ref_record_val_type(const void *rec
)
289 const struct reftable_ref_record
*r
=
290 (const struct reftable_ref_record
*)rec
;
291 return r
->value_type
;
294 static int reftable_ref_record_encode(const void *rec
, struct string_view s
,
297 const struct reftable_ref_record
*r
=
298 (const struct reftable_ref_record
*)rec
;
299 struct string_view start
= s
;
300 int n
= put_var_int(&s
, r
->update_index
);
301 assert(hash_size
> 0);
304 string_view_consume(&s
, n
);
306 switch (r
->value_type
) {
307 case REFTABLE_REF_SYMREF
:
308 n
= encode_string(r
->value
.symref
, s
);
312 string_view_consume(&s
, n
);
314 case REFTABLE_REF_VAL2
:
315 if (s
.len
< 2 * hash_size
) {
318 memcpy(s
.buf
, r
->value
.val2
.value
, hash_size
);
319 string_view_consume(&s
, hash_size
);
320 memcpy(s
.buf
, r
->value
.val2
.target_value
, hash_size
);
321 string_view_consume(&s
, hash_size
);
323 case REFTABLE_REF_VAL1
:
324 if (s
.len
< hash_size
) {
327 memcpy(s
.buf
, r
->value
.val1
, hash_size
);
328 string_view_consume(&s
, hash_size
);
330 case REFTABLE_REF_DELETION
:
336 return start
.len
- s
.len
;
339 static int reftable_ref_record_decode(void *rec
, struct strbuf key
,
340 uint8_t val_type
, struct string_view in
,
341 int hash_size
, struct strbuf
*scratch
)
343 struct reftable_ref_record
*r
= rec
;
344 struct string_view start
= in
;
345 uint64_t update_index
= 0;
346 const char *refname
= NULL
;
347 size_t refname_cap
= 0;
350 assert(hash_size
> 0);
352 n
= get_var_int(&update_index
, &in
);
355 string_view_consume(&in
, n
);
357 SWAP(refname
, r
->refname
);
358 SWAP(refname_cap
, r
->refname_cap
);
359 reftable_ref_record_release(r
);
360 SWAP(r
->refname
, refname
);
361 SWAP(r
->refname_cap
, refname_cap
);
363 REFTABLE_ALLOC_GROW(r
->refname
, key
.len
+ 1, r
->refname_cap
);
364 memcpy(r
->refname
, key
.buf
, key
.len
);
365 r
->refname
[key
.len
] = 0;
367 r
->update_index
= update_index
;
368 r
->value_type
= val_type
;
370 case REFTABLE_REF_VAL1
:
371 if (in
.len
< hash_size
) {
375 memcpy(r
->value
.val1
, in
.buf
, hash_size
);
376 string_view_consume(&in
, hash_size
);
379 case REFTABLE_REF_VAL2
:
380 if (in
.len
< 2 * hash_size
) {
384 memcpy(r
->value
.val2
.value
, in
.buf
, hash_size
);
385 string_view_consume(&in
, hash_size
);
387 memcpy(r
->value
.val2
.target_value
, in
.buf
, hash_size
);
388 string_view_consume(&in
, hash_size
);
391 case REFTABLE_REF_SYMREF
: {
392 int n
= decode_string(scratch
, in
);
396 string_view_consume(&in
, n
);
397 r
->value
.symref
= strbuf_detach(scratch
, NULL
);
400 case REFTABLE_REF_DELETION
:
407 return start
.len
- in
.len
;
410 static int reftable_ref_record_is_deletion_void(const void *p
)
412 return reftable_ref_record_is_deletion(
413 (const struct reftable_ref_record
*)p
);
416 static int reftable_ref_record_equal_void(const void *a
,
417 const void *b
, int hash_size
)
419 struct reftable_ref_record
*ra
= (struct reftable_ref_record
*) a
;
420 struct reftable_ref_record
*rb
= (struct reftable_ref_record
*) b
;
421 return reftable_ref_record_equal(ra
, rb
, hash_size
);
424 static int reftable_ref_record_cmp_void(const void *_a
, const void *_b
)
426 const struct reftable_ref_record
*a
= _a
;
427 const struct reftable_ref_record
*b
= _b
;
428 return strcmp(a
->refname
, b
->refname
);
431 static struct reftable_record_vtable reftable_ref_record_vtable
= {
432 .key
= &reftable_ref_record_key
,
433 .type
= BLOCK_TYPE_REF
,
434 .copy_from
= &reftable_ref_record_copy_from
,
435 .val_type
= &reftable_ref_record_val_type
,
436 .encode
= &reftable_ref_record_encode
,
437 .decode
= &reftable_ref_record_decode
,
438 .release
= &reftable_ref_record_release_void
,
439 .is_deletion
= &reftable_ref_record_is_deletion_void
,
440 .equal
= &reftable_ref_record_equal_void
,
441 .cmp
= &reftable_ref_record_cmp_void
,
444 static void reftable_obj_record_key(const void *r
, struct strbuf
*dest
)
446 const struct reftable_obj_record
*rec
=
447 (const struct reftable_obj_record
*)r
;
449 strbuf_add(dest
, rec
->hash_prefix
, rec
->hash_prefix_len
);
452 static void reftable_obj_record_release(void *rec
)
454 struct reftable_obj_record
*obj
= rec
;
455 FREE_AND_NULL(obj
->hash_prefix
);
456 FREE_AND_NULL(obj
->offsets
);
457 memset(obj
, 0, sizeof(struct reftable_obj_record
));
460 static void reftable_obj_record_copy_from(void *rec
, const void *src_rec
,
461 int hash_size UNUSED
)
463 struct reftable_obj_record
*obj
= rec
;
464 const struct reftable_obj_record
*src
=
465 (const struct reftable_obj_record
*)src_rec
;
467 reftable_obj_record_release(obj
);
469 REFTABLE_ALLOC_ARRAY(obj
->hash_prefix
, src
->hash_prefix_len
);
470 obj
->hash_prefix_len
= src
->hash_prefix_len
;
471 if (src
->hash_prefix_len
)
472 memcpy(obj
->hash_prefix
, src
->hash_prefix
, obj
->hash_prefix_len
);
474 REFTABLE_ALLOC_ARRAY(obj
->offsets
, src
->offset_len
);
475 obj
->offset_len
= src
->offset_len
;
476 COPY_ARRAY(obj
->offsets
, src
->offsets
, src
->offset_len
);
479 static uint8_t reftable_obj_record_val_type(const void *rec
)
481 const struct reftable_obj_record
*r
= rec
;
482 if (r
->offset_len
> 0 && r
->offset_len
< 8)
483 return r
->offset_len
;
487 static int reftable_obj_record_encode(const void *rec
, struct string_view s
,
488 int hash_size UNUSED
)
490 const struct reftable_obj_record
*r
= rec
;
491 struct string_view start
= s
;
495 if (r
->offset_len
== 0 || r
->offset_len
>= 8) {
496 n
= put_var_int(&s
, r
->offset_len
);
500 string_view_consume(&s
, n
);
502 if (r
->offset_len
== 0)
503 return start
.len
- s
.len
;
504 n
= put_var_int(&s
, r
->offsets
[0]);
507 string_view_consume(&s
, n
);
509 last
= r
->offsets
[0];
510 for (i
= 1; i
< r
->offset_len
; i
++) {
511 int n
= put_var_int(&s
, r
->offsets
[i
] - last
);
515 string_view_consume(&s
, n
);
516 last
= r
->offsets
[i
];
518 return start
.len
- s
.len
;
521 static int reftable_obj_record_decode(void *rec
, struct strbuf key
,
522 uint8_t val_type
, struct string_view in
,
523 int hash_size UNUSED
,
524 struct strbuf
*scratch UNUSED
)
526 struct string_view start
= in
;
527 struct reftable_obj_record
*r
= rec
;
528 uint64_t count
= val_type
;
533 reftable_obj_record_release(r
);
535 REFTABLE_ALLOC_ARRAY(r
->hash_prefix
, key
.len
);
536 memcpy(r
->hash_prefix
, key
.buf
, key
.len
);
537 r
->hash_prefix_len
= key
.len
;
540 n
= get_var_int(&count
, &in
);
545 string_view_consume(&in
, n
);
551 return start
.len
- in
.len
;
553 REFTABLE_ALLOC_ARRAY(r
->offsets
, count
);
554 r
->offset_len
= count
;
556 n
= get_var_int(&r
->offsets
[0], &in
);
559 string_view_consume(&in
, n
);
561 last
= r
->offsets
[0];
565 int n
= get_var_int(&delta
, &in
);
569 string_view_consume(&in
, n
);
571 last
= r
->offsets
[j
] = (delta
+ last
);
574 return start
.len
- in
.len
;
577 static int not_a_deletion(const void *p UNUSED
)
582 static int reftable_obj_record_equal_void(const void *a
, const void *b
,
583 int hash_size UNUSED
)
585 struct reftable_obj_record
*ra
= (struct reftable_obj_record
*) a
;
586 struct reftable_obj_record
*rb
= (struct reftable_obj_record
*) b
;
588 if (ra
->hash_prefix_len
!= rb
->hash_prefix_len
589 || ra
->offset_len
!= rb
->offset_len
)
592 if (ra
->hash_prefix_len
&&
593 memcmp(ra
->hash_prefix
, rb
->hash_prefix
, ra
->hash_prefix_len
))
595 if (ra
->offset_len
&&
596 memcmp(ra
->offsets
, rb
->offsets
, ra
->offset_len
* sizeof(uint64_t)))
602 static int reftable_obj_record_cmp_void(const void *_a
, const void *_b
)
604 const struct reftable_obj_record
*a
= _a
;
605 const struct reftable_obj_record
*b
= _b
;
608 cmp
= memcmp(a
->hash_prefix
, b
->hash_prefix
,
609 a
->hash_prefix_len
> b
->hash_prefix_len
?
610 a
->hash_prefix_len
: b
->hash_prefix_len
);
615 * When the prefix is the same then the object record that is longer is
616 * considered to be bigger.
618 return a
->hash_prefix_len
- b
->hash_prefix_len
;
621 static struct reftable_record_vtable reftable_obj_record_vtable
= {
622 .key
= &reftable_obj_record_key
,
623 .type
= BLOCK_TYPE_OBJ
,
624 .copy_from
= &reftable_obj_record_copy_from
,
625 .val_type
= &reftable_obj_record_val_type
,
626 .encode
= &reftable_obj_record_encode
,
627 .decode
= &reftable_obj_record_decode
,
628 .release
= &reftable_obj_record_release
,
629 .is_deletion
= ¬_a_deletion
,
630 .equal
= &reftable_obj_record_equal_void
,
631 .cmp
= &reftable_obj_record_cmp_void
,
634 static void reftable_log_record_key(const void *r
, struct strbuf
*dest
)
636 const struct reftable_log_record
*rec
=
637 (const struct reftable_log_record
*)r
;
638 int len
= strlen(rec
->refname
);
642 strbuf_add(dest
, (uint8_t *)rec
->refname
, len
+ 1);
644 ts
= (~ts
) - rec
->update_index
;
645 put_be64(&i64
[0], ts
);
646 strbuf_add(dest
, i64
, sizeof(i64
));
649 static void reftable_log_record_copy_from(void *rec
, const void *src_rec
,
652 struct reftable_log_record
*dst
= rec
;
653 const struct reftable_log_record
*src
=
654 (const struct reftable_log_record
*)src_rec
;
656 reftable_log_record_release(dst
);
659 dst
->refname
= xstrdup(dst
->refname
);
661 switch (dst
->value_type
) {
662 case REFTABLE_LOG_DELETION
:
664 case REFTABLE_LOG_UPDATE
:
665 if (dst
->value
.update
.email
) {
666 dst
->value
.update
.email
=
667 xstrdup(dst
->value
.update
.email
);
669 if (dst
->value
.update
.name
) {
670 dst
->value
.update
.name
=
671 xstrdup(dst
->value
.update
.name
);
673 if (dst
->value
.update
.message
) {
674 dst
->value
.update
.message
=
675 xstrdup(dst
->value
.update
.message
);
678 memcpy(dst
->value
.update
.new_hash
,
679 src
->value
.update
.new_hash
, hash_size
);
680 memcpy(dst
->value
.update
.old_hash
,
681 src
->value
.update
.old_hash
, hash_size
);
686 static void reftable_log_record_release_void(void *rec
)
688 struct reftable_log_record
*r
= rec
;
689 reftable_log_record_release(r
);
692 void reftable_log_record_release(struct reftable_log_record
*r
)
694 reftable_free(r
->refname
);
695 switch (r
->value_type
) {
696 case REFTABLE_LOG_DELETION
:
698 case REFTABLE_LOG_UPDATE
:
699 reftable_free(r
->value
.update
.name
);
700 reftable_free(r
->value
.update
.email
);
701 reftable_free(r
->value
.update
.message
);
704 memset(r
, 0, sizeof(struct reftable_log_record
));
707 static uint8_t reftable_log_record_val_type(const void *rec
)
709 const struct reftable_log_record
*log
=
710 (const struct reftable_log_record
*)rec
;
712 return reftable_log_record_is_deletion(log
) ? 0 : 1;
715 static int reftable_log_record_encode(const void *rec
, struct string_view s
,
718 const struct reftable_log_record
*r
= rec
;
719 struct string_view start
= s
;
721 if (reftable_log_record_is_deletion(r
))
724 if (s
.len
< 2 * hash_size
)
727 memcpy(s
.buf
, r
->value
.update
.old_hash
, hash_size
);
728 memcpy(s
.buf
+ hash_size
, r
->value
.update
.new_hash
, hash_size
);
729 string_view_consume(&s
, 2 * hash_size
);
731 n
= encode_string(r
->value
.update
.name
? r
->value
.update
.name
: "", s
);
734 string_view_consume(&s
, n
);
736 n
= encode_string(r
->value
.update
.email
? r
->value
.update
.email
: "",
740 string_view_consume(&s
, n
);
742 n
= put_var_int(&s
, r
->value
.update
.time
);
745 string_view_consume(&s
, n
);
750 put_be16(s
.buf
, r
->value
.update
.tz_offset
);
751 string_view_consume(&s
, 2);
754 r
->value
.update
.message
? r
->value
.update
.message
: "", s
);
757 string_view_consume(&s
, n
);
759 return start
.len
- s
.len
;
762 static int reftable_log_record_decode(void *rec
, struct strbuf key
,
763 uint8_t val_type
, struct string_view in
,
764 int hash_size
, struct strbuf
*scratch
)
766 struct string_view start
= in
;
767 struct reftable_log_record
*r
= rec
;
772 if (key
.len
<= 9 || key
.buf
[key
.len
- 9] != 0)
773 return REFTABLE_FORMAT_ERROR
;
775 REFTABLE_ALLOC_GROW(r
->refname
, key
.len
- 8, r
->refname_cap
);
776 memcpy(r
->refname
, key
.buf
, key
.len
- 8);
777 ts
= get_be64(key
.buf
+ key
.len
- 8);
779 r
->update_index
= (~max
) - ts
;
781 if (val_type
!= r
->value_type
) {
782 switch (r
->value_type
) {
783 case REFTABLE_LOG_UPDATE
:
784 FREE_AND_NULL(r
->value
.update
.message
);
785 r
->value
.update
.message_cap
= 0;
786 FREE_AND_NULL(r
->value
.update
.email
);
787 FREE_AND_NULL(r
->value
.update
.name
);
789 case REFTABLE_LOG_DELETION
:
794 r
->value_type
= val_type
;
795 if (val_type
== REFTABLE_LOG_DELETION
)
798 if (in
.len
< 2 * hash_size
)
799 return REFTABLE_FORMAT_ERROR
;
801 memcpy(r
->value
.update
.old_hash
, in
.buf
, hash_size
);
802 memcpy(r
->value
.update
.new_hash
, in
.buf
+ hash_size
, hash_size
);
804 string_view_consume(&in
, 2 * hash_size
);
806 n
= decode_string(scratch
, in
);
809 string_view_consume(&in
, n
);
812 * In almost all cases we can expect the reflog name to not change for
813 * reflog entries as they are tied to the local identity, not to the
814 * target commits. As an optimization for this common case we can thus
815 * skip copying over the name in case it's accurate already.
817 if (!r
->value
.update
.name
||
818 strcmp(r
->value
.update
.name
, scratch
->buf
)) {
819 r
->value
.update
.name
=
820 reftable_realloc(r
->value
.update
.name
, scratch
->len
+ 1);
821 memcpy(r
->value
.update
.name
, scratch
->buf
, scratch
->len
);
822 r
->value
.update
.name
[scratch
->len
] = 0;
825 n
= decode_string(scratch
, in
);
828 string_view_consume(&in
, n
);
830 /* Same as above, but for the reflog email. */
831 if (!r
->value
.update
.email
||
832 strcmp(r
->value
.update
.email
, scratch
->buf
)) {
833 r
->value
.update
.email
=
834 reftable_realloc(r
->value
.update
.email
, scratch
->len
+ 1);
835 memcpy(r
->value
.update
.email
, scratch
->buf
, scratch
->len
);
836 r
->value
.update
.email
[scratch
->len
] = 0;
840 n
= get_var_int(&ts
, &in
);
843 string_view_consume(&in
, n
);
844 r
->value
.update
.time
= ts
;
848 r
->value
.update
.tz_offset
= get_be16(in
.buf
);
849 string_view_consume(&in
, 2);
851 n
= decode_string(scratch
, in
);
854 string_view_consume(&in
, n
);
856 REFTABLE_ALLOC_GROW(r
->value
.update
.message
, scratch
->len
+ 1,
857 r
->value
.update
.message_cap
);
858 memcpy(r
->value
.update
.message
, scratch
->buf
, scratch
->len
);
859 r
->value
.update
.message
[scratch
->len
] = 0;
861 return start
.len
- in
.len
;
864 return REFTABLE_FORMAT_ERROR
;
867 static int null_streq(const char *a
, const char *b
)
869 const char *empty
= "";
876 return 0 == strcmp(a
, b
);
879 static int reftable_log_record_equal_void(const void *a
,
880 const void *b
, int hash_size
)
882 return reftable_log_record_equal((struct reftable_log_record
*) a
,
883 (struct reftable_log_record
*) b
,
887 static int reftable_log_record_cmp_void(const void *_a
, const void *_b
)
889 const struct reftable_log_record
*a
= _a
;
890 const struct reftable_log_record
*b
= _b
;
891 int cmp
= strcmp(a
->refname
, b
->refname
);
896 * Note that the comparison here is reversed. This is because the
897 * update index is reversed when comparing keys. For reference, see how
898 * we handle this in reftable_log_record_key()`.
900 return b
->update_index
- a
->update_index
;
903 int reftable_log_record_equal(const struct reftable_log_record
*a
,
904 const struct reftable_log_record
*b
, int hash_size
)
906 if (!(null_streq(a
->refname
, b
->refname
) &&
907 a
->update_index
== b
->update_index
&&
908 a
->value_type
== b
->value_type
))
911 switch (a
->value_type
) {
912 case REFTABLE_LOG_DELETION
:
914 case REFTABLE_LOG_UPDATE
:
915 return null_streq(a
->value
.update
.name
, b
->value
.update
.name
) &&
916 a
->value
.update
.time
== b
->value
.update
.time
&&
917 a
->value
.update
.tz_offset
== b
->value
.update
.tz_offset
&&
918 null_streq(a
->value
.update
.email
,
919 b
->value
.update
.email
) &&
920 null_streq(a
->value
.update
.message
,
921 b
->value
.update
.message
) &&
922 !memcmp(a
->value
.update
.old_hash
,
923 b
->value
.update
.old_hash
, hash_size
) &&
924 !memcmp(a
->value
.update
.new_hash
,
925 b
->value
.update
.new_hash
, hash_size
);
931 static int reftable_log_record_is_deletion_void(const void *p
)
933 return reftable_log_record_is_deletion(
934 (const struct reftable_log_record
*)p
);
937 static struct reftable_record_vtable reftable_log_record_vtable
= {
938 .key
= &reftable_log_record_key
,
939 .type
= BLOCK_TYPE_LOG
,
940 .copy_from
= &reftable_log_record_copy_from
,
941 .val_type
= &reftable_log_record_val_type
,
942 .encode
= &reftable_log_record_encode
,
943 .decode
= &reftable_log_record_decode
,
944 .release
= &reftable_log_record_release_void
,
945 .is_deletion
= &reftable_log_record_is_deletion_void
,
946 .equal
= &reftable_log_record_equal_void
,
947 .cmp
= &reftable_log_record_cmp_void
,
950 static void reftable_index_record_key(const void *r
, struct strbuf
*dest
)
952 const struct reftable_index_record
*rec
= r
;
954 strbuf_addbuf(dest
, &rec
->last_key
);
957 static void reftable_index_record_copy_from(void *rec
, const void *src_rec
,
958 int hash_size UNUSED
)
960 struct reftable_index_record
*dst
= rec
;
961 const struct reftable_index_record
*src
= src_rec
;
963 strbuf_reset(&dst
->last_key
);
964 strbuf_addbuf(&dst
->last_key
, &src
->last_key
);
965 dst
->offset
= src
->offset
;
968 static void reftable_index_record_release(void *rec
)
970 struct reftable_index_record
*idx
= rec
;
971 strbuf_release(&idx
->last_key
);
974 static uint8_t reftable_index_record_val_type(const void *rec UNUSED
)
979 static int reftable_index_record_encode(const void *rec
, struct string_view out
,
980 int hash_size UNUSED
)
982 const struct reftable_index_record
*r
=
983 (const struct reftable_index_record
*)rec
;
984 struct string_view start
= out
;
986 int n
= put_var_int(&out
, r
->offset
);
990 string_view_consume(&out
, n
);
992 return start
.len
- out
.len
;
995 static int reftable_index_record_decode(void *rec
, struct strbuf key
,
996 uint8_t val_type UNUSED
,
997 struct string_view in
,
998 int hash_size UNUSED
,
999 struct strbuf
*scratch UNUSED
)
1001 struct string_view start
= in
;
1002 struct reftable_index_record
*r
= rec
;
1005 strbuf_reset(&r
->last_key
);
1006 strbuf_addbuf(&r
->last_key
, &key
);
1008 n
= get_var_int(&r
->offset
, &in
);
1012 string_view_consume(&in
, n
);
1013 return start
.len
- in
.len
;
1016 static int reftable_index_record_equal(const void *a
, const void *b
,
1017 int hash_size UNUSED
)
1019 struct reftable_index_record
*ia
= (struct reftable_index_record
*) a
;
1020 struct reftable_index_record
*ib
= (struct reftable_index_record
*) b
;
1022 return ia
->offset
== ib
->offset
&& !strbuf_cmp(&ia
->last_key
, &ib
->last_key
);
1025 static int reftable_index_record_cmp(const void *_a
, const void *_b
)
1027 const struct reftable_index_record
*a
= _a
;
1028 const struct reftable_index_record
*b
= _b
;
1029 return strbuf_cmp(&a
->last_key
, &b
->last_key
);
1032 static struct reftable_record_vtable reftable_index_record_vtable
= {
1033 .key
= &reftable_index_record_key
,
1034 .type
= BLOCK_TYPE_INDEX
,
1035 .copy_from
= &reftable_index_record_copy_from
,
1036 .val_type
= &reftable_index_record_val_type
,
1037 .encode
= &reftable_index_record_encode
,
1038 .decode
= &reftable_index_record_decode
,
1039 .release
= &reftable_index_record_release
,
1040 .is_deletion
= ¬_a_deletion
,
1041 .equal
= &reftable_index_record_equal
,
1042 .cmp
= &reftable_index_record_cmp
,
1045 void reftable_record_key(struct reftable_record
*rec
, struct strbuf
*dest
)
1047 reftable_record_vtable(rec
)->key(reftable_record_data(rec
), dest
);
1050 int reftable_record_encode(struct reftable_record
*rec
, struct string_view dest
,
1053 return reftable_record_vtable(rec
)->encode(reftable_record_data(rec
),
1057 void reftable_record_copy_from(struct reftable_record
*rec
,
1058 struct reftable_record
*src
, int hash_size
)
1060 assert(src
->type
== rec
->type
);
1062 reftable_record_vtable(rec
)->copy_from(reftable_record_data(rec
),
1063 reftable_record_data(src
),
1067 uint8_t reftable_record_val_type(struct reftable_record
*rec
)
1069 return reftable_record_vtable(rec
)->val_type(reftable_record_data(rec
));
1072 int reftable_record_decode(struct reftable_record
*rec
, struct strbuf key
,
1073 uint8_t extra
, struct string_view src
, int hash_size
,
1074 struct strbuf
*scratch
)
1076 return reftable_record_vtable(rec
)->decode(reftable_record_data(rec
),
1077 key
, extra
, src
, hash_size
,
1081 void reftable_record_release(struct reftable_record
*rec
)
1083 reftable_record_vtable(rec
)->release(reftable_record_data(rec
));
1086 int reftable_record_is_deletion(struct reftable_record
*rec
)
1088 return reftable_record_vtable(rec
)->is_deletion(
1089 reftable_record_data(rec
));
1092 int reftable_record_cmp(struct reftable_record
*a
, struct reftable_record
*b
)
1094 if (a
->type
!= b
->type
)
1095 BUG("cannot compare reftable records of different type");
1096 return reftable_record_vtable(a
)->cmp(
1097 reftable_record_data(a
), reftable_record_data(b
));
1100 int reftable_record_equal(struct reftable_record
*a
, struct reftable_record
*b
, int hash_size
)
1102 if (a
->type
!= b
->type
)
1104 return reftable_record_vtable(a
)->equal(
1105 reftable_record_data(a
), reftable_record_data(b
), hash_size
);
1108 static int hash_equal(const unsigned char *a
, const unsigned char *b
, int hash_size
)
1111 return !memcmp(a
, b
, hash_size
);
1116 int reftable_ref_record_equal(const struct reftable_ref_record
*a
,
1117 const struct reftable_ref_record
*b
, int hash_size
)
1119 assert(hash_size
> 0);
1120 if (!null_streq(a
->refname
, b
->refname
))
1123 if (a
->update_index
!= b
->update_index
||
1124 a
->value_type
!= b
->value_type
)
1127 switch (a
->value_type
) {
1128 case REFTABLE_REF_SYMREF
:
1129 return !strcmp(a
->value
.symref
, b
->value
.symref
);
1130 case REFTABLE_REF_VAL2
:
1131 return hash_equal(a
->value
.val2
.value
, b
->value
.val2
.value
,
1133 hash_equal(a
->value
.val2
.target_value
,
1134 b
->value
.val2
.target_value
, hash_size
);
1135 case REFTABLE_REF_VAL1
:
1136 return hash_equal(a
->value
.val1
, b
->value
.val1
, hash_size
);
1137 case REFTABLE_REF_DELETION
:
1144 int reftable_ref_record_compare_name(const void *a
, const void *b
)
1146 return strcmp(((struct reftable_ref_record
*)a
)->refname
,
1147 ((struct reftable_ref_record
*)b
)->refname
);
1150 int reftable_ref_record_is_deletion(const struct reftable_ref_record
*ref
)
1152 return ref
->value_type
== REFTABLE_REF_DELETION
;
1155 int reftable_log_record_compare_key(const void *a
, const void *b
)
1157 const struct reftable_log_record
*la
= a
;
1158 const struct reftable_log_record
*lb
= b
;
1160 int cmp
= strcmp(la
->refname
, lb
->refname
);
1163 if (la
->update_index
> lb
->update_index
)
1165 return (la
->update_index
< lb
->update_index
) ? 1 : 0;
1168 int reftable_log_record_is_deletion(const struct reftable_log_record
*log
)
1170 return (log
->value_type
== REFTABLE_LOG_DELETION
);
1173 static void *reftable_record_data(struct reftable_record
*rec
)
1175 switch (rec
->type
) {
1176 case BLOCK_TYPE_REF
:
1178 case BLOCK_TYPE_LOG
:
1180 case BLOCK_TYPE_INDEX
:
1182 case BLOCK_TYPE_OBJ
:
1188 static struct reftable_record_vtable
*
1189 reftable_record_vtable(struct reftable_record
*rec
)
1191 switch (rec
->type
) {
1192 case BLOCK_TYPE_REF
:
1193 return &reftable_ref_record_vtable
;
1194 case BLOCK_TYPE_LOG
:
1195 return &reftable_log_record_vtable
;
1196 case BLOCK_TYPE_INDEX
:
1197 return &reftable_index_record_vtable
;
1198 case BLOCK_TYPE_OBJ
:
1199 return &reftable_obj_record_vtable
;
1204 void reftable_record_init(struct reftable_record
*rec
, uint8_t typ
)
1206 memset(rec
, 0, sizeof(*rec
));
1210 case BLOCK_TYPE_REF
:
1211 case BLOCK_TYPE_LOG
:
1212 case BLOCK_TYPE_OBJ
:
1214 case BLOCK_TYPE_INDEX
:
1215 strbuf_init(&rec
->u
.idx
.last_key
, 0);
1218 BUG("unhandled record type");