From 2ecc04e00288fbf6beffb065d20aac9c491e59ce Mon Sep 17 00:00:00 2001 From: "Michael J. Rubinsky" Date: Fri, 12 Nov 2010 13:57:19 -0500 Subject: [PATCH] First stab at caching the Horde_Share listcache, instead of the entire horde_share object. --- ansel/lib/Gallery.php | 18 +++- framework/Core/lib/Horde/Core/Factory/Share.php | 55 +---------- .../Core/lib/Horde/Core/Factory/ShareBase.php | 71 +++++++++++++ framework/Core/lib/Horde/Core/Share/Driver.php | 47 +-------- .../Core/lib/Horde/Core/Share/FactoryCallback.php | 28 ++++++ framework/Core/package.xml | 10 +- framework/Share/lib/Horde/Share.php | 51 +++++++--- framework/Share/lib/Horde/Share/Datatree.php | 16 +-- framework/Share/lib/Horde/Share/Kolab.php | 85 +--------------- framework/Share/lib/Horde/Share/Object.php | 36 ++++--- .../Share/lib/Horde/Share/Object/Datatree.php | 2 +- framework/Share/lib/Horde/Share/Object/Kolab.php | 23 ++--- framework/Share/lib/Horde/Share/Object/Sql.php | 21 ++-- .../lib/Horde/Share/Object/Sql/Hierarchical.php | 14 +-- framework/Share/lib/Horde/Share/Sql.php | 110 +++++---------------- .../Share/lib/Horde/Share/Sql/Hierarchical.php | 43 +++----- framework/Share/package.xml | 11 ++- 17 files changed, 279 insertions(+), 362 deletions(-) create mode 100644 framework/Core/lib/Horde/Core/Factory/ShareBase.php create mode 100644 framework/Core/lib/Horde/Core/Share/FactoryCallback.php diff --git a/ansel/lib/Gallery.php b/ansel/lib/Gallery.php index a214ec1a9..fa84e8752 100644 --- a/ansel/lib/Gallery.php +++ b/ansel/lib/Gallery.php @@ -11,7 +11,7 @@ * @author Michael J. Rubinsky * @package Ansel */ -class Ansel_Gallery extends Horde_Share_Object_Sql_Hierarchical +class Ansel_Gallery extends Horde_Share_Object_Sql_Hierarchical implements Serializable { /** * The gallery mode helper @@ -965,11 +965,25 @@ class Ansel_Gallery extends Horde_Share_Object_Sql_Hierarchical { return $this->_modeHelper->getGalleryCrumbData(); } +/** + * Serialize this object. + * + * @return string The serialized data. + */ + public function serialize() + { + $data = array( + self::VERSION, + $this->data, + $this->_shareCallback, + ); + + return serialize($data); + } public function unserialize($data) { parent::unserialize($data); - $GLOBALS['injector']->getInstance('Ansel_Injector_Factory_Storage')->create()->shares->initShareObject($this); $this->_setModeHelper($this->get('view_mode')); } } diff --git a/framework/Core/lib/Horde/Core/Factory/Share.php b/framework/Core/lib/Horde/Core/Factory/Share.php index dcff45c8e..e3fb7a61f 100644 --- a/framework/Core/lib/Horde/Core/Factory/Share.php +++ b/framework/Core/lib/Horde/Core/Factory/Share.php @@ -22,13 +22,6 @@ class Horde_Core_Factory_Share { /** - * Instances. - * - * @var array - */ - private $_instances = array(); - - /** * The injector. * * @var Horde_Injector @@ -53,56 +46,12 @@ class Horde_Core_Factory_Share * @param string $driver The share driver. Either empty (use default * driver from $conf) or a driver name. * - * @return Horde_Share The Horde_Share instance. + * @return Horde_Core_Share_Driver The Horde_Share instance. * @throws Horde_Exception */ public function create($app = null, $driver = null) { - if (empty($driver)) { - $driver = $GLOBALS['conf']['share']['driver']; - } - if (empty($app)) { - $app = $this->_injector->getInstance('Horde_Registry')->getApp(); - } - - $sig = $app . '_' . $driver; - - if (isset($this->_instances[$sig])) { - return $this->_instances[$sig]; - } - - if (!empty($GLOBALS['conf']['share']['cache'])) { - $cache_sig = 'horde_share/' . $app . '/' . $driver . '1'; - $ob = $GLOBALS['session']->retrieve($cache_sig); - } - - if (empty($ob)) { - $class = 'Horde_Share_' . ucfirst(basename($driver)); - if (!class_exists($class)) { - throw new Horde_Exception(sprintf(Horde_Core_Translation::t("\"%s\" share driver not found."), $driver)); - } - $sob = new $class($app, $GLOBALS['registry']->getAuth(), $this->_injector->getInstance('Horde_Perms'), $this->_injector->getInstance('Horde_Group')); - $ob = new Horde_Core_Share_Driver($sob); - } - - if (!empty($GLOBALS['conf']['share']['cache'])) { - register_shutdown_function(array($this, 'shutdown'), $cache_sig, $ob); - } - - $this->_instances[$sig] = $ob; - - return $ob; - } - - /** - * Shutdown function. - * - * @param string $sig Cache signature. - * @param Horde_Share $share Horde_Share object to cache. - */ - public function shutdown($sig, $share) - { - $GLOBALS['session']->store($share, false, $sig); + return new Horde_Core_Share_Driver($this->_injector->getInstance('Horde_Core_Factory_ShareBase')->create($app, $driver)); } } diff --git a/framework/Core/lib/Horde/Core/Factory/ShareBase.php b/framework/Core/lib/Horde/Core/Factory/ShareBase.php new file mode 100644 index 000000000..1f21ef458 --- /dev/null +++ b/framework/Core/lib/Horde/Core/Factory/ShareBase.php @@ -0,0 +1,71 @@ + + */ + +/** + * A Horde_Injector:: based Horde_Share:: factory. + * + * Copyright 2010 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Horde + * @package Core + * @author Michael J. Rubinsky + */ +class Horde_Core_Factory_ShareBase +{ + public function create($app = null, $driver = null) + { + if (empty($driver)) { + $driver = $GLOBALS['conf']['share']['driver']; + } + if (empty($app)) { + $app = $GLOBALS['injector']->getInstance('Horde_Registry')->getApp(); + } + + $sig = $app . '_' . $driver; + if (isset($this->_instances[$sig])) { + return $this->_instances[$sig]; + } + + $class = 'Horde_Share_' . ucfirst(basename($driver)); + if (!class_exists($class)) { + throw new Horde_Exception(sprintf(Horde_Core_Translation::t("\"%s\" share driver not found."), $driver)); + } + + $ob = new $class($app, $GLOBALS['registry']->getAuth(), $GLOBALS['injector']->getInstance('Horde_Perms'), $GLOBALS['injector']->getInstance('Horde_Group')); + $cb = new Horde_Core_Share_FactoryCallback($app, $driver); + $ob->setShareCallback(array($cb, 'create')); + if (!empty($GLOBALS['conf']['share']['cache'])) { + $cache_sig = 'horde_share/' . $app . '/' . $driver; + $listCache = $GLOBALS['session']->retrieve($cache_sig); + $ob->setListCache($listCache); + } + + if (!empty($GLOBALS['conf']['share']['cache'])) { + register_shutdown_function(array($this, 'shutdown'), $cache_sig, $ob); + } + $this->_instances[$sig] = $ob; + + return $ob; + } + + /** + * Shutdown function. + * + * @param string $sig Cache signature. + * @param Horde_Share $share Horde_Share object to cache. + */ + public function shutdown($sig, $share) + { + $GLOBALS['session']->store($share->getListCache(), false, $sig); + } + +} \ No newline at end of file diff --git a/framework/Core/lib/Horde/Core/Share/Driver.php b/framework/Core/lib/Horde/Core/Share/Driver.php index 64b095ebd..9dbefddeb 100644 --- a/framework/Core/lib/Horde/Core/Share/Driver.php +++ b/framework/Core/lib/Horde/Core/Share/Driver.php @@ -1,7 +1,6 @@ _share); - - return serialize($data); - } - - /** - * Reconstructs object from serialized properties. - * - * @param $serialized - */ - public function unserialize($data) - { - // Rebuild the object - $data = @unserialize($data); - if (!is_array($data) || - !isset($data[0]) || - ($data[0] != self::VERSION)) { - throw new Exception('Cache version change'); - } - $this->_share = $data[1]; - - // Set the storage adapter. - $this->_share->setStorage($GLOBALS['injector']->getInstance($this->_storageMap[get_class($this->_share)])); - - // Call the init hook - try { - Horde::callHook('share_init', array($this, $this->_share->getApp())); - } catch (Horde_Exception_HookNotSet $e) {} - } - - /** * Lock an item belonging to a share, or an entire share itself. * * @param Horde_Lock $locks The lock object diff --git a/framework/Core/lib/Horde/Core/Share/FactoryCallback.php b/framework/Core/lib/Horde/Core/Share/FactoryCallback.php new file mode 100644 index 000000000..48e092361 --- /dev/null +++ b/framework/Core/lib/Horde/Core/Share/FactoryCallback.php @@ -0,0 +1,28 @@ +_app = $app; + $this->_driver = $driver; + } + + public function create() + { + return $GLOBALS['injector']->getInstance('Horde_Core_Factory_ShareBase')->create($this->_app, $this->_driver); + } + +} diff --git a/framework/Core/package.xml b/framework/Core/package.xml index 176aac2ba..17f49b063 100644 --- a/framework/Core/package.xml +++ b/framework/Core/package.xml @@ -23,8 +23,8 @@ Application Framework. slusarz@horde.org yes - 2010-11-04 - + 2010-11-12 + 0.1.0 0.1.0 @@ -161,6 +161,7 @@ Application Framework. + @@ -205,6 +206,7 @@ Application Framework. + @@ -776,6 +778,7 @@ Application Framework. + @@ -796,6 +799,7 @@ Application Framework. + @@ -945,7 +949,7 @@ Initial packaging beta beta - 2010-11-04 + 2010-11-12 LGPL * Add Horde_Session. diff --git a/framework/Share/lib/Horde/Share.php b/framework/Share/lib/Horde/Share.php index 2fa527300..8d3c559ba 100644 --- a/framework/Share/lib/Horde/Share.php +++ b/framework/Share/lib/Horde/Share.php @@ -92,6 +92,8 @@ class Horde_Share */ protected $_groups; + protected $_shareCallback; + /** * Configured callbacks. We currently support: *
@@ -130,15 +132,24 @@ class Horde_Share
     }
 
     /**
-     * (re)connect the share object to this share driver. Userful for when
-     * share objects are unserialized from a cache separate from the share
-     * driver.
+     * (re)connect the share object to this share driver.
      *
      * @param Horde_Share_Object $object
      */
