[CalendarServer-changes] [6206] CalendarServer/trunk/txdav/base/propertystore

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 30 13:53:35 PDT 2010


Revision: 6206
          http://trac.macosforge.org/projects/calendarserver/changeset/6206
Author:   cdaboo at apple.com
Date:     2010-08-30 13:53:34 -0700 (Mon, 30 Aug 2010)
Log Message:
-----------
Do a single SQL query to read in all of a resource's properties and use a write-through cache.

Modified Paths:
--------------
    CalendarServer/trunk/txdav/base/propertystore/sql.py
    CalendarServer/trunk/txdav/base/propertystore/test/base.py
    CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py

Modified: CalendarServer/trunk/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/sql.py	2010-08-30 19:17:50 UTC (rev 6205)
+++ CalendarServer/trunk/txdav/base/propertystore/sql.py	2010-08-30 20:53:34 UTC (rev 6206)
@@ -35,47 +35,78 @@
         self._txn = txn
         self._resourceID = resourceID
 
+    @property
+    def _cached(self):
+        
+        if not hasattr(self, "_cached_properties"):
+            self._cached_properties = {}
+            rows = self._txn.execSQL(
+                """
+                select NAME, VIEWER_UID, VALUE from RESOURCE_PROPERTY
+                where RESOURCE_ID = %s
+                """,
+                [self._resourceID]
+            )
+            for name, uid, value in rows:
+                self._cached_properties[(name, uid)] = value
+        
+        return self._cached_properties
 
     def _getitem_uid(self, key, uid):
         validKey(key)
-        rows = self._txn.execSQL(
-            "select VALUE from RESOURCE_PROPERTY where "
-            "RESOURCE_ID = %s and NAME = %s and VIEWER_UID = %s",
-            [self._resourceID, key.toString(), uid]
-        )
-        if not rows:
+        
+        try:
+            value = self._cached[(key.toString(), uid)]
+        except KeyError:
             raise KeyError(key)
-        return WebDAVDocument.fromString(rows[0][0]).root_element
 
+        return WebDAVDocument.fromString(value).root_element
 
+
     def _setitem_uid(self, key, value, uid):
         validKey(key)
-        try:
-            self._delitem_uid(key, uid)
-        except KeyError:
-            pass
-        self._txn.execSQL(
-            "insert into RESOURCE_PROPERTY "
-            "(RESOURCE_ID, NAME, VALUE, VIEWER_UID) values (%s, %s, %s, %s)",
-            [self._resourceID, key.toString(), value.toxml(), uid]
-        )
 
+        key_str = key.toString()
+        value_str = value.toxml()
 
+        if (key_str, uid) in self._cached:
+            self._txn.execSQL(
+                """
+                update RESOURCE_PROPERTY
+                set VALUE = %s
+                where RESOURCE_ID = %s and NAME = %s and VIEWER_UID = %s
+                """,
+                [value_str, self._resourceID, key_str, uid]
+            )
+        else:        
+            self._txn.execSQL(
+                """
+                insert into RESOURCE_PROPERTY
+                (RESOURCE_ID, NAME, VALUE, VIEWER_UID)
+                values (%s, %s, %s, %s)
+                """,
+                [self._resourceID, key_str, value_str, uid]
+            )
+        self._cached[(key_str, uid)] = value_str
+
+
     def _delitem_uid(self, key, uid):
         validKey(key)
+
+        key_str = key.toString()
+        del self._cached[(key_str, uid)]
         self._txn.execSQL(
-            "delete from RESOURCE_PROPERTY where VIEWER_UID = %s"
-            "and RESOURCE_ID = %s AND NAME = %s",
-            [uid, self._resourceID, key.toString()],
+            """
+            delete from RESOURCE_PROPERTY
+            where RESOURCE_ID = %s and NAME = %s and VIEWER_UID = %s
+            """,
+            [self._resourceID, key_str, uid],
             raiseOnZeroRowCount=lambda:KeyError(key)
         )
             
 
     def _keys_uid(self, uid):
