Database-Sophia
view release on metacpan or search on metacpan
Sophia-src/db/recover.c view on Meta::CPAN
/*
* sophia database
* sphia.org
*
* Copyright (c) Dmitry Simonenko
* BSD License
*/
#include <sp.h>
#include <track.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
static inline int sp_dircreate(sp *s)
{
int rc = mkdir(s->env->dir, 0700);
if (spunlikely(rc == -1)) {
sp_e(s, SPE, "failed to create directory %s (errno: %d, %s)",
s->env->dir, errno, strerror(errno));
return -1;
}
return 0;
}
typedef struct {
splist link;
char dir[];
} spdirlock;
static spspinlock dirlock = 0;
static int dirlockn = 0;
static splist dirlocks;
static int sp_dirlock(sp *s)
{
/* implement multi-process database exclusive access by creating
* lock file. */
char path[1024];
snprintf(path, sizeof(path), "%s/lock", s->env->dir);
int rc = sp_lockfile(&s->lockdb, path);
if (spunlikely(rc == -1))
sp_e(s, SPE, "failed to create lock file (errno: %d, %s)",
errno, strerror(errno));
if (rc == 1)
return sp_e(s, SPE, "database is locked");
/* within a single process, add database path to the list and
* check the presence on a open. */
sp_lock(&dirlock);
if (dirlockn == 0) {
sp_listinit(&dirlocks);
} else {
splist *i;
sp_listforeach(&dirlocks, i) {
spdirlock *l = spcast(i, spdirlock, link);
if (! strcmp(s->env->dir, l->dir)) {
sp_unlock(&dirlock);
return sp_e(s, SPE, "database is locked");
}
}
}
int lendir = strlen(s->env->dir) + 1;
int len = sizeof(spdirlock) + lendir;
spdirlock *l = malloc(len);
if (spunlikely(l == NULL)) {
sp_unlock(&dirlock);
return sp_e(s, SPEOOM, "failed to allocate memory");
}
sp_listinit(&l->link);
memcpy(l->dir, s->env->dir, lendir);
sp_listappend(&dirlocks, &l->link);
dirlockn++;
sp_unlock(&dirlock);
return 0;
}
static int sp_dirunlock(sp *s)
{
sp_lock(&dirlock);
if (spunlikely(dirlockn == 0)) {
sp_unlock(&dirlock);
return 0;
}
splist *i, *n;
sp_listforeach_safe(&dirlocks, i, n) {
spdirlock *l = spcast(i, spdirlock, link);
if (! strcmp(s->env->dir, l->dir)) {
sp_listunlink(&l->link);
free(l);
break;
}
}
dirlockn--;
sp_unlock(&dirlock);
return sp_unlockfile(&s->lockdb);
}
static inline ssize_t
sp_epochof(char *s) {
size_t v = 0;
while (*s && *s != '.') {
if (spunlikely(!isdigit(*s)))
return -1;
v = (v * 10) + *s - '0';
s++;
}
return v;
}
static int sp_diropen(sp *s)
{
/* read repository and determine states */
DIR *d = opendir(s->env->dir);
if (spunlikely(d == NULL)) {
sp_e(s, SPE, "failed to open directory %s (errno: %d, %s)",
s->env->dir, errno, strerror(errno));
return -1;
}
( run in 1.039 second using v1.01-cache-2.11-cpan-99c4e6809bf )