-    public function initShareObject($object)
+    public function initShareObject(Horde_Share_Object $object)
     {
-        // noop
+        $object->setShareOb($this->_shareCallback);
+        $this->_initShareObject($object);
+    }
+
+    protected function _initShareObject(Horde_Share_Object $object)
+    {
+        // noop here
+    }
+
+    public function setShareCallback($callback)
+    {
+        $this->_shareCallback = $callback;
     }
 
     /**
@@ -166,7 +177,6 @@ class Horde_Share
         }
 
         $share = $this->_getShare($name);
-        $share->setShareOb($this);
         $this->_shareMap[$share->getId()] = $name;
         $this->_cache[$name] = $share;
 
@@ -185,7 +195,6 @@ class Horde_Share
     {
         if (!isset($this->_shareMap[$cid])) {
             $share = $this->_getShareById($cid);
-            $share->setShareOb($this);
             $name = $share->getName();
             $this->_cache[$name] = $share;
             $this->_shareMap[$cid] = $name;
@@ -217,7 +226,6 @@ class Horde_Share
             $shares = $this->_getShares($missing_ids);
             foreach (array_keys($shares) as $key) {
                 $this->_cache[$key] = $shares[$key];
-                $this->_cache[$key]->setShareOb($this);
                 $this->_shareMap[$shares[$key]->getId()] = $key;
                 $all_shares[$key] = $this->_cache[$key];
             }
@@ -327,14 +335,11 @@ class Horde_Share
      * @return Horde_Share_Object  A new share object.
      * @throws Horde_Share_Exception
      */
