2021-10-07 20:25:02 +00:00
|
|
|
/*
|
|
|
|
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 REFTABLE_RECORD_H
|
|
|
|
#define REFTABLE_RECORD_H
|
|
|
|
|
reftable/record: store "val1" hashes as static arrays
When reading ref records of type "val1", we store its object ID in an
allocated array. This results in an additional allocation for every
single ref record we read, which is rather inefficient especially when
iterating over refs.
Refactor the code to instead use an embedded array of `GIT_MAX_RAWSZ`
bytes. While this means that `struct ref_record` is bigger now, we
typically do not store all refs in an array anyway and instead only
handle a limited number of records at the same point in time.
Using `git show-ref --quiet` in a repository with ~350k refs this leads
to a significant drop in allocations. Before:
HEAP SUMMARY:
in use at exit: 21,098 bytes in 192 blocks
total heap usage: 2,116,683 allocs, 2,116,491 frees, 76,098,060 bytes allocated
After:
HEAP SUMMARY:
in use at exit: 21,098 bytes in 192 blocks
total heap usage: 1,419,031 allocs, 1,418,839 frees, 62,145,036 bytes allocated
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-01-03 06:22:30 +00:00
|
|
|
#include "hash-ll.h"
|
2021-10-07 20:25:02 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Basic data types
|
|
|
|
*
|
|
|
|
* Reftables store the state of each ref in struct reftable_ref_record, and they
|
|
|
|
* store a sequence of reflog updates in struct reftable_log_record.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* reftable_ref_record holds a ref database entry target_value */
|
|
|
|
struct reftable_ref_record {
|
|
|
|
char *refname; /* Name of the ref, malloced. */
|
|
|
|
uint64_t update_index; /* Logical timestamp at which this value is
|
|
|
|
* written */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/* tombstone to hide deletions from earlier tables */
|
|
|
|
REFTABLE_REF_DELETION = 0x0,
|
|
|
|
|
|
|
|
/* a simple ref */
|
|
|
|
REFTABLE_REF_VAL1 = 0x1,
|
|
|
|
/* a tag, plus its peeled hash */
|
|
|
|
REFTABLE_REF_VAL2 = 0x2,
|
|
|
|
|
|
|
|
/* a symbolic reference */
|
|
|
|
REFTABLE_REF_SYMREF = 0x3,
|
|
|
|
#define REFTABLE_NR_REF_VALUETYPES 4
|
|
|
|
} value_type;
|
|
|
|
union {
|
reftable/record: store "val1" hashes as static arrays
When reading ref records of type "val1", we store its object ID in an
allocated array. This results in an additional allocation for every
single ref record we read, which is rather inefficient especially when
iterating over refs.
Refactor the code to instead use an embedded array of `GIT_MAX_RAWSZ`
bytes. While this means that `struct ref_record` is bigger now, we
typically do not store all refs in an array anyway and instead only
handle a limited number of records at the same point in time.
Using `git show-ref --quiet` in a repository with ~350k refs this leads
to a significant drop in allocations. Before:
HEAP SUMMARY:
in use at exit: 21,098 bytes in 192 blocks
total heap usage: 2,116,683 allocs, 2,116,491 frees, 76,098,060 bytes allocated
After:
HEAP SUMMARY:
in use at exit: 21,098 bytes in 192 blocks
total heap usage: 1,419,031 allocs, 1,418,839 frees, 62,145,036 bytes allocated
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-01-03 06:22:30 +00:00
|
|
|
unsigned char val1[GIT_MAX_RAWSZ];
|
2021-10-07 20:25:02 +00:00
|
|
|
struct {
|
reftable/record: store "val2" hashes as static arrays
Similar to the preceding commit, convert ref records of type "val2" to
store their object IDs in static arrays instead of allocating them for
every single record.
We're using the same benchmark as in the preceding commit, with `git
show-ref --quiet` in a repository with ~350k refs. This time around
though the effects aren't this huge. Before:
HEAP SUMMARY:
in use at exit: 21,163 bytes in 193 blocks
total heap usage: 1,419,040 allocs, 1,418,847 frees, 62,153,868 bytes allocated
After:
HEAP SUMMARY:
in use at exit: 21,163 bytes in 193 blocks
total heap usage: 1,410,148 allocs, 1,409,955 frees, 61,976,068 bytes allocated
This is because "val2"-type records are typically only stored for peeled
tags, and the number of annotated tags in the benchmark repository is
rather low. Still, it can be seen that this change leads to a reduction
of allocations overall, even if only a small one.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-01-03 06:22:34 +00:00
|
|
|
unsigned char value[GIT_MAX_RAWSZ]; /* first hash */
|
|
|
|
unsigned char target_value[GIT_MAX_RAWSZ]; /* second hash */
|
2021-10-07 20:25:02 +00:00
|
|
|
} val2;
|
|
|
|
char *symref; /* referent, malloced 0-terminated string */
|
|
|
|
} value;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Returns the first hash, or NULL if `rec` is not of type
|
|
|
|
* REFTABLE_REF_VAL1 or REFTABLE_REF_VAL2. */
|
2024-01-03 06:22:26 +00:00
|
|
|
const unsigned char *reftable_ref_record_val1(const struct reftable_ref_record *rec);
|
2021-10-07 20:25:02 +00:00
|
|
|
|
|
|
|
/* Returns the second hash, or NULL if `rec` is not of type
|
|
|
|
* REFTABLE_REF_VAL2. */
|
2024-01-03 06:22:26 +00:00
|
|
|
const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *rec);
|
2021-10-07 20:25:02 +00:00
|
|
|
|
|
|
|
/* returns whether 'ref' represents a deletion */
|
|
|
|
int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
|
|
|
|
|
|
|
|
/* prints a reftable_ref_record onto stdout. Useful for debugging. */
|
2022-01-20 15:12:10 +00:00
|
|
|
void reftable_ref_record_print(const struct reftable_ref_record *ref,
|
2021-10-07 20:25:02 +00:00
|
|
|
uint32_t hash_id);
|
|
|
|
|
|
|
|
/* frees and nulls all pointer values inside `ref`. */
|
|
|
|
void reftable_ref_record_release(struct reftable_ref_record *ref);
|
|
|
|
|
|
|
|
/* returns whether two reftable_ref_records are the same. Useful for testing. */
|
2022-01-20 15:12:10 +00:00
|
|
|
int reftable_ref_record_equal(const struct reftable_ref_record *a,
|
|
|
|
const struct reftable_ref_record *b, int hash_size);
|
2021-10-07 20:25:02 +00:00
|
|
|
|
|
|
|
/* reftable_log_record holds a reflog entry */
|
|
|
|
struct reftable_log_record {
|
|
|
|
char *refname;
|
|
|
|
uint64_t update_index; /* logical timestamp of a transactional update.
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/* tombstone to hide deletions from earlier tables */
|
|
|
|
REFTABLE_LOG_DELETION = 0x0,
|
|
|
|
|
|
|
|
/* a simple update */
|
|
|
|
REFTABLE_LOG_UPDATE = 0x1,
|
|
|
|
#define REFTABLE_NR_LOG_VALUETYPES 2
|
|
|
|
} value_type;
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
uint8_t *new_hash;
|
|
|
|
uint8_t *old_hash;
|
|
|
|
char *name;
|
|
|
|
char *email;
|
|
|
|
uint64_t time;
|
|
|
|
int16_t tz_offset;
|
|
|
|
char *message;
|
|
|
|
} update;
|
|
|
|
} value;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* returns whether 'ref' represents the deletion of a log record. */
|
|
|
|
int reftable_log_record_is_deletion(const struct reftable_log_record *log);
|
|
|
|
|
|
|
|
/* frees and nulls all pointer values. */
|
|
|
|
void reftable_log_record_release(struct reftable_log_record *log);
|
|
|
|
|
|
|
|
/* returns whether two records are equal. Useful for testing. */
|
2022-01-20 15:12:10 +00:00
|
|
|
int reftable_log_record_equal(const struct reftable_log_record *a,
|
|
|
|
const struct reftable_log_record *b, int hash_size);
|
2021-10-07 20:25:02 +00:00
|
|
|
|
|
|
|
/* dumps a reftable_log_record on stdout, for debugging/testing. */
|
|
|
|
void reftable_log_record_print(struct reftable_log_record *log,
|
|
|
|
uint32_t hash_id);
|
|
|
|
|
|
|
|
#endif
|