[dconf] keyfile: add advisory locking
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dconf] keyfile: add advisory locking
- Date: Sat, 12 Jan 2013 03:01:31 +0000 (UTC)
commit bdd4dc68f54f9700a9b7c13cf035b0deba03612c
Author: Ryan Lortie <desrt desrt ca>
Date: Fri Jan 11 19:23:18 2013 -0500
keyfile: add advisory locking
Use fcntl() on a lockfile when accessing a keyfile.
Now reading the keyfile, notifying local processes of changes in it,
applying changes from local request and rewriting it is all done under a
single acquire of the lock. This effectively means that concurrent
changes made to the database across several machines sharing a home
directory over NFS will be seen by all machines as having occurred in
the same order (decided by who won the race to the lock).
service/dconf-keyfile-writer.c | 64 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 62 insertions(+), 2 deletions(-)
---
diff --git a/service/dconf-keyfile-writer.c b/service/dconf-keyfile-writer.c
index 2845c65..e41d0fe 100644
--- a/service/dconf-keyfile-writer.c
+++ b/service/dconf-keyfile-writer.c
@@ -23,6 +23,9 @@
#include "dconf-writer.h"
#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
typedef DConfWriterClass DConfKeyfileWriterClass;
@@ -30,6 +33,8 @@ typedef struct
{
DConfWriter parent_instance;
gchar *filename;
+ gchar *lock_filename;
+ gint lock_fd;
GFileMonitor *monitor;
guint scheduled_update;
gchar *contents;
@@ -159,6 +164,7 @@ dconf_keyfile_writer_begin (DConfWriter *writer,
filename_base = g_build_filename (g_get_user_config_dir (), "dconf", dconf_writer_get_name (writer), NULL);
kfw->filename = g_strconcat (filename_base, ".txt", NULL);
+ kfw->lock_filename = g_strconcat (kfw->filename, "-lock", NULL);
g_free (filename_base);
file = g_file_new_for_path (kfw->filename);
@@ -170,6 +176,55 @@ dconf_keyfile_writer_begin (DConfWriter *writer,
g_clear_pointer (&kfw->contents, g_free);
+ kfw->lock_fd = open (kfw->lock_filename, O_RDWR | O_CREAT, 0666);
+ if (kfw->lock_fd == -1)
+ {
+ gchar *dirname;
+
+ /* Maybe it failed because the directory doesn't exist. Try
+ * again, after mkdir().
+ */
+ dirname = g_path_get_dirname (kfw->lock_filename);
+ g_mkdir_with_parents (dirname, 0777);
+ g_free (dirname);
+
+ kfw->lock_fd = open (kfw->lock_filename, O_RDWR | O_CREAT, 0666);
+ if (kfw->lock_fd == -1)
+ {
+ gint saved_errno = errno;
+
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+ "%s: %s", kfw->lock_filename, g_strerror (saved_errno));
+ return FALSE;
+ }
+ }
+
+ while (TRUE)
+ {
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = 0;
+ lock.l_start = 0;
+ lock.l_len = 0; /* lock all bytes */
+
+ if (fcntl (kfw->lock_fd, F_SETLKW, &lock) == 0)
+ break;
+
+ if (errno != EINTR)
+ {
+ gint saved_errno = errno;
+
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+ "%s: unable to fcntl(F_SETLKW): %s", kfw->lock_filename, g_strerror (saved_errno));
+ close (kfw->lock_fd);
+ kfw->lock_fd = -1;
+ return FALSE;
+ }
+
+ /* it was EINTR. loop again. */
+ }
+
if (!g_file_get_contents (kfw->filename, &kfw->contents, NULL, &local_error))
{
if (!g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
@@ -394,6 +449,8 @@ dconf_keyfile_writer_end (DConfWriter *writer)
g_clear_pointer (&kfw->keyfile, g_key_file_free);
g_clear_pointer (&kfw->contents, g_free);
+ close (kfw->lock_fd);
+ kfw->lock_fd = -1;
}
static gboolean
@@ -421,15 +478,18 @@ dconf_keyfile_writer_finalize (GObject *object)
g_source_remove (kfw->scheduled_update);
g_clear_object (&kfw->monitor);
+ g_free (kfw->lock_filename);
g_free (kfw->filename);
G_OBJECT_CLASS (dconf_keyfile_writer_parent_class)->finalize (object);
}
static void
-dconf_keyfile_writer_init (DConfKeyfileWriter *writer)
+dconf_keyfile_writer_init (DConfKeyfileWriter *kfw)
{
- dconf_writer_set_basepath (DCONF_WRITER (writer), "keyfile");
+ dconf_writer_set_basepath (DCONF_WRITER (kfw), "keyfile");
+
+ kfw->lock_fd = -1;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]