-    public function newShare($owner, $name)
+    public function newShare($owner, $name = '')
     {
-        if (empty($name)) {
-            throw new Horde_Share_Exception('Share names must be non-empty');
-        }
         $share = $this->_newShare($name);
-        $this->initShareObject($share);
         $share->set('owner', $owner);
+        $share->setShareOb(empty($this->_shareCallback) ? $this : $this->_shareCallback);
 
         return $share;
     }
@@ -473,6 +478,26 @@ class Horde_Share
     }
 
     /**
+     * Returns an opaque value representing this share's listcache.
+     *
+     * @return string
+     */
+    public function getListCache()
+    {
+        return serialize($this->_listcache);
+    }
+
+    /**
+     * Set the list cache by passing in a previously retrieved listcache.
+     *
+     * @param string $cache
+     */
+    public function setListCache($cache)
+    {
+        $this->_listcache = unserialize($cache);
+    }
+
+    /**
      * Give public access to call the share callbacks. Needed to run the
      * callbacks from the Horde_Share_Object objects.
      *
diff --git a/framework/Share/lib/Horde/Share/Datatree.php b/framework/Share/lib/Horde/Share/Datatree.php
index 7e2a26b84..2b63e7ec0 100644
--- a/framework/Share/lib/Horde/Share/Datatree.php
+++ b/framework/Share/lib/Horde/Share/Datatree.php
@@ -79,7 +79,7 @@ class Horde_Share_Datatree extends Horde_Share
         if ($datatreeObject instanceof PEAR_Error) {
             throw new Horde_Share_Exception($datatreeObject->getMessage());
         }
-        $share = new $this->_shareObject($datatreeObject);
+        $share = $this->_createObject($datatreeObject);
 
         return $share;
     }
@@ -99,7 +99,7 @@ class Horde_Share_Datatree extends Horde_Share
         if (is_a($datatreeObject, 'PEAR_Error')) {
             throw new Horde_Share_Exception($datatreeObject->getMessage());
         }
-        $share = new $this->_shareObject($datatreeObject);
+        $share = $this->_createObject($datatreeObject);
 
         return $share;
     }
@@ -125,7 +125,7 @@ class Horde_Share_Datatree extends Horde_Share
             if (is_a($objects[$key], 'PEAR_Error')) {
                 return $objects[$key];
             }
-            $shares[$key] = new $this->_shareObject($objects[$key]);
+            $shares[$key] = $this->_createObject($objects[$key]);
         }
         return $shares;
     }
@@ -205,17 +205,21 @@ class Horde_Share_Datatree extends Horde_Share
     }
 
     /**
-     * Returns a new share object.
+     * Returns a new share object. Share objects should *ALWAYS* be instantiated
+     * via the Horde_Share object.
      *
      * @param string $name  The share's name.
      *
      * @return Horde_Share_Object_datatree  A new share object.
      */