-        rows = self._txn.execSQL(
-            "select NAME from RESOURCE_PROPERTY where "
-            "VIEWER_UID = %s and RESOURCE_ID = %s",
-            [uid, self._resourceID]
-        )
-        for row in rows:
-            yield PropertyName.fromString(row[0])
+
+        for cachedKey, cachedUID in self._cached.keys():
+            if cachedUID == uid:
+                yield PropertyName.fromString(cachedKey)

Modified: CalendarServer/trunk/txdav/base/propertystore/test/base.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/base.py	2010-08-30 19:17:50 UTC (rev 6205)
+++ CalendarServer/trunk/txdav/base/propertystore/test/base.py	2010-08-30 20:53:34 UTC (rev 6206)
@@ -57,184 +57,175 @@
     def test_set_get_contains(self):
         
         self._preTest()
-        store = self.propertyStore
 
         name = propertyName("test")
         value = propertyValue("Hello, World!")
 
         # Test with commit after change
-        store[name] = value
-        self._changed(store)
-        self.assertEquals(store.get(name, None), value)
-        self.failUnless(name in store)
+        self.propertyStore[name] = value
+        self._changed(self.propertyStore)
+        self.assertEquals(self.propertyStore.get(name, None), value)
+        self.failUnless(name in self.propertyStore)
 
         # Test without commit after change
         value = propertyValue("Hello, Universe!")
-        store[name] = value
-        self.assertEquals(store.get(name, None), value)
-        self.failUnless(name in store)
+        self.propertyStore[name] = value
+        self.assertEquals(self.propertyStore.get(name, None), value)
+        self.failUnless(name in self.propertyStore)
 
     def test_delete_get_contains(self):
 
         self._preTest()
-        store = self.propertyStore
 
         # Test with commit after change
         name = propertyName("test")
         value = propertyValue("Hello, World!")
 
-        store[name] = value
-        self._changed(store)
+        self.propertyStore[name] = value
+        self._changed(self.propertyStore)
 
-        del store[name]
-        self._changed(store)
+        del self.propertyStore[name]
+        self._changed(self.propertyStore)
 
-        self.assertEquals(store.get(name, None), None)
-        self.failIf(name in store)
+        self.assertEquals(self.propertyStore.get(name, None), None)
+        self.failIf(name in self.propertyStore)
 
         # Test without commit after change
         name = propertyName("test")
         value = propertyValue("Hello, Universe!")
 
-        store[name] = value
-        self._changed(store)
+        self.propertyStore[name] = value
+        self._changed(self.propertyStore)
 
-        del store[name]
+        del self.propertyStore[name]
 
-        self.assertEquals(store.get(name, None), None)
-        self.failIf(name in store)
+        self.assertEquals(self.propertyStore.get(name, None), None)
+        self.failIf(name in self.propertyStore)
 
     def test_peruser(self):
 
         self._preTest()
-        store1 = self.propertyStore1
-        store2 = self.propertyStore2
 
         name = propertyName("test")
         value1 = propertyValue("Hello, World1!")
         value2 = propertyValue("Hello, World2!")
 
