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:
Juan RP 2014-02-23 08:23:14 +01:00
parent bc2bada045
commit 4d1cdcac0c
9 changed files with 115 additions and 16 deletions

4
NEWS
View File

@ -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.

View File

@ -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
View File

@ -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>.

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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_ */

View File

@ -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

View File

@ -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)
{ {