-    protected function &_newShare($name)
+    protected function _newShare($name)
     {
+        if (empty($name)) {
+            throw new Horde_Share_Exception('Share names must be non-empty');
+        }
         $datatreeObject = new Horde_Share_Object_DataTree_Share($name);
         $datatreeObject->setDataTree($this->_datatree);
-        $share = new $this->_shareObject($datatreeObject);
+        $share = $this->_createObject($datatreeObject);
 
         return $share;
     }
diff --git a/framework/Share/lib/Horde/Share/Kolab.php b/framework/Share/lib/Horde/Share/Kolab.php
index c762f784f..218025969 100644
--- a/framework/Share/lib/Horde/Share/Kolab.php
+++ b/framework/Share/lib/Horde/Share/Kolab.php
@@ -64,88 +64,6 @@ class Horde_Share_kolab extends Horde_Share
         }
     }
 
-//    /**
-//     * Returns the properties that need to be serialized.
-//     *
-//     * @return array  List of serializable properties.
-//     */
-//    public function __sleep()
-//    {
-//        $properties = get_object_vars($this);
-//        unset($properties['_sortList'], $properties['_list']);
-//        $properties = array_keys($properties);
-//        return $properties;
-//    }
-//    /**
-//     * Initializes the object.
-//     *
-//     * @throws Horde_Exception
-//     */
-//    public function __wakeup()
-//    {
-//        if (empty($GLOBALS['conf']['kolab']['enabled'])) {
-//            throw new Horde_Exception('You must enable the kolab settings to use the Kolab Share driver.');
-//        }
-//        $this->_type = $this->_getFolderType($this->_app);
-//        $this->_list = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
-//
-//        parent::__wakeup();
-//    }
-
-    /**
-     * Serialize the object. You *MUST* call setStorage() after unserialized.
-     *
-     * @return string
-     */
-    public function serialize()
-    {
-        $data = array(
-            self::VERSION,
-            $this->_app,
-            $this->_root,
-            $this->_cache,
-            $this->_shareMap,
-            $this->_listcache,
-            $this->_shareObject,
-            $this->_permsObject,
-            $this->_type,
-            $this->_listCacheValidity,
-            $this->_session);
-
-        return serialize($data);
-    }
-
-    /**
-     * Reconstruct object from serialized data. You MUST call setStorage()
-     * after unserialize.
-     *
-     * @param  $data
-     */
-    public function unserialize($data)
-    {
-        // Rebuild the object
-        $data = @unserialize($data);
-        if (!is_array($data) ||
-            !isset($data[0]) ||
-            ($data[0] != self::VERSION)) {
-            throw new Exception('Cache version change');
-        }
-        $this->_app = $data[1];
-        $this->_root = $data[2];
-        $this->_cache = $data[3];
-        $this->_shareMap = $data[4];
-        $this->_listcache = $data[5];
-        $this->_shareObject = $data[6];
-        $this->_permsObject = $data [7];
-        $this->_type = $data[8];
-        $this->_listCacheValidity = $data[9];
-        $this->_session = $data[10];
-
-        foreach (array_keys($this->_cache) as $name) {
-            $this->_initShareObject($this->_cache[$name]);
-        }
-    }
-
     /**
      * (re)connect the share object to this share driver. Userful for when
      * share objects are unserialized from a cache separate from the share
@@ -328,6 +246,9 @@ class Horde_Share_kolab extends Horde_Share
      */
     protected function &_newShare($name)
     {
+        if (empty($name)) {
+            throw new Horde_Share_Exception('Share names must be non-empty');
+        }
         $storageObject = new Horde_Share_Object_Kolab($name, $this->_type);
         return $storageObject;
     }