-        store1[name] = value1
-        self._changed(store1)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), None)
-        self.failUnless(name in store1)
-        self.failIf(name in store2)
+        self.propertyStore1[name] = value1
+        self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failUnless(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
         
-        store2[name] = value2
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), value2)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        self.propertyStore2[name] = value2
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value2)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        del store2[name]
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), None)
-        self.failUnless(name in store1)
-        self.failIf(name in store2)
+        del self.propertyStore2[name]
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failUnless(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
         
-        del store1[name]
-        self._changed(store1)
-        self.assertEquals(store1.get(name, None), None)
-        self.assertEquals(store2.get(name, None), None)
-        self.failIf(name in store1)
-        self.failIf(name in store2)
+        del self.propertyStore1[name]
+        self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), None)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failIf(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
         
     def test_peruser_shadow(self):
 
         self._preTest()
-        store1 = self.propertyStore1
-        store2 = self.propertyStore2
 
         name = propertyName("shadow")
 
-        store1.setSpecialProperties((name,), ())
-        store2.setSpecialProperties((name,), ())
+        self.propertyStore1.setSpecialProperties((name,), ())
+        self.propertyStore2.setSpecialProperties((name,), ())
 
         value1 = propertyValue("Hello, World1!")
         value2 = propertyValue("Hello, World2!")
 
-        store1[name] = value1
-        self._changed(store1)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), value1)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        self.propertyStore1[name] = value1
+        self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value1)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        store2[name] = value2
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), value2)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        self.propertyStore2[name] = value2
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value2)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        del store2[name]
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), value1)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        del self.propertyStore2[name]
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value1)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        del store1[name]
-        self._changed(store1)
-        self.assertEquals(store1.get(name, None), None)
-        self.assertEquals(store2.get(name, None), None)
-        self.failIf(name in store1)
-        self.failIf(name in store2)
+        del self.propertyStore1[name]
+        self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), None)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failIf(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
 
 
     def test_peruser_global(self):
 
         self._preTest()
-        store1 = self.propertyStore1
-        store2 = self.propertyStore2
 
         name = propertyName("global")
 
-        store1.setSpecialProperties((), (name,))
-        store2.setSpecialProperties((), (name,))
+        self.propertyStore1.setSpecialProperties((), (name,))
+        self.propertyStore2.setSpecialProperties((), (name,))
 
         value1 = propertyValue("Hello, World1!")
         value2 = propertyValue("Hello, World2!")
 
-        store1[name] = value1
-        self._changed(store1)
-        self.assertEquals(store1.get(name, None), value1)
-        self.assertEquals(store2.get(name, None), value1)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        self.propertyStore1[name] = value1
+        self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value1)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        store2[name] = value2
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), value2)
-        self.assertEquals(store2.get(name, None), value2)
-        self.failUnless(name in store1)
-        self.failUnless(name in store2)
+        self.propertyStore2[name] = value2
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value2)
+        self.assertEquals(self.propertyStore2.get(name, None), value2)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
         
