403b09
From 1aa300c53f070436888150ae582dad23cddac03b Mon Sep 17 00:00:00 2001
403b09
From: David Kupka <dkupka@redhat.com>
403b09
Date: Mon, 15 Aug 2016 08:01:59 +0200
403b09
Subject: [PATCH] schema cache: Store API schema cache in memory
403b09
403b09
Read whole cache into memory and keep it there for lifetime of api
403b09
object. This removes the need to repetitively open/close the cache and
403b09
speeds up every access to it.
403b09
403b09
https://fedorahosted.org/freeipa/ticket/6048
403b09
403b09
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
403b09
---
403b09
 ipaclient/remote_plugins/schema.py | 51 +++++++++++++++++++++-----------------
403b09
 1 file changed, 28 insertions(+), 23 deletions(-)
403b09
403b09
diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py
403b09
index aadc891750782b0961bc46989e3693d1d3ed0ecb..2fc6cce3eca392447cd4230216900116002934f4 100644
403b09
--- a/ipaclient/remote_plugins/schema.py
403b09
+++ b/ipaclient/remote_plugins/schema.py
403b09
@@ -3,6 +3,7 @@
403b09
 #
403b09
 
403b09
 import collections
403b09
+import contextlib
403b09
 import errno
403b09
 import fcntl
403b09
 import json
403b09
@@ -315,24 +316,6 @@ class _SchemaObjectPlugin(_SchemaPlugin):
403b09
     schema_key = 'classes'
403b09
 
403b09
 
403b09
-class _LockedZipFile(zipfile.ZipFile):
403b09
-    """ Add locking to zipfile.ZipFile
403b09
-    Shared lock is used with read mode, exclusive with write mode.
403b09
-    """
403b09
-    def __enter__(self):
403b09
-        if 'r' in self.mode:
403b09
-            fcntl.flock(self.fp, fcntl.LOCK_SH)
403b09
-        elif 'w' in self.mode or 'a' in self.mode:
403b09
-            fcntl.flock(self.fp, fcntl.LOCK_EX)
403b09
-
403b09
-        return super(_LockedZipFile, self).__enter__()
403b09
-
403b09
-    def __exit__(self, type_, value, traceback):
403b09
-        fcntl.flock(self.fp, fcntl.LOCK_UN)
403b09
-
403b09
-        return super(_LockedZipFile, self).__exit__(type_, value, traceback)
403b09
-
403b09
-
403b09
 class _SchemaNameSpace(collections.Mapping):
403b09
 
403b09
     def __init__(self, schema, name):
403b09
@@ -450,6 +433,7 @@ class Schema(object):
403b09
         self._dict = {}
403b09
         self._namespaces = {}
403b09
         self._help = None
403b09
+        self._file = six.StringIO()
403b09
 
403b09
         for ns in self.namespaces:
403b09
             self._dict[ns] = {}
403b09
@@ -486,9 +470,20 @@ class Schema(object):
403b09
             except AttributeError:
403b09
                 pass
403b09
 
403b09
-    def _open_schema(self, filename, mode):
403b09
+    @contextlib.contextmanager
403b09
+    def _open(self, filename, mode):
403b09
         path = os.path.join(self._DIR, filename)
403b09
-        return _LockedZipFile(path, mode)
403b09
+
403b09
+        with open(path, mode) as f:
403b09
+            if mode.startswith('r'):
403b09
+                fcntl.flock(f, fcntl.LOCK_SH)
403b09
+            else:
403b09
+                fcntl.flock(f, fcntl.LOCK_EX)
403b09
+
403b09
+            try:
403b09
+                yield f
403b09
+            finally:
403b09
+                fcntl.flock(f, fcntl.LOCK_UN)
403b09
 
403b09
     def _fetch(self, client):
403b09
         if not client.isconnected():
403b09
@@ -523,7 +518,11 @@ class Schema(object):
403b09
         self._expiration = ttl + time.time()
403b09
 
403b09
     def _read_schema(self):
403b09
-        with self._open_schema(self._fingerprint, 'r') as schema:
403b09
+        self._file.truncate(0)
403b09
+        with self._open(self._fingerprint, 'r') as f:
403b09
+            self._file.write(f.read())
403b09
+
403b09
+        with zipfile.ZipFile(self._file, 'r') as schema:
403b09
             self._dict['fingerprint'] = self._fingerprint
403b09
 
403b09
             for name in schema.namelist():
403b09
@@ -566,7 +565,8 @@ class Schema(object):
403b09
                 logger.warning("Failed to write schema: {}".format(e))
403b09
                 return
403b09
 
403b09
-        with self._open_schema(self._fingerprint, 'w') as schema:
403b09
+        self._file.truncate(0)
403b09
+        with zipfile.ZipFile(self._file, 'w', zipfile.ZIP_DEFLATED) as schema:
403b09
             for key, value in self._dict.items():
403b09
                 if key in self.namespaces:
403b09
                     ns = value
403b09
@@ -579,8 +579,13 @@ class Schema(object):
403b09
             schema.writestr('_help',
403b09
                             json.dumps(self._generate_help(self._dict)))
403b09
 
403b09
+        self._file.seek(0)
403b09
+        with self._open(self._fingerprint, 'w') as f:
403b09
+            f.truncate(0)
403b09
+            f.write(self._file.read())
403b09
+
403b09
     def _read(self, path):
403b09
-        with self._open_schema(self._fingerprint, 'r') as zf:
403b09
+        with zipfile.ZipFile(self._file, 'r') as zf:
403b09
             return json.loads(zf.read(path))
403b09
 
403b09
     def read_namespace_member(self, namespace, member):
403b09
-- 
403b09
2.7.4
403b09