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 )