-        del store2[name]
-        self._changed(store2)
-        self.assertEquals(store1.get(name, None), None)
-        self.assertEquals(store2.get(name, None), None)
-        self.failIf(name in store1)
-        self.failIf(name in store2)
+        del self.propertyStore2[name]
+        self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), None)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failIf(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
         
 
     def test_iteration(self):
 
         self._preTest()
-        store = self.propertyStore
 
         value = propertyValue("Hello, World!")
 
         names = set(propertyName(str(i)) for i in (1,2,3,4))
 
         for name in names:
-            store[name] = value
+            self.propertyStore[name] = value
 
-        self.assertEquals(set(store.keys()), names)
-        self.assertEquals(len(store), len(names))
+        self.assertEquals(set(self.propertyStore.keys()), names)
+        self.assertEquals(len(self.propertyStore), len(names))
 
     def test_delete_none(self):
 
@@ -247,19 +238,18 @@
     def test_keyInPropertyName(self):
 
         self._preTest()
-        store = self.propertyStore
 
         def doGet():
-            store["xyzzy"]
+            self.propertyStore["xyzzy"]
 
         def doSet():
-            store["xyzzy"] = propertyValue("Hello, World!")
+            self.propertyStore["xyzzy"] = propertyValue("Hello, World!")
 
         def doDelete():
-            del store["xyzzy"]
+            del self.propertyStore["xyzzy"]
 
         def doContains():
-            return "xyzzy" in store
+            return "xyzzy" in self.propertyStore
 
         self.assertRaises(TypeError, doGet)
         self.assertRaises(TypeError, doSet)
@@ -269,7 +259,6 @@
     def test_flush(self):
 
         self._preTest()
-        store = self.propertyStore
 
         name = propertyName("test")
         value = propertyValue("Hello, World!")
@@ -277,39 +266,38 @@
         #
         # Set value flushes correctly
         #
-        store[name] = value
+        self.propertyStore[name] = value
 
-        self._changed(store)
-        self._abort(store)
+        self._changed(self.propertyStore)
+        self._abort(self.propertyStore)
 
-        self.assertEquals(store.get(name, None), value)
-        self.assertEquals(len(store), 1)
+        self.assertEquals(self.propertyStore.get(name, None), value)
+        self.assertEquals(len(self.propertyStore), 1)
 
         #
         # Deleted value flushes correctly
         #
-        del store[name]
+        del self.propertyStore[name]
 
-        self._changed(store)
-        self._abort(store)
+        self._changed(self.propertyStore)
+        self._abort(self.propertyStore)
 
-        self.assertEquals(store.get(name, None), None)
-        self.assertEquals(len(store), 0)
+        self.assertEquals(self.propertyStore.get(name, None), None)
+        self.assertEquals(len(self.propertyStore), 0)
 
     def test_abort(self):
 
         self._preTest()
-        store = self.propertyStore
 
         name = propertyName("test")
         value = propertyValue("Hello, World!")
 
-        store[name] = value
+        self.propertyStore[name] = value
 
-        self._abort(store)
+        self._abort(self.propertyStore)
 
-        self.assertEquals(store.get(name, None), None)
-        self.assertEquals(len(store), 0)
+        self.assertEquals(self.propertyStore.get(name, None), None)
+        self.assertEquals(len(self.propertyStore), 0)
 
 
 def propertyName(name):

Modified: CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2010-08-30 19:17:50 UTC (rev 6205)
+++ CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2010-08-30 20:53:34 UTC (rev 6206)
@@ -59,18 +59,40 @@
             self._txn.commit()
             delattr(self, "_txn")
         self._txn = self.store.newTransaction()
-        self.propertyStore1._txn = self._txn
-        self.propertyStore2._txn = self._txn
+        
+        store = self.propertyStore1
+        self.propertyStore = self.propertyStore1 = PropertyStore(
+            "user01", self._txn, 1
+        )
+        self.propertyStore1._shadowableKeys = store._shadowableKeys
+        self.propertyStore1._globalKeys = store._globalKeys
 
+        store = self.propertyStore2
+        self.propertyStore2 = PropertyStore("user01", self._txn, 1)
+        self.propertyStore2._setPerUserUID("user02")
+        self.propertyStore2._shadowableKeys = store._shadowableKeys
+        self.propertyStore2._globalKeys = store._globalKeys
+
     def _abort(self, store):
         if hasattr(self, "_txn"):
             self._txn.abort()
             delattr(self, "_txn")
 
         self._txn = self.store.newTransaction()
-        self.propertyStore1._txn = self._txn
-        self.propertyStore2._txn = self._txn
 
+        store = self.propertyStore1
+        self.propertyStore = self.propertyStore1 = PropertyStore(
+            "user01", self._txn, 1
+        )
+        self.propertyStore1._shadowableKeys = store._shadowableKeys
+        self.propertyStore1._globalKeys = store._globalKeys
+
+        store = self.propertyStore2
+        self.propertyStore2 = PropertyStore("user01", self._txn, 1)
+        self.propertyStore2._setPerUserUID("user02")
+        self.propertyStore2._shadowableKeys = store._shadowableKeys
+        self.propertyStore2._globalKeys = store._globalKeys
+
     @inlineCallbacks
     def setUp(self):
         self.notifierFactory = StubNotifierFactory()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100830/0f65659f/attachment-0001.html>


More information about the calendarserver-changes mailing list