diff --git a/framework/Share/lib/Horde/Share/Object.php b/framework/Share/lib/Horde/Share/Object.php
index 4e63ce772..cb012f456 100644
--- a/framework/Share/lib/Horde/Share/Object.php
+++ b/framework/Share/lib/Horde/Share/Object.php
@@ -12,30 +12,34 @@
 abstract class Horde_Share_Object implements Serializable
 {
     /**
-     * The Horde_Share object which this share is associated with.
+     * A function to be called when a Horde_Share object is needed and not
+     * available.
      *
-     * @var Horde_Share
+     * @var callback
      */
-    protected $_shareOb;
+    protected $_shareCallback;
 
     /**
-     * Associates a Share object with this share.
+     * The Horde_Share object which this share is associated with.
+     * If this is empty, the $_shareCallback is called to obtain it.
      *
-     * @param Horde_Share $shareOb  The Share object.
+     * @var Horde_Share
      */
-    public function setShareOb(Horde_Share $shareOb)
-    {
-        $this->_shareOb = $shareOb;
-    }
+    protected $_shareOb;
 
     /**
-     * Sets any additional storage driver this object may need.
+     * Associates a Share object with this share, or provides a callback that
+     * knows how to provide it.
      *
-     * @param mixed $driver  The storage driver. 
+     * @param mixed Horde_Share | Callback $shareOb  The Share object.
      */
-    public function setStorage($driver)
+    public function setShareOb($shareOb)
     {
-        // Noop
+        if ($shareOb instanceof Horde_Share) {
+            $this->_shareOb = $shareOb;
+        } else {
+            $this->_shareCallback = $shareOb;
+        }
     }
 
     /**
@@ -45,6 +49,10 @@ abstract class Horde_Share_Object implements Serializable
      */
     public function getShareOb()
     {
+        if (empty($this->_shareOb)) {
+            $this->_shareOb = call_user_func($this->_shareCallback);
+        }
+
         return $this->_shareOb;
     }
 
@@ -101,7 +109,7 @@ abstract class Horde_Share_Object implements Serializable
      */
     public function save()
     {
-        $this->_shareOb->runCallback('modify', array($this));
+        $this->getShareOb()->runCallback('modify', array($this));
         return $this->_save();
     }
 
diff --git a/framework/Share/lib/Horde/Share/Object/Datatree.php b/framework/Share/lib/Horde/Share/Object/Datatree.php
index d7728066b..f5737f4e6 100644
--- a/framework/Share/lib/Horde/Share/Object/Datatree.php
+++ b/framework/Share/lib/Horde/Share/Object/Datatree.php
@@ -98,7 +98,7 @@ class Horde_Share_Object_Datatree extends Horde_Share_Object
             return true;
         }
 
-        return $this->_shareOb->getPermsObject()->hasPermission($this->getPermission(), $userid, $permission, $creator);
+        return $this->getShareOb()->getPermsObject()->hasPermission($this->getPermission(), $userid, $permission, $creator);
     }
 
     /**
diff --git a/framework/Share/lib/Horde/Share/Object/Kolab.php b/framework/Share/lib/Horde/Share/Object/Kolab.php
index 9f8324992..6f95894e4 100644
--- a/framework/Share/lib/Horde/Share/Object/Kolab.php
+++ b/framework/Share/lib/Horde/Share/Object/Kolab.php
@@ -10,7 +10,7 @@
 class Horde_Share_Object_Kolab extends Horde_Share_Object implements Serializable
 {
     /** Serializable version **/
-    const VERSION = 1;
+    const VERSION = 2;
 
     /**
      * The Kolab folder this share is based on.
@@ -79,12 +79,14 @@ class Horde_Share_Object_Kolab extends Horde_Share_Object implements Serializabl
         $data = array(
             self::VERSION,
             $this->_data,
-            $this->_folder_name
+            $this->_folder_name,
+            $this->_shareCallback
         );
     }
 
     /**
-     * Unserialize object. You MUST call setShareOb() after unserializtion.
+     * Unserialize object.
+     *
      * @param  $data
      */
     public function unserialize($data)
@@ -98,16 +100,11 @@ class Horde_Share_Object_Kolab extends Horde_Share_Object implements Serializabl
 
         $this->_data = $data[1];
         $this->_folder_name = $data[2];
-    }
-
-    /**
-     * Sets the kolab storage object.
-     *
-     * @param Horde_Kolab_Storage $driver
-     */
-    public function setStorage($driver)
-    {
-        $this->_list = $driver;
+        if (empty($data[3])) {
+            throw new Exception('Missing callback for unserializing Horde_Share_Object');
+        }
+        $this->_shareCallback = $data[3];
+        $this->setShareOb(call_user_func($this->_shareCallback));
     }
 
     /**
diff --git a/framework/Share/lib/Horde/Share/Object/Sql.php b/framework/Share/lib/Horde/Share/Object/Sql.php
index 3fcfed5d7..72e0950f2 100644
--- a/framework/Share/lib/Horde/Share/Object/Sql.php
+++ b/framework/Share/lib/Horde/Share/Object/Sql.php
@@ -7,10 +7,10 @@
  * @author  Michael J. Rubinsky 
  * @package Horde_Share
  */
-class Horde_Share_Object_Sql extends Horde_Share_Object
+class Horde_Share_Object_Sql extends Horde_Share_Object implements Serializable
 {
     /** Serializable version **/
-    const VERSION = 1;
+    const VERSION = 2;
 
     /**
      * The actual storage object that holds the data.
@@ -46,7 +46,7 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
     }
 
     /**
-     * Serialize this object. You *MUST* call setShareOb() after unserializing.
+     * Serialize this object.
      *
      * @return string  The serialized data.
      */
@@ -55,6 +55,7 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
         $data = array(
             self::VERSION,
             $this->data,
+            $this->_shareCallback,
         );
 
         return serialize($data);
@@ -63,8 +64,6 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
     /**
      * Reconstruct the object from serialized data.
      *
-     * You *MUST* call setShareOb() after unserializing.
-     *
      * @param string $data  The serialized data.
      */
     public function unserialize($data)
@@ -77,6 +76,10 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
         }
 
         $this->data = $data[1];
