odb_mempack.c 4.23 KB
Newer Older
Vicent Marti committed
1 2 3 4 5 6 7 8
/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

#include "common.h"
9

10
#include "buf.h"
11
#include "futils.h"
Vicent Marti committed
12 13 14 15
#include "hash.h"
#include "odb.h"
#include "array.h"
#include "oidmap.h"
16
#include "pack-objects.h"
Vicent Marti committed
17 18

#include "git2/odb_backend.h"
19
#include "git2/object.h"
Vicent Marti committed
20 21
#include "git2/types.h"
#include "git2/pack.h"
22 23
#include "git2/sys/odb_backend.h"
#include "git2/sys/mempack.h"
Vicent Marti committed
24 25 26 27

struct memobject {
	git_oid oid;
	size_t len;
28
	git_object_t type;
29
	char data[GIT_FLEX_ARRAY];
Vicent Marti committed
30 31 32 33 34 35 36 37
};

struct memory_packer_db {
	git_odb_backend parent;
	git_oidmap *objects;
	git_array_t(struct memobject *) commits;
};

38
static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void *data, size_t len, git_object_t type)
Vicent Marti committed
39 40
{
	struct memory_packer_db *db = (struct memory_packer_db *)_backend;
41
	struct memobject *obj = NULL;
42
	size_t alloc_len;
Vicent Marti committed
43

44
	if (git_oidmap_exists(db->objects, oid))
Vicent Marti committed
45 46
		return 0;

47
	GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(struct memobject), len);
48
	obj = git__malloc(alloc_len);
49
	GIT_ERROR_CHECK_ALLOC(obj);
Vicent Marti committed
50 51 52 53 54 55

	memcpy(obj->data, data, len);
	git_oid_cpy(&obj->oid, oid);
	obj->len = len;
	obj->type = type;

56 57
	if (git_oidmap_set(db->objects, &obj->oid, obj) < 0)
		return -1;
Vicent Marti committed
58

59
	if (type == GIT_OBJECT_COMMIT) {
Vicent Marti committed
60
		struct memobject **store = git_array_alloc(db->commits);
61
		GIT_ERROR_CHECK_ALLOC(store);
Vicent Marti committed
62 63 64 65 66 67 68 69 70 71
		*store = obj;
	}

	return 0;
}

static int impl__exists(git_odb_backend *backend, const git_oid *oid)
{
	struct memory_packer_db *db = (struct memory_packer_db *)backend;

72
	return git_oidmap_exists(db->objects, oid);
Vicent Marti committed
73 74
}

75
static int impl__read(void **buffer_p, size_t *len_p, git_object_t *type_p, git_odb_backend *backend, const git_oid *oid)
Vicent Marti committed
76 77
{
	struct memory_packer_db *db = (struct memory_packer_db *)backend;
78
	struct memobject *obj;
Vicent Marti committed
79

80
	if ((obj = git_oidmap_get(db->objects, oid)) == NULL)
Vicent Marti committed
81 82 83 84 85
		return GIT_ENOTFOUND;

	*len_p = obj->len;
	*type_p = obj->type;
	*buffer_p = git__malloc(obj->len);
86
	GIT_ERROR_CHECK_ALLOC(*buffer_p);
Vicent Marti committed
87 88 89 90 91

	memcpy(*buffer_p, obj->data, obj->len);
	return 0;
}

92
static int impl__read_header(size_t *len_p, git_object_t *type_p, git_odb_backend *backend, const git_oid *oid)
Vicent Marti committed
93 94
{
	struct memory_packer_db *db = (struct memory_packer_db *)backend;
95
	struct memobject *obj;
Vicent Marti committed
96

97
	if ((obj = git_oidmap_get(db->objects, oid)) == NULL)
Vicent Marti committed
98 99 100 101 102 103 104
		return GIT_ENOTFOUND;

	*len_p = obj->len;
	*type_p = obj->type;
	return 0;
}

105 106 107 108
static int git_mempack__dump(
	git_str *pack,
	git_repository *repo,
	git_odb_backend *_backend)
Vicent Marti committed
109 110 111 112 113 114 115 116 117
{
	struct memory_packer_db *db = (struct memory_packer_db *)_backend;
	git_packbuilder *packbuilder;
	uint32_t i;
	int err = -1;

	if (git_packbuilder_new(&packbuilder, repo) < 0)
		return -1;

118 119
	git_packbuilder_set_threads(packbuilder, 0);

Vicent Marti committed
120 121 122 123 124 125 126 127
	for (i = 0; i < db->commits.size; ++i) {
		struct memobject *commit = db->commits.ptr[i];

		err = git_packbuilder_insert_commit(packbuilder, &commit->oid);
		if (err < 0)
			goto cleanup;
	}

128
	err = git_packbuilder__write_buf(pack, packbuilder);
Vicent Marti committed
129 130 131 132 133 134

cleanup:
	git_packbuilder_free(packbuilder);
	return err;
}

135 136 137 138 139 140 141 142
int git_mempack_dump(
	git_buf *pack,
	git_repository *repo,
	git_odb_backend *_backend)
{
	GIT_BUF_WRAP_PRIVATE(pack, git_mempack__dump, repo, _backend);
}

143
int git_mempack_reset(git_odb_backend *_backend)
Vicent Marti committed
144 145 146 147
{
	struct memory_packer_db *db = (struct memory_packer_db *)_backend;
	struct memobject *object = NULL;

148
	git_oidmap_foreach_value(db->objects, object, {
Vicent Marti committed
149 150 151 152
		git__free(object);
	});

	git_array_clear(db->commits);
153

154
	git_oidmap_clear(db->objects);
155 156

	return 0;
Vicent Marti committed
157 158 159 160
}

static void impl__free(git_odb_backend *_backend)
{
161 162
	struct memory_packer_db *db = (struct memory_packer_db *)_backend;

163
	git_mempack_reset(_backend);
164 165
	git_oidmap_free(db->objects);
	git__free(db);
Vicent Marti committed
166 167 168 169 170 171
}

int git_mempack_new(git_odb_backend **out)
{
	struct memory_packer_db *db;

172
	GIT_ASSERT_ARG(out);
Vicent Marti committed
173 174

	db = git__calloc(1, sizeof(struct memory_packer_db));
175
	GIT_ERROR_CHECK_ALLOC(db);
Vicent Marti committed
176

177 178
	if (git_oidmap_new(&db->objects) < 0)
		return -1;
Vicent Marti committed
179

180
	db->parent.version = GIT_ODB_BACKEND_VERSION;
Vicent Marti committed
181 182 183 184 185 186 187 188 189
	db->parent.read = &impl__read;
	db->parent.write = &impl__write;
	db->parent.read_header = &impl__read_header;
	db->parent.exists = &impl__exists;
	db->parent.free = &impl__free;

	*out = (git_odb_backend *)db;
	return 0;
}