reftable: implement record equality generically
This simplifies unittests a little, and provides further coverage for reftable_record_copy(). Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Han-Wen Nienhuys committed
Jan 20, 2022 at 15:12 UTC
c983374035bcba0f70d8908d735d17dfef4e0edf
3 files changed
+63
-22
reftable/record.c
+56
-1
@@ -430,6 +430,15 @@ static int reftable_ref_record_is_deletion_void(const void *p)
430
(const struct reftable_ref_record *)p);
431
}
432
433
+
434
+static int reftable_ref_record_equal_void(const void *a,
435
+ const void *b, int hash_size)
436
+{
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);
440
+}
441
+
442
static struct reftable_record_vtable reftable_ref_record_vtable = {
443
.key = &reftable_ref_record_key,
444
.type = BLOCK_TYPE_REF,
@@ -439,6 +448,7 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
448
.decode = &reftable_ref_record_decode,
449
.release = &reftable_ref_record_release_void,
450
.is_deletion = &reftable_ref_record_is_deletion_void,
451
+ .equal = &reftable_ref_record_equal_void,
452
};
453
454
static void reftable_obj_record_key(const void *r, struct strbuf *dest)
@@ -572,6 +582,25 @@ static int not_a_deletion(const void *p)
582
return 0;
583
}
584
585
+static int reftable_obj_record_equal_void(const void *a, const void *b, int hash_size)
586
+{
587
+ struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
588
+ struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
589
+
590
+ if (ra->hash_prefix_len != rb->hash_prefix_len
591
+ || ra->offset_len != rb->offset_len)
592
+ return 0;
593
+
594
+ if (ra->hash_prefix_len &&
595
+ memcmp(ra->hash_prefix, rb->hash_prefix, ra->hash_prefix_len))
596
+ return 0;
597
+ if (ra->offset_len &&
598
+ memcmp(ra->offsets, rb->offsets, ra->offset_len * sizeof(uint64_t)))
599
+ return 0;
600
+
601
+ return 1;
602
+}
603
+
604
static struct reftable_record_vtable reftable_obj_record_vtable = {
605
.key = &reftable_obj_record_key,
606
.type = BLOCK_TYPE_OBJ,
@@ -580,7 +609,8 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
609
.encode = &reftable_obj_record_encode,
610
.decode = &reftable_obj_record_decode,
611
.release = &reftable_obj_record_release,
583
- .is_deletion = not_a_deletion,
612
+ .is_deletion = ¬_a_deletion,
613
+ .equal = &reftable_obj_record_equal_void,
614
};
615
616
void reftable_log_record_print(struct reftable_log_record *log,
@@ -881,6 +911,14 @@ static int zero_hash_eq(uint8_t *a, uint8_t *b, int sz)
911
return !memcmp(a, b, sz);
912
}
913
914
+static int reftable_log_record_equal_void(const void *a,
915
+ const void *b, int hash_size)
916
+{
917
+ return reftable_log_record_equal((struct reftable_log_record *) a,
918
+ (struct reftable_log_record *) b,
919
+ hash_size);
920
+}
921
+
922
int reftable_log_record_equal(const struct reftable_log_record *a,
923
const struct reftable_log_record *b, int hash_size)
924
{
@@ -924,6 +962,7 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
962
.decode = &reftable_log_record_decode,
963
.release = &reftable_log_record_release_void,
964
.is_deletion = &reftable_log_record_is_deletion_void,
965
+ .equal = &reftable_log_record_equal_void
966
};
967
968
struct reftable_record reftable_new_record(uint8_t typ)
@@ -1042,6 +1081,14 @@ static int reftable_index_record_decode(void *rec, struct strbuf key,
1081
return start.len - in.len;
1082
}
1083
1084
+static int reftable_index_record_equal(const void *a, const void *b, int hash_size)
1085
+{
1086
+ struct reftable_index_record *ia = (struct reftable_index_record *) a;
1087
+ struct reftable_index_record *ib = (struct reftable_index_record *) b;
1088
+
1089
+ return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
1090
+}
1091
+
1092
static struct reftable_record_vtable reftable_index_record_vtable = {
1093
.key = &reftable_index_record_key,
1094
.type = BLOCK_TYPE_INDEX,
@@ -1051,6 +1098,7 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
1098
.decode = &reftable_index_record_decode,
1099
.release = &reftable_index_record_release,
1100
.is_deletion = ¬_a_deletion,
1101
+ .equal = &reftable_index_record_equal,
1102
};
1103
1104
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
@@ -1098,6 +1146,13 @@ int reftable_record_is_deletion(struct reftable_record *rec)
1146
return rec->ops->is_deletion(rec->data);
1147
}
1148
1149
+int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
1150
+{
1151
+ if (a->ops != b->ops)
1152
+ return 0;
1153
+ return a->ops->equal(a->data, b->data, hash_size);
1154
+}
1155
+
1156
void reftable_record_from_ref(struct reftable_record *rec,
1157
struct reftable_ref_record *ref_rec)
1158
{
reftable/record.h
+4
-1
@@ -58,6 +58,9 @@ struct reftable_record_vtable {
58
59
/* is this a tombstone? */
60
int (*is_deletion)(const void *rec);
61
+
62
+ /* Are two records equal? This assumes they have the same type. Returns 0 for non-equal. */
63
+ int (*equal)(const void *a, const void *b, int hash_size);
64
};
65
66
/* record is a generic wrapper for different types of records. */
@@ -98,7 +101,7 @@ struct reftable_obj_record {
101
};
102
103
/* see struct record_vtable */
101
-
104
+int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
105
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
106
uint8_t reftable_record_type(struct reftable_record *rec);
107
void reftable_record_copy_from(struct reftable_record *rec,
reftable/record_test.c
+3
-20
@@ -21,18 +21,7 @@ static void test_copy(struct reftable_record *rec)
21
reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ);
22
/* do it twice to catch memory leaks */
23
reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ);
24
- switch (reftable_record_type(©)) {
25
- case BLOCK_TYPE_REF:
26
- EXPECT(reftable_ref_record_equal(reftable_record_as_ref(©),
27
- reftable_record_as_ref(rec),
28
- GIT_SHA1_RAWSZ));
29
- break;
30
- case BLOCK_TYPE_LOG:
31
- EXPECT(reftable_log_record_equal(reftable_record_as_log(©),
32
- reftable_record_as_log(rec),
33
- GIT_SHA1_RAWSZ));
34
- break;
35
- }
24
+ EXPECT(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ));
25
reftable_record_destroy(©);
26
}
27
@@ -346,13 +335,7 @@ static void test_reftable_obj_record_roundtrip(void)
335
GIT_SHA1_RAWSZ);
336
EXPECT(n == m);
337
349
- EXPECT(in.hash_prefix_len == out.hash_prefix_len);
350
- EXPECT(in.offset_len == out.offset_len);
351
-
352
- EXPECT(!memcmp(in.hash_prefix, out.hash_prefix,
353
- in.hash_prefix_len));
354
- EXPECT(0 == memcmp(in.offsets, out.offsets,
355
- sizeof(uint64_t) * in.offset_len));
338
+ EXPECT(reftable_record_equal(&rec, &rec_out, GIT_SHA1_RAWSZ));
339
strbuf_release(&key);
340
reftable_record_release(&rec_out);
341
}
@@ -390,7 +373,7 @@ static void test_reftable_index_record_roundtrip(void)
373
m = reftable_record_decode(&out_rec, key, extra, dest, GIT_SHA1_RAWSZ);
374
EXPECT(m == n);
375
393
- EXPECT(in.offset == out.offset);
376
+ EXPECT(reftable_record_equal(&rec, &out_rec, GIT_SHA1_RAWSZ));
377
378
reftable_record_release(&out_rec);
379
strbuf_release(&key);