Skip to content

Commit d831e63

Browse files
committed
Added redis refdb backend
1 parent 77b1e71 commit d831e63

File tree

1 file changed

+329
-0
lines changed

1 file changed

+329
-0
lines changed

redis/hiredis.c

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include <string.h>
2828
#include <git2.h>
2929
#include <git2/sys/odb_backend.h>
30+
#include <git2/sys/refdb_backend.h>
31+
#include <git2/sys/refs.h>
3032
#include <hiredis/hiredis.h>
3133

3234
typedef struct {
@@ -37,6 +39,25 @@ typedef struct {
3739
redisContext *db;
3840
} hiredis_odb_backend;
3941

42+
typedef struct {
43+
git_refdb_backend parent;
44+
45+
const char *prefix;
46+
const char *repo_path;
47+
redisContext *db;
48+
} hiredis_refdb_backend;
49+
50+
typedef struct {
51+
git_reference_iterator parent;
52+
53+
size_t current;
54+
redisReply *keys;
55+
56+
hiredis_refdb_backend *backend;
57+
} hiredis_refdb_iterator;
58+
59+
/* Odb methods */
60+
4061
int hiredis_odb_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid)
4162
{
4263
hiredis_odb_backend *backend;
@@ -197,6 +218,274 @@ void hiredis_odb_backend__free(git_odb_backend *_backend)
197218
free(backend);
198219
}
199220

