Fix concurrency issues in pkgdb: only allow 1 write transaction at the same time.
This implementation relies on a POSIX named semaphore, which is also required by xbps-rindex(8).
This commit is contained in:
parent
bc2bada045
commit
4d1cdcac0c
4
NEWS
4
NEWS
@ -1,5 +1,9 @@
|
|||||||
xbps-0.33 (???):
|
xbps-0.33 (???):
|
||||||
|
|
||||||
|
* Only allow a single writer to the pkgdb to avoid concurrency issues
|
||||||
|
when performing multiple write transactions (install, update or remove).
|
||||||
|
The implementation relies on a POSIX named semaphore.
|
||||||
|
|
||||||
* Do not continue the transaction if downloading a binpkg/signature file
|
* Do not continue the transaction if downloading a binpkg/signature file
|
||||||
has failed for some reason, stop and return error immediately.
|
has failed for some reason, stop and return error immediately.
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ See `git tag -l` to list all available stable releases.
|
|||||||
To build this you'll need:
|
To build this you'll need:
|
||||||
|
|
||||||
- A C99 compiler (clang and gcc tested)
|
- A C99 compiler (clang and gcc tested)
|
||||||
|
- A system that supports POSIX named semaphores
|
||||||
- [GNU make](http://www.gnu.org/software/make/)
|
- [GNU make](http://www.gnu.org/software/make/)
|
||||||
- [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/)
|
- [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||||
- [zlib](http://www.zlib.net)
|
- [zlib](http://www.zlib.net)
|
||||||
|
1
TODO
1
TODO
@ -2,7 +2,6 @@ libxbps:
|
|||||||
- transaction: avoid fetching the whole pkg when updating and only fetch
|
- transaction: avoid fetching the whole pkg when updating and only fetch
|
||||||
modified files from target pkg.
|
modified files from target pkg.
|
||||||
- Add support to handle 'shlib-requires' and 'shlib-provides'.
|
- Add support to handle 'shlib-requires' and 'shlib-provides'.
|
||||||
- Concurrency issues with pkgdb.
|
|
||||||
|
|
||||||
xbps-create:
|
xbps-create:
|
||||||
- Move all configuration files to <prefix>/share/<pkgname>/conf/<cffile>.
|
- Move all configuration files to <prefix>/share/<pkgname>/conf/<cffile>.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2008-2013 Juan Romero Pardines.
|
* Copyright (c) 2008-2014 Juan Romero Pardines.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -216,6 +216,11 @@ main(int argc, char **argv)
|
|||||||
if (sync && !update && (argc == optind))
|
if (sync && !update && (argc == optind))
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
if ((rv = xbps_pkgdb_lock(&xh)) != 0) {
|
||||||
|
fprintf(stderr, "Failed to lock the pkgdb: %s\n", strerror(rv));
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
|
||||||
if (update && (argc == optind)) {
|
if (update && (argc == optind)) {
|
||||||
/* Update all installed packages */
|
/* Update all installed packages */
|
||||||
rv = dist_upgrade(&xh, maxcols, yes, drun);
|
rv = dist_upgrade(&xh, maxcols, yes, drun);
|
||||||
@ -223,19 +228,24 @@ main(int argc, char **argv)
|
|||||||
/* Update target packages */
|
/* Update target packages */
|
||||||
for (i = optind; i < argc; i++) {
|
for (i = optind; i < argc; i++) {
|
||||||
rv = update_pkg(&xh, argv[i]);
|
rv = update_pkg(&xh, argv[i]);
|
||||||
if (rv != 0)
|
if (rv != 0) {
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(rv);
|
exit(rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
rv = exec_transaction(&xh, maxcols, yes, drun);
|
rv = exec_transaction(&xh, maxcols, yes, drun);
|
||||||
} else if (!update) {
|
} else if (!update) {
|
||||||
/* Install target packages */
|
/* Install target packages */
|
||||||
for (i = optind; i < argc; i++) {
|
for (i = optind; i < argc; i++) {
|
||||||
rv = install_new_pkg(&xh, argv[i], reinstall);
|
rv = install_new_pkg(&xh, argv[i], reinstall);
|
||||||
if (rv != 0)
|
if (rv != 0) {
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(rv);
|
exit(rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
rv = exec_transaction(&xh, maxcols, yes, drun);
|
rv = exec_transaction(&xh, maxcols, yes, drun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(rv);
|
exit(rv);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2013 Juan Romero Pardines.
|
* Copyright (c) 2013-2014 Juan Romero Pardines.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -146,12 +146,17 @@ main(int argc, char **argv)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((rv = xbps_pkgdb_lock(&xh)) != 0) {
|
||||||
|
fprintf(stderr, "failed to lock pkgdb: %s\n", strerror(rv));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
if (update_format)
|
if (update_format)
|
||||||
convert_pkgdb_format(&xh);
|
convert_pkgdb_format(&xh);
|
||||||
else if (instmode) {
|
else if (instmode) {
|
||||||
if (argc == optind) {
|
if (argc == optind) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"xbps-pkgdb: missing PKGNAME argument\n");
|
"xbps-pkgdb: missing PKGNAME argument\n");
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
for (i = optind; i < argc; i++) {
|
for (i = optind; i < argc; i++) {
|
||||||
@ -160,6 +165,7 @@ main(int argc, char **argv)
|
|||||||
fprintf(stderr, "xbps-pkgdb: failed to "
|
fprintf(stderr, "xbps-pkgdb: failed to "
|
||||||
"change to %s mode to %s: %s\n",
|
"change to %s mode to %s: %s\n",
|
||||||
instmode, argv[i], strerror(rv));
|
instmode, argv[i], strerror(rv));
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,5 +180,6 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -350,8 +350,14 @@ main(int argc, char **argv)
|
|||||||
exit(rv);;
|
exit(rv);;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((rv = xbps_pkgdb_lock(&xh)) != 0) {
|
||||||
|
fprintf(stderr, "failed to lock pkgdb: %s\n", strerror(rv));
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
|
||||||
if (orphans) {
|
if (orphans) {
|
||||||
if ((rv = xbps_transaction_autoremove_pkgs(&xh)) != 0) {
|
if ((rv = xbps_transaction_autoremove_pkgs(&xh)) != 0) {
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
if (rv != ENOENT) {
|
if (rv != ENOENT) {
|
||||||
fprintf(stderr, "Failed to queue package "
|
fprintf(stderr, "Failed to queue package "
|
||||||
"orphans: %s\n", strerror(rv));
|
"orphans: %s\n", strerror(rv));
|
||||||
@ -370,11 +376,13 @@ main(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
reqby_force = true;
|
reqby_force = true;
|
||||||
}
|
}
|
||||||
if (reqby_force && !ignore_revdeps)
|
if (reqby_force && !ignore_revdeps) {
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
if (orphans || (argc > optind))
|
if (orphans || (argc > optind)) {
|
||||||
rv = exec_transaction(&xh, maxcols, yes, drun);
|
rv = exec_transaction(&xh, maxcols, yes, drun);
|
||||||
|
}
|
||||||
|
xbps_pkgdb_unlock(&xh);
|
||||||
exit(rv);
|
exit(rv);
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@
|
|||||||
*-
|
*-
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _XBPS_API_H_
|
#ifndef _XBPS_H_
|
||||||
#define _XBPS_API_H_
|
#define _XBPS_H_
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
#include <xbps/xbps_array.h>
|
#include <xbps/xbps_array.h>
|
||||||
#include <xbps/xbps_bool.h>
|
#include <xbps/xbps_bool.h>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
*
|
*
|
||||||
* This header documents the full API for the XBPS Library.
|
* This header documents the full API for the XBPS Library.
|
||||||
*/
|
*/
|
||||||
#define XBPS_API_VERSION "20140130"
|
#define XBPS_API_VERSION "20140223"
|
||||||
|
|
||||||
#ifndef XBPS_VERSION
|
#ifndef XBPS_VERSION
|
||||||
#define XBPS_VERSION "UNSET"
|
#define XBPS_VERSION "UNSET"
|
||||||
@ -475,6 +475,12 @@ struct xbps_handle {
|
|||||||
* stored in XBPS_META_PATH/XBPS_PKGDB.
|
* stored in XBPS_META_PATH/XBPS_PKGDB.
|
||||||
*/
|
*/
|
||||||
xbps_dictionary_t pkgdb;
|
xbps_dictionary_t pkgdb;
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*
|
||||||
|
* POSIX named semaphore associated with the pkgdb for writers.
|
||||||
|
*/
|
||||||
|
sem_t *pkgdb_sem;
|
||||||
/**
|
/**
|
||||||
* @var transd
|
* @var transd
|
||||||
*
|
*
|
||||||
@ -706,6 +712,25 @@ xbps_array_t xbps_find_pkg_obsoletes(struct xbps_handle *xhp,
|
|||||||
/** @addtogroup pkgdb */
|
/** @addtogroup pkgdb */
|
||||||
/*@{*/
|
/*@{*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the pkgdb to allow a write transaction.
|
||||||
|
*
|
||||||
|
* This routine should be called before a write transaction is the target:
|
||||||
|
* install, remove or update.
|
||||||
|
*
|
||||||
|
* @param[in] xhp The pointer to the xbps_handle struct.
|
||||||
|
* @return 0 on success, otherwise an errno value.
|
||||||
|
*/
|
||||||
|
int xbps_pkgdb_lock(struct xbps_handle *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks the pkgdb after a write transaction: the POSIX named semaphore
|
||||||
|
* is unlocked and unlinked.
|
||||||
|
*
|
||||||
|
* @param[in] xhp The pointer to the xbps_handle struct.
|
||||||
|
*/
|
||||||
|
void xbps_pkgdb_unlock(struct xbps_handle *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a function callback per a package dictionary registered
|
* Executes a function callback per a package dictionary registered
|
||||||
* in master package database (pkgdb) plist.
|
* in master package database (pkgdb) plist.
|
||||||
@ -1693,4 +1718,4 @@ char *xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !_XBPS_API_H_ */
|
#endif /* !_XBPS_H_ */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2010-2013 Juan Romero Pardines.
|
* Copyright (c) 2010-2014 Juan Romero Pardines.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
47
lib/pkgdb.c
47
lib/pkgdb.c
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2012-2013 Juan Romero Pardines.
|
* Copyright (c) 2012-2014 Juan Romero Pardines.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -28,6 +28,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
#include "xbps_api_impl.h"
|
#include "xbps_api_impl.h"
|
||||||
|
|
||||||
@ -54,6 +57,48 @@
|
|||||||
* data type is specified on its edge, i.e array, bool, integer, string,
|
* data type is specified on its edge, i.e array, bool, integer, string,
|
||||||
* dictionary.
|
* dictionary.
|
||||||
*/
|
*/
|
||||||
|
#define _PKGDB_SEMNAME "/libxbps-pkgdb"
|
||||||
|
int
|
||||||
|
xbps_pkgdb_lock(struct xbps_handle *xhp)
|
||||||
|
{
|
||||||
|
int rv = 0;
|
||||||
|
mode_t myumask;
|
||||||
|
/*
|
||||||
|
* Create/open the POSIX named semaphore.
|
||||||
|
*/
|
||||||
|
myumask = umask(0);
|
||||||
|
xhp->pkgdb_sem = sem_open(_PKGDB_SEMNAME, O_CREAT, 0660, 1);
|
||||||
|
umask(myumask);
|
||||||
|
|
||||||
|
if (xhp->pkgdb_sem == SEM_FAILED) {
|
||||||
|
rv = errno;
|
||||||
|
xbps_dbg_printf(xhp, "pkgdb: failed to create/open named "
|
||||||
|
"semaphore: %s\n", strerror(errno));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (sem_wait(xhp->pkgdb_sem) == -1) {
|
||||||
|
rv = errno;
|
||||||
|
xbps_dbg_printf(xhp, "pkgdb: failed to lock named semaphore: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xbps_pkgdb_unlock(struct xbps_handle *xhp)
|
||||||
|
{
|
||||||
|
/* Unlock semaphore, close and destroy it (if possible) */
|
||||||
|
if (xhp->pkgdb_sem == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sem_post(xhp->pkgdb_sem);
|
||||||
|
sem_close(xhp->pkgdb_sem);
|
||||||
|
sem_unlink(_PKGDB_SEMNAME);
|
||||||
|
xhp->pkgdb_sem = NULL;
|
||||||
|
}
|
||||||
|
#undef _PKGDB_SEMNAME
|
||||||
|
|
||||||
int HIDDEN
|
int HIDDEN
|
||||||
xbps_pkgdb_init(struct xbps_handle *xhp)
|
xbps_pkgdb_init(struct xbps_handle *xhp)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user