summaryrefslogtreecommitdiffstats
path: root/ipaclient
diff options
context:
space:
mode:
authorChristian Heimes <cheimes@redhat.com>2017-02-28 10:38:07 +0100
committerMartin Basti <mbasti@redhat.com>2017-03-01 12:50:43 +0100
commit3be696c92f6948ea0ced9784920600b73703e414 (patch)
treef6da5bca52cbb743056778c36b47191007cde7e7 /ipaclient
parent332dbab1ff09eb719eb9e0a7a90bbf5b6e69ddc9 (diff)
downloadfreeipa-3be696c92f6948ea0ced9784920600b73703e414.tar.gz
freeipa-3be696c92f6948ea0ced9784920600b73703e414.tar.xz
freeipa-3be696c92f6948ea0ced9784920600b73703e414.zip
Drop in-memory copy of schema zip file
The schema cache used a BytesIO buffer to read/write schema cache before it got flushed to disk. Since the schema cache is now loaded in one go, the temporary buffer is no longer needed. File locking has been replaced with a temporary file and atomic rename. Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: David Kupka <dkupka@redhat.com>
Diffstat (limited to 'ipaclient')
-rw-r--r--ipaclient/remote_plugins/schema.py49
1 files changed, 18 insertions, 31 deletions
diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py
index 13bdee4ef..0cdce9d03 100644
--- a/ipaclient/remote_plugins/schema.py
+++ b/ipaclient/remote_plugins/schema.py
@@ -3,13 +3,11 @@
#
import collections
-import contextlib
import errno
-import fcntl
-import io
import json
import os
import sys
+import tempfile
import types
import zipfile
@@ -374,7 +372,6 @@ class Schema(object):
self._dict = {}
self._namespaces = {}
self._help = None
- self._file = six.BytesIO()
for ns in self.namespaces:
self._dict[ns] = {}
@@ -404,21 +401,6 @@ class Schema(object):
self.fingerprint = fingerprint
self.ttl = ttl
- @contextlib.contextmanager
- def _open(self, filename, mode):
- path = os.path.join(self._DIR, filename)
-
- with io.open(path, mode) as f:
- if mode.startswith('r'):
- fcntl.flock(f, fcntl.LOCK_SH)
- else:
- fcntl.flock(f, fcntl.LOCK_EX)
-
- try:
- yield f
- finally:
- fcntl.flock(f, fcntl.LOCK_UN)
-
def _fetch(self, client, ignore_cache=False):
if not client.isconnected():
client.connect(verbose=False)
@@ -454,13 +436,10 @@ class Schema(object):
return (fp, ttl,)
def _read_schema(self, fingerprint):
- self._file.truncate(0)
- with self._open(fingerprint, 'rb') as f:
- self._file.write(f.read())
-
# It's more efficient to read zip file members at once than to open
# the zip file a couple of times, see #6690.
- with zipfile.ZipFile(self._file, 'r') as schema:
+ filename = os.path.join(self._DIR, fingerprint)
+ with zipfile.ZipFile(filename, 'r') as schema:
for name in schema.namelist():
ns, _slash, key = name.partition('/')
if ns in self.namespaces:
@@ -502,8 +481,21 @@ class Schema(object):
if e.errno != errno.EEXIST:
raise
- self._file.truncate(0)
- with zipfile.ZipFile(self._file, 'w', zipfile.ZIP_DEFLATED) as schema:
+ with tempfile.NamedTemporaryFile('wb', prefix=fingerprint,
+ dir=self._DIR, delete=False) as f:
+ try:
+ self._write_schema_data(f)
+ f.flush()
+ os.fdatasync(f.fileno())
+ f.close()
+ except Exception:
+ os.unlink(f.name)
+ raise
+ else:
+ os.rename(f.name, os.path.join(self._DIR, fingerprint))
+
+ def _write_schema_data(self, fileobj):
+ with zipfile.ZipFile(fileobj, 'w', zipfile.ZIP_DEFLATED) as schema:
for key, value in self._dict.items():
if key in self.namespaces:
ns = value
@@ -519,11 +511,6 @@ class Schema(object):
json.dumps(self._generate_help(self._dict)).encode('utf-8')
)
- self._file.seek(0)
- with self._open(fingerprint, 'wb') as f:
- f.truncate(0)
- f.write(self._file.read())
-
def read_namespace_member(self, namespace, member):
value = self._dict[namespace][member]