]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - classes/Memcached_DataObject.php
Remove verifier from Oauth_application_user (not needed there)
[quix0rs-gnu-social.git] / classes / Memcached_DataObject.php
index f511335083e987da245fc4243236a845131436ec..33645a3e8b6eeaf75246d69e87f70db41ab209a7 100644 (file)
@@ -19,8 +19,6 @@
 
 if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
-
 class Memcached_DataObject extends DB_DataObject
 {
     /**
@@ -37,6 +35,51 @@ class Memcached_DataObject extends DB_DataObject
         }
     }
 
+    /**
+     * Magic function called at serialize() time.
+     *
+     * We use this to drop a couple process-specific references
+     * from DB_DataObject which can cause trouble in future
+     * processes.
+     *
+     * @return array of variable names to include in serialization.
+     */
+    function __sleep()
+    {
+        $vars = array_keys(get_object_vars($this));
+        $skip = array('_DB_resultid', '_link_loaded');
+        return array_diff($vars, $skip);
+    }
+
+    /**
+     * Magic function called at unserialize() time.
+     *
+     * Clean out some process-specific variables which might
+     * be floating around from a previous process's cached
+     * objects.
+     *
+     * Old cached objects may still have them.
+     */
+    function __wakeup()
+    {
+        // Refers to global state info from a previous process.
+        // Clear this out so we don't accidentally break global
+        // state in *this* process.
+        $this->_DB_resultid = null;
+
+        // We don't have any local DBO refs, so clear these out.
+        $this->_link_loaded = false;
+    }
+
+    /**
+     * Wrapper for DB_DataObject's static lookup using memcached
+     * as backing instead of an in-process cache array.
+     *
+     * @param string $cls classname of object type to load
+     * @param mixed $k key field name, or value for primary key
+     * @param mixed $v key field value, or leave out for primary key lookup
+     * @return mixed Memcached_DataObject subtype or false
+     */
     function &staticGet($cls, $k, $v=null)
     {
         if (is_null($v)) {
@@ -53,14 +96,16 @@ class Memcached_DataObject extends DB_DataObject
         } else {
             $i = DB_DataObject::factory($cls);
             if (empty($i)) {
-                return null;
+                $i = false;
+                return $i;
             }
             $result = $i->get($k, $v);
             if ($result) {
                 $i->encache();
                 return $i;
             } else {
-                return null;
+                $i = false;
+                return $i;
             }
         }
     }
@@ -113,7 +158,7 @@ class Memcached_DataObject extends DB_DataObject
     }
 
     static function cacheKey($cls, $k, $v) {
-        if (is_object($cls) || is_object($j) || is_object($v)) {
+        if (is_object($cls) || is_object($k) || is_object($v)) {
             $e = new Exception();
             common_log(LOG_ERR, __METHOD__ . ' object in param: ' .
                 str_replace("\n", " ", $e->getTraceAsString()));
@@ -126,7 +171,16 @@ class Memcached_DataObject extends DB_DataObject
         if (!$c) {
             return false;
         } else {
-            return $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
+            $obj = $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
+            if (0 == strcasecmp($cls, 'User')) {
+                // Special case for User
+                if (is_object($obj) && is_object($obj->id)) {
+                    common_log(LOG_ERR, "User " . $obj->nickname . " was cached with User as ID; deleting");
+                    $c->delete(Memcached_DataObject::cacheKey($cls, $k, $v));
+                    return false;
+                }
+            }
+            return $obj;
         }
     }
 
@@ -145,6 +199,12 @@ class Memcached_DataObject extends DB_DataObject
         $c = $this->memcache();
         if (!$c) {
             return false;
+        } else if ($this->tableName() == 'user' && is_object($this->id)) {
+            // Special case for User bug
+            $e = new Exception();
+            common_log(LOG_ERR, __METHOD__ . ' caching user with User object as ID ' .
+                       str_replace("\n", " ", $e->getTraceAsString()));
+            return false;
         } else {
             $pkey = array();
             $pval = array();
@@ -253,6 +313,39 @@ class Memcached_DataObject extends DB_DataObject
         return new ArrayWrapper($cached);
     }
 
+    /**
+     * sends query to database - this is the private one that must work 
+     *   - internal functions use this rather than $this->query()
+     *
+     * Overridden to do logging.
+     *
+     * @param  string  $string
+     * @access private
+     * @return mixed none or PEAR_Error
+     */
+    function _query($string)
+    {
+        $start = microtime(true);
+        $result = parent::_query($string);
+        $delta = microtime(true) - $start;
+
+        $limit = common_config('db', 'log_slow_queries');
+        if (($limit > 0 && $delta >= $limit) || common_config('db', 'log_queries')) {
+            $clean = $this->sanitizeQuery($string);
+            common_log(LOG_DEBUG, sprintf("DB query (%0.3fs): %s", $delta, $clean));
+        }
+        return $result;
+    }
+
+    // Sanitize a query for logging
+    // @fixme don't trim spaces in string literals
+    function sanitizeQuery($string)
+    {
+        $string = preg_replace('/\s+/', ' ', $string);
+        $string = trim($string);
+        return $string;
+    }
+
     // We overload so that 'SET NAMES "utf8"' is called for
     // each connection
 
@@ -269,6 +362,29 @@ class Memcached_DataObject extends DB_DataObject
             $exists = false;
        }
 
+        // @fixme horrible evil hack!
+        //
+        // In multisite configuration we don't want to keep around a separate
+        // connection for every database; we could end up with thousands of
+        // connections open per thread. In an ideal world we might keep
+        // a connection per server and select different databases, but that'd
+        // be reliant on having the same db username/pass as well.
+        //
+        // MySQL connections are cheap enough we're going to try just
+        // closing out the old connection and reopening when we encounter
+        // a new DSN.
+        //
+        // WARNING WARNING if we end up actually using multiple DBs at a time
+        // we'll need some fancier logic here.
+        if (!$exists && !empty($_DB_DATAOBJECT['CONNECTIONS'])) {
+            foreach ($_DB_DATAOBJECT['CONNECTIONS'] as $index => $conn) {
+                if (!empty($conn)) {
+                    $conn->disconnect();
+                }
+                unset($_DB_DATAOBJECT['CONNECTIONS'][$index]);
+            }
+        }
+
         $result = parent::_connect();
 
         if ($result && !$exists) {