summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCsaba Henk <csaba@gluster.com>2011-04-02 19:40:48 +0000
committerVijay Bellur <vijay@dev.gluster.com>2011-04-04 08:02:22 -0700
commite77c35248e8ce796bc5b108c10013089a0c65bde (patch)
tree10e7eda370a3bb9c35ed3f965e84c2063ca47195
parentcfb9c834f96dc57c47dac8d27da4266d0dab1f3f (diff)
syncdaemon: provide transactional semantics to config file writing
So updating the config file from multiple contexts won't mess it up. This prepares the next commit where we'll set options internaly (which lacks the serial nature of user actions). Signed-off-by: Csaba Henk <csaba@gluster.com> Signed-off-by: Vijay Bellur <vijay@dev.gluster.com> BUG: 2537 (gsync autorestart) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2537
-rw-r--r--xlators/features/marker/utils/syncdaemon/configinterface.py31
-rw-r--r--xlators/features/marker/utils/syncdaemon/syncdutils.py31
2 files changed, 49 insertions, 13 deletions
diff --git a/xlators/features/marker/utils/syncdaemon/configinterface.py b/xlators/features/marker/utils/syncdaemon/configinterface.py
index cda7da7ebf3..a1079d80394 100644
--- a/xlators/features/marker/utils/syncdaemon/configinterface.py
+++ b/xlators/features/marker/utils/syncdaemon/configinterface.py
@@ -109,19 +109,19 @@ class GConffile(object):
continue
print("%s: %s" % (k, v))
- def write(self):
- if not self.config.has_section(SECT_META):
- self.config.add_section(SECT_META)
- self.config.set(SECT_META, 'version', config_version)
- f = None
- try:
- f = open(self.path, 'wb')
+ def write(self, trfn, *a, **kw):
+ def mergeconf(f):
+ self.config = ConfigParser.RawConfigParser()
+ self.config.readfp(f)
+ def updateconf(f):
+ if not self.config.has_section(SECT_META):
+ self.config.add_section(SECT_META)
+ self.config.set(SECT_META, 'version', config_version)
+ trfn(*a, **kw)
self.config.write(f)
- finally:
- if f:
- f.close()
+ syncdutils.update_file(self.path, updateconf, mergeconf)
- def set(self, opt, val, rx=False):
+ def _set(self, opt, val, rx=False):
sect = self.section(rx)
if not self.config.has_section(sect):
self.config.add_section(sect)
@@ -130,11 +130,16 @@ class GConffile(object):
self.config.add_section(SECT_ORD)
self.config.set(SECT_ORD, sect, len(self.config._sections[SECT_ORD]))
self.config.set(sect, opt, val)
- self.write()
- def delete(self, opt, rx=False):
+ def set(self, *a, **kw):
+ self.write(self._set, *a, **kw)
+
+ def _delete(self, opt, rx=False):
sect = self.section(rx)
if not self.config.has_section(sect):
return
if self.config.remove_option(sect, opt):
self.write()
+
+ def delete(self, *a, **kw):
+ self.write(self._delete, *a, **kw)
diff --git a/xlators/features/marker/utils/syncdaemon/syncdutils.py b/xlators/features/marker/utils/syncdaemon/syncdutils.py
index 52dad8c5ff3..723ab8fb5fc 100644
--- a/xlators/features/marker/utils/syncdaemon/syncdutils.py
+++ b/xlators/features/marker/utils/syncdaemon/syncdutils.py
@@ -1,3 +1,5 @@
+import os
+import fcntl
try:
# py 3
from urllib import parse as urllib
@@ -9,3 +11,32 @@ def escape(s):
def unescape(s):
return urllib.unquote_plus(s)
+
+def update_file(path, updater, merger = lambda f: True):
+ """update a file in a transaction-like manner"""
+
+ fr = fw = None
+ try:
+ fd = os.open(path, os.O_CREAT|os.O_RDWR)
+ try:
+ fr = os.fdopen(fd, 'r+b')
+ except:
+ os.close(fd)
+ raise
+ fcntl.lockf(fr, fcntl.LOCK_EX)
+ merger(fr)
+
+ tmpp = path + '.tmp.' + str(os.getpid())
+ fd = os.open(tmpp, os.O_CREAT|os.O_EXCL|os.O_WRONLY)
+ try:
+ fw = os.fdopen(fd, 'wb', 0)
+ except:
+ os.close(fd)
+ raise
+ updater(fw)
+ os.fsync(fd)
+ os.rename(tmpp, path)
+ finally:
+ for fx in (fr, fw):
+ if fx:
+ fx.close()