Introduce xbps_repo_{un,}lock() to serialize write access to repodata.
We use a simple file lock that is created with O_CREAT|O_EXCL. This should fix the concurrency issues with multiple processes running xbps-rindex -a/-c on the same repository/arch combo.
This commit is contained in:
86
lib/repo.c
86
lib/repo.c
@@ -73,22 +73,61 @@ repo_get_dict(struct xbps_repo *repo)
|
||||
return xbps_archive_get_dictionary(repo->ar, entry);
|
||||
}
|
||||
|
||||
bool
|
||||
xbps_repo_lock(struct xbps_handle *xhp, const char *repodir,
|
||||
int *lockfd, char **lockfname)
|
||||
{
|
||||
char *repofile, *lockfile;
|
||||
int fd, rv;
|
||||
|
||||
assert(repodir);
|
||||
assert(lockfd);
|
||||
assert(lockfname);
|
||||
|
||||
repofile = xbps_repo_path(xhp, repodir);
|
||||
assert(repofile);
|
||||
|
||||
lockfile = xbps_xasprintf("%s.lock", repofile);
|
||||
free(repofile);
|
||||
|
||||
for (;;) {
|
||||
fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0660);
|
||||
rv = errno;
|
||||
if (fd != -1)
|
||||
break;
|
||||
if (rv != EEXIST) {
|
||||
xbps_dbg_printf(xhp, "[repo] `%s' failed to "
|
||||
"create lock file %s\n", lockfile, strerror(rv));
|
||||
free(lockfile);
|
||||
return false;
|
||||
} else {
|
||||
xbps_dbg_printf(xhp, "[repo] `%s' lock file exists,"
|
||||
"waiting...\n", lockfile);
|
||||
}
|
||||
}
|
||||
*lockfname = lockfile;
|
||||
*lockfd = fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
xbps_repo_unlock(int lockfd, char *lockfname)
|
||||
{
|
||||
if (lockfd != -1) {
|
||||
close(lockfd);
|
||||
}
|
||||
if (lockfname) {
|
||||
unlink(lockfname);
|
||||
free(lockfname);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
repo_open_local(struct xbps_repo *repo, const char *repofile, bool lock)
|
||||
repo_open_local(struct xbps_repo *repo, const char *repofile)
|
||||
{
|
||||
struct stat st;
|
||||
int rv = 0;
|
||||
|
||||
/*
|
||||
* Acquire a POSIX file lock on the archive; wait if the lock is
|
||||
* already taken.
|
||||
*/
|
||||
if (lock && lockf(repo->fd, F_LOCK, 0) == -1) {
|
||||
rv = errno;
|
||||
xbps_dbg_printf(repo->xhp, "[repo] failed to lock %s: %s\n",
|
||||
repofile, strerror(rv));
|
||||
return false;
|
||||
}
|
||||
if (fstat(repo->fd, &st) == -1) {
|
||||
rv = errno;
|
||||
xbps_dbg_printf(repo->xhp, "[repo] `%s' fstat repodata %s\n",
|
||||
@@ -179,7 +218,7 @@ xbps_repo_store(struct xbps_handle *xhp, const char *repo)
|
||||
}
|
||||
|
||||
struct xbps_repo *
|
||||
xbps_repo_open(struct xbps_handle *xhp, const char *url, bool lock)
|
||||
xbps_repo_open(struct xbps_handle *xhp, const char *url)
|
||||
{
|
||||
struct xbps_repo *repo;
|
||||
const char *arch;
|
||||
@@ -195,6 +234,7 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url, bool lock)
|
||||
|
||||
repo = calloc(1, sizeof(struct xbps_repo));
|
||||
assert(repo);
|
||||
repo->fd = -1;
|
||||
repo->xhp = xhp;
|
||||
repo->uri = url;
|
||||
|
||||
@@ -225,31 +265,21 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url, bool lock)
|
||||
/*
|
||||
* Open the repository archive.
|
||||
*/
|
||||
if (lock) {
|
||||
repo->fd = open(repofile, O_RDWR);
|
||||
repo->is_locked = true;
|
||||
} else {
|
||||
repo->fd = open(repofile, O_RDONLY);
|
||||
}
|
||||
|
||||
repo->fd = open(repofile, O_RDONLY);
|
||||
if (repo->fd == -1) {
|
||||
int rv = errno;
|
||||
xbps_dbg_printf(xhp, "[repo] `%s' open repodata %s\n",
|
||||
repofile, strerror(rv));
|
||||
goto out;
|
||||
}
|
||||
if (repo_open_local(repo, repofile, lock)) {
|
||||
if (repo_open_local(repo, repofile)) {
|
||||
free(repofile);
|
||||
return repo;
|
||||
}
|
||||
|
||||
out:
|
||||
if (repo->ar)
|
||||
archive_read_free(repo->ar);
|
||||
if (repo->fd != -1)
|
||||
close(repo->fd);
|
||||
free(repofile);
|
||||
free(repo);
|
||||
xbps_repo_close(repo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -269,10 +299,10 @@ xbps_repo_close(struct xbps_repo *repo)
|
||||
xbps_object_release(repo->idxmeta);
|
||||
repo->idxmeta = NULL;
|
||||
}
|
||||
if (repo->is_locked && lockf(repo->fd, F_ULOCK, 0) == -1)
|
||||
xbps_dbg_printf(repo->xhp, "[repo] failed to unlock %s: %s\n", repo->uri, strerror(errno));
|
||||
if (repo->fd != -1)
|
||||
close(repo->fd);
|
||||
|
||||
close(repo->fd);
|
||||
free(repo);
|
||||
}
|
||||
|
||||
xbps_dictionary_t
|
||||
|
@@ -92,7 +92,7 @@ xbps_regget_repo(struct xbps_handle *xhp, const char *url)
|
||||
if (strcmp(repouri, url))
|
||||
continue;
|
||||
|
||||
repo = xbps_repo_open(xhp, repouri, false);
|
||||
repo = xbps_repo_open(xhp, repouri);
|
||||
if (!repo)
|
||||
return NULL;
|
||||
|
||||
@@ -148,7 +148,7 @@ xbps_rpool_foreach(struct xbps_handle *xhp,
|
||||
for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) {
|
||||
xbps_array_get_cstring_nocopy(xhp->repositories, i, &repouri);
|
||||
if ((repo = xbps_rpool_get_repo(repouri)) == NULL) {
|
||||
repo = xbps_repo_open(xhp, repouri, false);
|
||||
repo = xbps_repo_open(xhp, repouri);
|
||||
if (!repo)
|
||||
continue;
|
||||
SIMPLEQ_INSERT_TAIL(&rpool_queue, repo, entries);
|
||||
|
Reference in New Issue
Block a user