221+
/* Refdb methods */
222+
223+
int hiredis_refdb_backend__exists(int *exists, git_refdb_backend *_backend, const char *ref_name)
224+
{
225+
hiredis_refdb_backend *backend;
226+
int error = GIT_OK;
227+
redisReply *reply;
228+
229+
assert(ref_name && _backend);
230+
231+
backend = (hiredis_refdb_backend *) _backend;
232+
233+
reply = redisCommand(backend->db, "EXISTS %s:%s:refdb:%s", backend->prefix, backend->repo_path, ref_name);
234+
if (reply->type == REDIS_REPLY_INTEGER) {
235+
*exists = reply->integer;
236+
} else {
237+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
238+
error = GIT_ERROR;
239+
}
240+
241+
freeReplyObject(reply);
242+
return error;
243+
}
244+
245+
int hiredis_refdb_backend__lookup(git_reference **out, git_refdb_backend *_backend, const char *ref_name)
246+
{
247+
hiredis_refdb_backend *backend;
248+
int error = GIT_OK;
249+
redisReply *reply;
250+
git_oid oid;
251+
252+
assert(ref_name && _backend);
253+
254+
backend = (hiredis_refdb_backend *) _backend;
255+
256+
reply = redisCommand(backend->db, "HMGET %s:%s:refdb:%s type target", backend->prefix, backend->repo_path, ref_name);
257+
if(reply->type == REDIS_REPLY_ARRAY) {
258+
if (reply->element[0]->type != REDIS_REPLY_NIL && reply->element[1]->type != REDIS_REPLY_NIL) {
259+
git_ref_t type = (git_ref_t) atoi(reply->element[0]->str);
260+
261+
if (type == GIT_REF_OID) {
262+
git_oid_fromstr(&oid, reply->element[1]->str);
263+
*out = git_reference__alloc(ref_name, &oid, NULL);
264+
} else if (type == GIT_REF_SYMBOLIC) {
265+
*out = git_reference__alloc_symbolic(ref_name, reply->element[1]->str);
266+
} else {
267+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage corrupted (unknown ref type returned)");
268+
error = GIT_ERROR;
269+
}
270+
271+
} else {
272+
giterr_set_str(GITERR_REFERENCE, "Redis refdb couldn't find ref");
273+
error = GIT_ENOTFOUND;
274+
}
275+
} else {
276+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
277+
error = GIT_ERROR;
278+
}
279+
280+
freeReplyObject(reply);
281+
return error;
282+
}
283+
284+
int hiredis_refdb_backend__iterator_next(git_reference **ref, git_reference_iterator *_iter) {
285+
hiredis_refdb_iterator *iter;
286+
hiredis_refdb_backend *backend;
287+
char* ref_name;
288+
int error;
289+
290+
assert(_iter);
291+
iter = (hiredis_refdb_iterator *) _iter;
292+
293+
if(iter->current < iter->keys->elements) {
294+
ref_name = strstr(iter->keys->element[iter->current++]->str, ":refdb:") + 7;
295+
error = hiredis_refdb_backend__lookup(ref, (git_refdb_backend *) iter->backend, ref_name);
296+
297+
return error;
298+
} else {
299+
return GIT_ITEROVER;
300+
}
301+
}
302+
303+
int hiredis_refdb_backend__iterator_next_name(const char **ref_name, git_reference_iterator *_iter) {
304+
hiredis_refdb_iterator *iter;
305+
306+
assert(_iter);
307+
iter = (hiredis_refdb_iterator *) _iter;
308+
309+
if(iter->current < iter->keys->elements) {
310+
*ref_name = strdup(strstr(iter->keys->element[iter->current++]->str, ":refdb:") + 7);
311+
312+
return GIT_OK;
313+
} else {
314+
return GIT_ITEROVER;
315+
}
316+
}
317+
318+
void hiredis_refdb_backend__iterator_free(git_reference_iterator *_iter) {
319+
hiredis_refdb_iterator *iter;
320+
321+
assert(_iter);
322+
iter = (hiredis_refdb_iterator *) _iter;
323+
324+
freeReplyObject(iter->keys);
325+
326+
free(iter);
327+
}
328+
329+
int hiredis_refdb_backend__iterator(git_reference_iterator **_iter, struct git_refdb_backend *_backend, const char *glob)
330+
{
331+
hiredis_refdb_backend *backend;
332+
hiredis_refdb_iterator *iterator;
333+
int error = GIT_OK;
334+
redisReply *reply;
335+
336+
assert(_backend);
337+
338+
backend = (hiredis_refdb_backend *) _backend;
339+
340+
reply = redisCommand(backend->db, "KEYS %s:%s:refdb:%s", backend->prefix, backend->repo_path, (glob != NULL ? glob : "*"));
341+
if(reply->type != REDIS_REPLY_ARRAY) {
342+
freeReplyObject(reply);
343+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
344+
return GIT_ERROR;
345+
}
346+
347+
iterator = calloc(1, sizeof(hiredis_refdb_iterator));
348+
349+
iterator->backend = backend;
350+
iterator->keys = reply;
351+
352+
iterator->parent.next = &hiredis_refdb_backend__iterator_next;
353+
iterator->parent.next_name = &hiredis_refdb_backend__iterator_next_name;
354+
iterator->parent.free = &hiredis_refdb_backend__iterator_free;
355+
356+
*_iter = (git_reference_iterator *) iterator;
357+
358+
return GIT_OK;
359+
}
360+
361+
int hiredis_refdb_backend__write(git_refdb_backend *_backend, const git_reference *ref, int force, const git_signature *who,
362+
const char *message) // FIXME when rugged gets updated to the latest libgit2 update this to the latest backend API
363+
{
364+
hiredis_refdb_backend *backend;
365+
int error = GIT_OK;
366+
redisReply *reply;
367+
368+
const char *name = git_reference_name(ref);
369+
const git_oid *target;
370+
const char *symbolic_target;
371+
char oid_str[GIT_OID_HEXSZ + 1];
372+
373+
assert(ref && _backend);
374+
375+
backend = (hiredis_refdb_backend *) _backend;
376+
377+
target = git_reference_target(ref);
378+
symbolic_target = git_reference_symbolic_target(ref);
379+
380+
/* FIXME handle force correctly */
381+
382+
if (target) {
383+
git_oid_nfmt(oid_str, sizeof(oid_str), target);
384+
reply = redisCommand(backend->db, "HMSET %s:%s:refdb:%s type %d target %s", backend->prefix, backend->repo_path, name, GIT_REF_OID, oid_str);
385+
} else {
386+
symbolic_target = git_reference_symbolic_target(ref);
387+
reply = redisCommand(backend->db, "HMSET %s:%s:refdb:%s type %d target %s", backend->prefix, backend->repo_path, name, GIT_REF_SYMBOLIC, symbolic_target);
388+
}
389+
390+
if(reply->type == REDIS_REPLY_ERROR) {
391+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
392+
error = GIT_ERROR;
393+
}
394+
395+
freeReplyObject(reply);
396+
return error;
397+
}
398+
399+
int hiredis_refdb_backend__rename(git_reference **out, git_refdb_backend *_backend, const char *old_name,
400+
const char *new_name, int force, const git_signature *who, const char *message)
401+
{
402+
hiredis_refdb_backend *backend;
403+
int error = GIT_OK;
404+
redisReply *reply;
405+
406+
assert(old_name && new_name && _backend);
407+
408+
backend = (hiredis_refdb_backend *) _backend;
409+
410+
reply = redisCommand(backend->db, "RENAME %s:%s:refdb:%s %s:%s:refdb:%s",
411+
backend->prefix, backend->repo_path, old_name, backend->prefix, backend->repo_path, new_name);
412+
if(reply->type == REDIS_REPLY_ERROR) {
413+
freeReplyObject(reply);
414+
415+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
416+
return GIT_ERROR;
417+
}
418+
419+
freeReplyObject(reply);
420+
return hiredis_refdb_backend__lookup(out, _backend, new_name);
421+
}
422+
423+
int hiredis_refdb_backend__del(git_refdb_backend *_backend, const char *ref_name) // FIXME when rugged gets updated to the latest libgit2 update this to the latest backend API
424+
{
425+
hiredis_refdb_backend *backend;
426+
int error = GIT_OK;
427+
redisReply *reply;
428+
429+
assert(ref_name && _backend);
430+
431+
backend = (hiredis_refdb_backend *) _backend;
432+
433+
reply = redisCommand(backend->db, "DEL %s:%s:refdb:%s", backend->prefix, backend->repo_path, ref_name);
434+
if(reply->type == REDIS_REPLY_ERROR) {
435+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage error");
436+
error = GIT_ERROR;
437+
}
438+
439+
freeReplyObject(reply);
440+
return error;
441+
}
442+
443+
void hiredis_refdb_backend__free(git_refdb_backend *_backend)
444+
{
445+
hiredis_refdb_backend *backend;
446+
447+
assert(_backend);
448+
backend = (hiredis_refdb_backend *) _backend;
449+
450+
redisFree(backend->db);
451+
452+
free(backend);
453+
}
454+
455+
/* reflog methods */
456+
457+
int hiredis_refdb_backend__has_log(git_refdb_backend *_backend, const char *refname)
458+
{
459+
return 0;
460+
}
461+
462+
int hiredis_refdb_backend__ensure_log(git_refdb_backend *_backend, const char *refname)
463+
{
464+
return GIT_ERROR;
465+
}
466+
467+
int hiredis_refdb_backend__reflog_read(git_reflog **out, git_refdb_backend *_backend, const char *name)
468+
{
469+
return GIT_ERROR;
470+
}
471+
472+
int hiredis_refdb_backend__reflog_write(git_refdb_backend *_backend, git_reflog *reflog)
473+
{
474+
return GIT_ERROR;
475+
}
476+
477+
int hiredis_refdb_backend__reflog_rename(git_refdb_backend *_backend, const char *old_name, const char *new_name)
478+
{
479+
return GIT_ERROR;
480+
}
481+
482+
int hiredis_refdb_backend__reflog_delete(git_refdb_backend *_backend, const char *name)
483+
{
484+
return GIT_ERROR;
485+
}
486+
487+
/* Constructors */
488+
200489
int git_odb_backend_hiredis(git_odb_backend **backend_out, const char* prefix, const char* path, const char *host, int port)
201490
{
202491
hiredis_odb_backend *backend;
@@ -231,3 +520,43 @@ int git_odb_backend_hiredis(git_odb_backend **backend_out, const char* prefix, c
231520

232521
return GIT_OK;
233522
}
523+
524+
int git_refdb_backend_hiredis(git_refdb_backend **backend_out, const char* prefix, const char* path, const char *host, int port)
525+
{
526+
hiredis_refdb_backend *backend;
527+
528+
backend = calloc(1, sizeof(hiredis_refdb_backend));
529+
if (backend == NULL)
530+
return GITERR_NOMEMORY;
531+
532+
backend-> db = redisConnect(host, port);
533+
if (backend->db->err) {
534+
free(backend);
535+
giterr_set_str(GITERR_REFERENCE, "Redis refdb storage couldn't connect to redis server");
536+
return GIT_ERROR;
537+
}
538+
539+
backend->prefix = prefix;
540+
backend->repo_path = path;
541+
542+
backend->parent.exists = &hiredis_refdb_backend__exists;
543+
backend->parent.lookup = &hiredis_refdb_backend__lookup;
544+
backend->parent.iterator = &hiredis_refdb_backend__iterator;
545+
backend->parent.write = &hiredis_refdb_backend__write;
546+
backend->parent.del = &hiredis_refdb_backend__del;
547+
backend->parent.rename = &hiredis_refdb_backend__rename;
548+
backend->parent.compress = NULL;
549+
backend->parent.free = &hiredis_refdb_backend__free;
550+
551+
backend->parent.has_log = &hiredis_refdb_backend__has_log;
552+
backend->parent.ensure_log = &hiredis_refdb_backend__ensure_log;
553+
backend->parent.reflog_read = &hiredis_refdb_backend__reflog_read;
554+
backend->parent.reflog_write = &hiredis_refdb_backend__reflog_write;
555+
backend->parent.reflog_rename = &hiredis_refdb_backend__reflog_rename;
556+
backend->parent.reflog_delete = &hiredis_refdb_backend__reflog_delete;
557+
558+
*backend_out = (git_refdb_backend *) backend;
559+
560+
return GIT_OK;
561+
}
562+

0 commit comments

Comments
 (0)