Files
git/odb/source-inmemory.c
Patrick Steinhardt 8179380518 odb/source-inmemory: stub out remaining functions
Stub out remaining functions that we either don't need or that are
basically no-ops.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-09 11:17:08 -07:00

379 lines
10 KiB
C

#include "git-compat-util.h"
#include "object-file.h"
#include "odb.h"
#include "odb/source-inmemory.h"
#include "odb/streaming.h"
#include "oidtree.h"
#include "repository.h"
struct inmemory_object {
enum object_type type;
const void *buf;
unsigned long size;
};
static const struct inmemory_object *find_cached_object(struct odb_source_inmemory *source,
const struct object_id *oid)
{
static const struct inmemory_object empty_tree = {
.type = OBJ_TREE,
.buf = "",
};
const struct inmemory_object *object;
if (source->objects) {
object = oidtree_get(source->objects, oid);
if (object)
return object;
}
if (oid->algo && oideq(oid, hash_algos[oid->algo].empty_tree))
return &empty_tree;
return NULL;
}
static void populate_object_info(struct odb_source_inmemory *source,
struct object_info *oi,
const struct inmemory_object *object)
{
if (!oi)
return;
if (oi->typep)
*(oi->typep) = object->type;
if (oi->sizep)
*(oi->sizep) = object->size;
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
if (oi->delta_base_oid)
oidclr(oi->delta_base_oid, source->base.odb->repo->hash_algo);
if (oi->contentp)
*oi->contentp = xmemdupz(object->buf, object->size);
if (oi->mtimep)
*oi->mtimep = 0;
oi->whence = OI_CACHED;
}
static int odb_source_inmemory_read_object_info(struct odb_source *source,
const struct object_id *oid,
struct object_info *oi,
enum object_info_flags flags UNUSED)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
const struct inmemory_object *object;
object = find_cached_object(inmemory, oid);
if (!object)
return -1;
populate_object_info(inmemory, oi, object);
return 0;
}
struct odb_read_stream_inmemory {
struct odb_read_stream base;
const void *buf;
size_t offset;
};
static ssize_t odb_read_stream_inmemory_read(struct odb_read_stream *stream,
char *buf, size_t buf_len)
{
struct odb_read_stream_inmemory *inmemory =
container_of(stream, struct odb_read_stream_inmemory, base);
size_t bytes = buf_len;
if (buf_len > inmemory->base.size - inmemory->offset)
bytes = inmemory->base.size - inmemory->offset;
memcpy(buf, inmemory->buf, bytes);
return bytes;
}
static int odb_read_stream_inmemory_close(struct odb_read_stream *stream UNUSED)
{
return 0;
}
static int odb_source_inmemory_read_object_stream(struct odb_read_stream **out,
struct odb_source *source,
const struct object_id *oid)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
struct odb_read_stream_inmemory *stream;
const struct inmemory_object *object;
object = find_cached_object(inmemory, oid);
if (!object)
return -1;
CALLOC_ARRAY(stream, 1);
stream->base.read = odb_read_stream_inmemory_read;
stream->base.close = odb_read_stream_inmemory_close;
stream->base.size = object->size;
stream->base.type = object->type;
stream->buf = object->buf;
*out = &stream->base;
return 0;
}
struct odb_source_inmemory_for_each_object_data {
struct odb_source_inmemory *inmemory;
const struct object_info *request;
odb_for_each_object_cb cb;
void *cb_data;
};
static int odb_source_inmemory_for_each_object_cb(const struct object_id *oid,
void *node_data, void *cb_data)
{
struct odb_source_inmemory_for_each_object_data *data = cb_data;
struct inmemory_object *object = node_data;
if (data->request) {
struct object_info oi = *data->request;
populate_object_info(data->inmemory, &oi, object);
return data->cb(oid, &oi, data->cb_data);
} else {
return data->cb(oid, NULL, data->cb_data);
}
}
static int odb_source_inmemory_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
struct odb_source_inmemory_for_each_object_data payload = {
.inmemory = inmemory,
.request = request,
.cb = cb,
.cb_data = cb_data,
};
struct object_id null_oid = { 0 };
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) ||
(opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local))
return 0;
return oidtree_each(inmemory->objects,
opts->prefix ? opts->prefix : &null_oid, opts->prefix_hex_len,
odb_source_inmemory_for_each_object_cb, &payload);
}
struct find_abbrev_len_data {
const struct object_id *oid;
unsigned len;
};
static int find_abbrev_len_cb(const struct object_id *oid,
struct object_info *oi UNUSED,
void *cb_data)
{
struct find_abbrev_len_data *data = cb_data;
unsigned len = oid_common_prefix_hexlen(oid, data->oid);
if (len != hash_algos[oid->algo].hexsz && len >= data->len)
data->len = len + 1;
return 0;
}
static int odb_source_inmemory_find_abbrev_len(struct odb_source *source,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
struct odb_for_each_object_options opts = {
.prefix = oid,
.prefix_hex_len = min_len,
};
struct find_abbrev_len_data data = {
.oid = oid,
.len = min_len,
};
int ret;
ret = odb_source_inmemory_for_each_object(source, NULL, find_abbrev_len_cb,
&data, &opts);
*out = data.len;
return ret;
}
static int count_objects_cb(const struct object_id *oid UNUSED,
struct object_info *oi UNUSED,
void *cb_data)
{
unsigned long *counter = cb_data;
(*counter)++;
return 0;
}
static int odb_source_inmemory_count_objects(struct odb_source *source,
enum odb_count_objects_flags flags UNUSED,
unsigned long *out)
{
struct odb_for_each_object_options opts = { 0 };
*out = 0;
return odb_source_inmemory_for_each_object(source, NULL, count_objects_cb,
out, &opts);
}
static int odb_source_inmemory_write_object(struct odb_source *source,
const void *buf, unsigned long len,
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid UNUSED,
enum odb_write_object_flags flags UNUSED)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
struct inmemory_object *object;
hash_object_file(source->odb->repo->hash_algo, buf, len, type, oid);
if (!inmemory->objects) {
CALLOC_ARRAY(inmemory->objects, 1);
oidtree_init(inmemory->objects);
} else if (oidtree_contains(inmemory->objects, oid)) {
return 0;
}
CALLOC_ARRAY(object, 1);
object->size = len;
object->type = type;
object->buf = xmemdupz(buf, len);
oidtree_insert(inmemory->objects, oid, object);
return 0;
}
static int odb_source_inmemory_write_object_stream(struct odb_source *source,
struct odb_write_stream *stream,
size_t len,
struct object_id *oid)
{
char buf[16384];
size_t total_read = 0;
char *data;
int ret;
CALLOC_ARRAY(data, len);
while (!stream->is_finished) {
ssize_t bytes_read;
bytes_read = odb_write_stream_read(stream, buf, sizeof(buf));
if (total_read + bytes_read > len) {
ret = error("object stream yielded more bytes than expected");
goto out;
}
memcpy(data, buf, bytes_read);
total_read += bytes_read;
}
if (total_read != len) {
ret = error("object stream yielded less bytes than expected");
goto out;
}
ret = odb_source_inmemory_write_object(source, data, len, OBJ_BLOB, oid,
NULL, 0);
if (ret < 0)
goto out;
out:
free(data);
return ret;
}
static int odb_source_inmemory_freshen_object(struct odb_source *source,
const struct object_id *oid)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
if (find_cached_object(inmemory, oid))
return 1;
return 0;
}
static int odb_source_inmemory_begin_transaction(struct odb_source *source UNUSED,
struct odb_transaction **out UNUSED)
{
return error("inmemory source does not support transactions");
}
static int odb_source_inmemory_read_alternates(struct odb_source *source UNUSED,
struct strvec *out UNUSED)
{
return 0;
}
static int odb_source_inmemory_write_alternate(struct odb_source *source UNUSED,
const char *alternate UNUSED)
{
return error("inmemory source does not support alternates");
}
static void odb_source_inmemory_close(struct odb_source *source UNUSED)
{
}
static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
{
}
static int inmemory_object_free(const struct object_id *oid UNUSED,
void *node_data,
void *cb_data UNUSED)
{
struct inmemory_object *object = node_data;
free((void *) object->buf);
free(object);
return 0;
}
static void odb_source_inmemory_free(struct odb_source *source)
{
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
if (inmemory->objects) {
struct object_id null_oid = { 0 };
oidtree_each(inmemory->objects, &null_oid, 0,
inmemory_object_free, NULL);
oidtree_clear(inmemory->objects);
free(inmemory->objects);
}
free(inmemory->base.path);
free(inmemory);
}
struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
{
struct odb_source_inmemory *source;
CALLOC_ARRAY(source, 1);
odb_source_init(&source->base, odb, ODB_SOURCE_INMEMORY, "source", false);
source->base.free = odb_source_inmemory_free;
source->base.close = odb_source_inmemory_close;
source->base.reprepare = odb_source_inmemory_reprepare;
source->base.read_object_info = odb_source_inmemory_read_object_info;
source->base.read_object_stream = odb_source_inmemory_read_object_stream;
source->base.for_each_object = odb_source_inmemory_for_each_object;
source->base.find_abbrev_len = odb_source_inmemory_find_abbrev_len;
source->base.count_objects = odb_source_inmemory_count_objects;
source->base.write_object = odb_source_inmemory_write_object;
source->base.write_object_stream = odb_source_inmemory_write_object_stream;
source->base.freshen_object = odb_source_inmemory_freshen_object;
source->base.begin_transaction = odb_source_inmemory_begin_transaction;
source->base.read_alternates = odb_source_inmemory_read_alternates;
source->base.write_alternate = odb_source_inmemory_write_alternate;
return source;
}