+        if (empty($data[2])) {
+            throw new Exception('Missing callback for Horde_Share_Object unserializing');
+        }
+        $this->_shareCallback = $data[2];
     }
 
     /**
@@ -138,14 +141,14 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
      */
     protected function _save()
     {
-        $db = $this->_shareOb->getStorage();
-        $table = $this->_shareOb->getTable();
+        $db = $this->getShareOb()->getStorage();
+        $table = $this->getShareOb()->getTable();
 
         $fields = array();
         $params = array();
 
         // Build the parameter arrays for the sql statement.
-        foreach ($this->_shareOb->toDriverCharset($this->data) as $key => $value) {
+        foreach ($this->getShareOb()->toDriverCharset($this->data) as $key => $value) {
             if ($key != 'share_id' && $key != 'perm' && $key != 'share_flags') {
                 $fields[] = $key;
                 $params[] = $value;
@@ -224,7 +227,7 @@ class Horde_Share_Object_Sql extends Horde_Share_Object
         if ($userid == $this->data['share_owner']) {
             return true;
         }
-        return $this->_shareOb->getPermsObject()->hasPermission($this->getPermission(), $userid, $permission, $creator);
+        return $this->getShareOb()->getPermsObject()->hasPermission($this->getPermission(), $userid, $permission, $creator);
     }
 
     /**
diff --git a/framework/Share/lib/Horde/Share/Object/Sql/Hierarchical.php b/framework/Share/lib/Horde/Share/Object/Sql/Hierarchical.php
index 3b88e3d43..27a858b38 100644
--- a/framework/Share/lib/Horde/Share/Object/Sql/Hierarchical.php
+++ b/framework/Share/lib/Horde/Share/Object/Sql/Hierarchical.php
@@ -36,7 +36,7 @@ class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
      */
     public function countChildren($user, $perm = Horde_Perms::SHOW, $allLevels = true)
     {
-        return $this->_shareOb->countShares($user, $perm, null, $this, $allLevels);
+        return $this->getShareOb()->countShares($user, $perm, null, $this, $allLevels);
     }
 
     /**
@@ -51,7 +51,7 @@ class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
      */
     public function getChildren($user, $perm = Horde_Perms::SHOW, $allLevels = true)
     {
-        return $this->_shareOb->listShares(
+        return $this->getShareOb()->listShares(
             $user, array('perm' => $perm,
                          'direction' => 1,
                          'parent' => $this,
@@ -66,7 +66,7 @@ class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
      */
     public function getParent()
     {
-        return $this->_shareOb->getParent($this);
+        return $this->getShareOb()->getParent($this);
     }
 
     /**
@@ -96,12 +96,12 @@ class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
     public function setParent($parent)
     {
         if (!is_null($parent) && !is_a($parent, 'Horde_Share_Object')) {
-            $parent = $this->_shareOb->getShareById($parent);
+            $parent = $this->getShareOb()->getShareById($parent);
         }
 
         /* If we are an existing share, check for any children */
         if ($this->getId()) {
-            $children = $this->_shareOb->listShares(null,
+            $children = $this->getShareOb()->listShares(null,
                 array('perm' => Horde_Perms::EDIT,
                       'parent' => $this,
                       'all_levels' => true,
@@ -121,9 +121,9 @@ class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
             $parent_string = null;
         }
         $this->data['share_parents'] = $parent_string;
-        $sql = 'UPDATE ' . $this->_shareOb->getTable() . ' SET share_parents = ? WHERE share_id = ?';
+        $sql = 'UPDATE ' . $this->getShareOb()->getTable() . ' SET share_parents = ? WHERE share_id = ?';
         try {
-            $this->_shareOb->getStorage()->update($sql, array($this->data['share_parents'], $this->getId()));
+            $this->getShareOb()->getStorage()->update($sql, array($this->data['share_parents'], $this->getId()));
         } catch (Horde_Db_Exception $e) {
             throw new Horde_Share_Exception($e->getMessage());
         }
diff --git a/framework/Share/lib/Horde/Share/Sql.php b/framework/Share/lib/Horde/Share/Sql.php
index 8f3e1c712..e7c836d61 100644
--- a/framework/Share/lib/Horde/Share/Sql.php
+++ b/framework/Share/lib/Horde/Share/Sql.php
@@ -16,7 +16,7 @@
 /**
  * @package Horde_Share
  */
-class Horde_Share_Sql extends Horde_Share implements Serializable
+class Horde_Share_Sql extends Horde_Share
 {
     /* Share has user perms */
     const SQL_FLAG_USERS = 1;
@@ -59,75 +59,6 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
     }
 
     /**
-     * Serializes the object. Includes all properties except _table (this can
-     * be determined by _app), and _db (which is injected when unserialized).
-     * Note that you MUST set the db adapter after unserializing, but calling
-     * the setDb() method.
-     *
-     * @return string  The serialized object.
-     */
-    public function serialize()
-    {
-        $data = array(
-            self::VERSION,
-            $this->_app,
-            $this->_root,
-            $this->_cache,
-            $this->_shareMap,
-            $this->_listcache,
-            $this->_shareObject,
-            $this->_permsObject,
-            $this->_groups
-        );
-
-        return serialize($data);
-    }
-
-    /**
-     * Reconstructs object from serialized properties.
-     * Note: You MUST set the db adapter via setDb() after unserializing this
-     * object.
-     *
-     * @param string $serialized
-     */
-    public function unserialize($data)
-    {
-        $data = @unserialize($data);
-        if (!is_array($data) ||
-            !isset($data[0]) ||
-            ($data[0] != self::VERSION)) {
-            throw new Exception('Cache version change');
-        }
-
-        $this->_app = $data[1];
-        $this->_root = $data[2];
-        $this->_cache = $data[3];
-        $this->_shareMap = $data[4];
-        $this->_listcache = $data[5];
-        $this->_shareObject = $data[6];
-        $this->_permsObject = $data[7];
-        $this->_groups = $data[8];
-
-        $this->_table = $this->_app . '_shares';
-
-        foreach (array_keys($this->_cache) as $name) {
-            $this->initShareObject($this->_cache[$name]);
-        }
-    }
-
-    /**
-     * (re)connect the share object to this share driver. Userful for when
-     * share objects are unserialized from a cache separate from the share
-     * driver.
-     *
-     * @param Horde_Share_Object $object
-     */
-    public function initShareObject($object)
-    {
-        $object->setShareOb($this);
-    }
-
-    /**
      * Get storage table
      *
      * @return string
@@ -232,7 +163,15 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         $data = $this->_fromDriverCharset($results);
         $this->_loadPermissions($data);
 
-        return new $this->_shareObject($data);
+        return $this->_createObject($data);
+    }
+
+    protected function _createObject($data = array())
+    {
+        $object = new $this->_shareObject($data);
+        $this->initShareObject($object);
+
+        return $object;
     }
 
     /**
@@ -279,7 +218,7 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         $data = $this->_fromDriverCharset($results);
         $this->_loadPermissions($data);
 
-        return new $this->_shareObject($data);
+        return $this->_createObject($data);
     }
 
     /**
@@ -342,7 +281,7 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         $sharelist = array();
         foreach ($shares as $id => $data) {
             $this->_getSharePerms($data);
-            $sharelist[$data['share_name']] = new $this->_shareObject($data);
+            $sharelist[$data['share_name']] = $this->_createObject($data);
         }
 
         return $sharelist;
@@ -408,8 +347,7 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         $sharelist = array();
         foreach ($shares as $id => $data) {
             $this->_getSharePerms($data);
-            $sharelist[$data['share_name']] = new $this->_shareObject($data);
-            $sharelist[$data['share_name']]->setShareOb($this);
+            $sharelist[$data['share_name']] = $this->_createObject($data);
         }
 
         return $sharelist;
@@ -433,7 +371,6 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
      */
     public function listShares($userid, $params = array())
     {
-        //var_dump($params);
         $params = array_merge(array('perm' => Horde_Perms::SHOW,
                                     'attributes' => null,
                                     'from' => 0,
@@ -441,6 +378,11 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
                                     'sort_by' => null,
                                     'direction' => 0),
                               $params);
+
+        $key = md5(serialize(array($userid, $params)));
+        if (!empty($this->_listcache[$key])) {
+            return $this->_listcache[$key];
+        }
         $shares = array();
         if (is_null($params['sort_by'])) {
             $sortfield = 's.share_name';
@@ -510,17 +452,17 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         $sharelist = array();
         foreach ($shares as $id => $data) {
             $this->_getSharePerms($data);
-            $sharelist[$data['share_name']] = new $this->_shareObject($data);
-            $sharelist[$data['share_name']]->setShareOb($this);
+            $sharelist[$data['share_name']] = $this->_createObject($data);
         }
         unset($shares);
 
         // Run the results through the callback, if configured.
         if (!empty($this->_callbacks['list'])) {
-            return $this->runCallback('list', array($userid, $sharelist, $params));
+            $sharelist = $this->runCallback('list', array($userid, $sharelist, $params));
         }
+        $this->_listcache[$key] = $sharelist;
 
-        return $sharelist;
+        return $this->_listcache[$key];
     }
 
     /**
@@ -544,8 +486,7 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
         foreach ($rows as $share) {
             $data = $this->_fromDriverCharset($share);
             $this->_getSharePerms($data);
-            $sharelist[$data['share_name']] = new $this->_shareObject($data);
-            $sharelist[$data['share_name']]->setShareOb($this);
+            $sharelist[$data['share_name']] = $this->_createObject($data);
         }
 
         return $sharelist;
@@ -582,7 +523,10 @@ class Horde_Share_Sql extends Horde_Share implements Serializable
      */
     protected function _newShare($name)
     {
-        return new $this->_shareObject(array('share_name' => $name));
+        if (empty($name)) {
+            throw new Horde_Share_Exception('Share names must be non-empty');
+        }
+        return $this->_createObject(array('share_name' => $name));
     }
 
     /**
diff --git a/framework/Share/lib/Horde/Share/Sql/Hierarchical.php b/framework/Share/lib/Horde/Share/Sql/Hierarchical.php
index d0b32223e..0889d8198 100644
--- a/framework/Share/lib/Horde/Share/Sql/Hierarchical.php
+++ b/framework/Share/lib/Horde/Share/Sql/Hierarchical.php
@@ -17,21 +17,6 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
     protected $_shareObject = 'Horde_Share_Object_Sql_Hierarchical';
 
     /**
-     * Override new share creation so we can allow for shares with empty
-     * share_names.
-     *
-     * @see Horde_Share::newShare
-     */
-    public function newShare($owner, $name = '')
-    {
-        $share = $this->_newShare();
-        $this->initShareObject($share);
-        $share->set('owner', $owner);
-
-        return $share;
-    }
-
-    /**
      * Returns a new share object.
      *
      * @param string $name  The share's name.
@@ -40,8 +25,7 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
      */
     protected function _newShare()
     {
-        $share = new $this->_shareObject();
-        return $share;
+        return $this->_createObject();
     }
 
     /**
@@ -76,6 +60,10 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
                                     'all_levels' => true,
                                     'ignore_perms' => false),
                               $params);
+        $key = md5(serialize(array($userid, $params)));
+        if (!empty($this->_listcache[$key])) {
+            return $this->_listcache[$key];
+        }
         $shares = array();
         if (is_null($params['sort_by'])) {
             $sortfield = 's.share_id';
@@ -145,16 +133,17 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
         $sharelist = array();
         foreach ($shares as $id => $data) {
             $this->_getSharePerms($data);
-            $sharelist[$id] = new $this->_shareObject($data);
-            $sharelist[$id]->setShareOb($this);
+            $sharelist[$id] = $this->_createObject($data);
         }
         unset($shares);
 
         // Run the results through the callback, if configured.
         if (!empty($this->_callbacks['list'])) {
-            return $this->runCallback('list', array($userid, $sharelist, $params));
+            $sharelist = $this->runCallback('list', array($userid, $sharelist, $params));
         }
 
+        $this->_listcache[$key] = $sharelist;
+
         return $sharelist;
     }
 
@@ -189,7 +178,7 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
         }
         $key = hash('sha1', serialize(array($userid, $perm, $parent_id, $allLevels, $attributes, $ignorePerms)));
         if (isset($criteria[$key])) {
-            //return $criteria[$key];
+            return $criteria[$key];
         }
 
         $query = ' FROM ' . $this->_table . ' s ';
@@ -381,8 +370,7 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
     {
         if (!isset($this->_cache[$cid])) {
             $share = $this->_getShareById($cid);
-            $share->setShareOb($this);
-            $this->_cache[$cid] = &$share;
+            $this->_cache[$cid] = $share;
         }
 
         return $this->_cache[$cid];
@@ -403,7 +391,7 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
         $missing_ids = array();
         foreach ($cids as $cid) {
             if (isset($this->_cache[$cid])) {
-                $all_shares[] = &$this->_cache[$cid];
+                $all_shares[] = $this->_cache[$cid];
             } else {
                 $missing_ids[] = $cid;
             }
@@ -412,9 +400,8 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
         if (count($missing_ids)) {
             $shares = $this->_getShares($missing_ids);
             foreach (array_keys($shares) as $key) {
-                $this->_cache[$key] = &$shares[$key];
-                $this->_cache[$key]->setShareOb($this);
-                $all_shares[$key] = &$this->_cache[$key];
+                $this->_cache[$key] = $shares[$key];
+                $all_shares[$key] = $this->_cache[$key];
             }
         }
 
@@ -507,7 +494,7 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
 
         $sharelist = array();
         foreach ($shares as $id => $data) {
-            $sharelist[$id] = new $this->_shareObject($data);
+            $sharelist[$id] = $this->_createObject($data);
         }
 
         return $sharelist;
diff --git a/framework/Share/package.xml b/framework/Share/package.xml
index 5d6ba47c5..337ae18bc 100644
--- a/framework/Share/package.xml
+++ b/framework/Share/package.xml
@@ -11,8 +11,8 @@ resources a user owns or has access to.
   chuck@horde.org
   yes
  
- 2010-10-29
- 
+ 2010-11-12
+ 
  
   0.0.4
   0.0.4
@@ -450,6 +450,11 @@ resources a user owns or has access to.
    
    
    
+   
+   
+   
+   
+   
   
  
  
@@ -518,7 +523,7 @@ Initial release as a PEAR package
     beta
     beta
    
-   2010-10-29
+   2010-11-12
    LGPL
    
 * Converted to Horde 4 coding standards
-- 
2.11.0