summaryrefslogtreecommitdiff
path: root/classes/Memcached_DataObject.php
diff options
context:
space:
mode:
Diffstat (limited to 'classes/Memcached_DataObject.php')
-rw-r--r--classes/Memcached_DataObject.php105
1 files changed, 101 insertions, 4 deletions
diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php
index bc4c3a000..4579f64df 100644
--- a/classes/Memcached_DataObject.php
+++ b/classes/Memcached_DataObject.php
@@ -128,12 +128,13 @@ class Memcached_DataObject extends Safe_DataObject
}
static function cacheKey($cls, $k, $v) {
- if (is_object($cls) || is_object($k) || is_object($v)) {
+ if (is_object($cls) || is_object($k) || (is_object($v) && !($v instanceof DB_DataObject_Cast))) {
$e = new Exception();
common_log(LOG_ERR, __METHOD__ . ' object in param: ' .
str_replace("\n", " ", $e->getTraceAsString()));
}
- return common_cache_key(strtolower($cls).':'.$k.':'.$v);
+ $vstr = self::valueString($v);
+ return common_cache_key(strtolower($cls).':'.$k.':'.$vstr);
}
static function getcached($cls, $k, $v) {
@@ -229,10 +230,10 @@ class Memcached_DataObject extends Safe_DataObject
if (empty($this->$key)) {
continue;
}
- $ckeys[] = $this->cacheKey($this->tableName(), $key, $this->$key);
+ $ckeys[] = $this->cacheKey($this->tableName(), $key, self::valueString($this->$key));
} else if ($type == 'K' || $type == 'N') {
$pkey[] = $key;
- $pval[] = $this->$key;
+ $pval[] = self::valueString($this->$key);
} else {
throw new Exception("Unknown key type $key => $type for " . $this->tableName());
}
@@ -330,6 +331,10 @@ class Memcached_DataObject extends Safe_DataObject
*/
function _query($string)
{
+ if (common_config('db', 'annotate_queries')) {
+ $string = $this->annotateQuery($string);
+ }
+
$start = microtime(true);
$result = parent::_query($string);
$delta = microtime(true) - $start;
@@ -342,6 +347,70 @@ class Memcached_DataObject extends Safe_DataObject
return $result;
}
+ /**
+ * Find the first caller in the stack trace that's not a
+ * low-level database function and add a comment to the
+ * query string. This should then be visible in process lists
+ * and slow query logs, to help identify problem areas.
+ *
+ * Also marks whether this was a web GET/POST or which daemon
+ * was running it.
+ *
+ * @param string $string SQL query string
+ * @return string SQL query string, with a comment in it
+ */
+ function annotateQuery($string)
+ {
+ $ignore = array('annotateQuery',
+ '_query',
+ 'query',
+ 'get',
+ 'insert',
+ 'delete',
+ 'update',
+ 'find');
+ $ignoreStatic = array('staticGet',
+ 'pkeyGet',
+ 'cachedQuery');
+ $here = get_class($this); // if we get confused
+ $bt = debug_backtrace();
+
+ // Find the first caller that's not us?
+ foreach ($bt as $frame) {
+ $func = $frame['function'];
+ if (isset($frame['type']) && $frame['type'] == '::') {
+ if (in_array($func, $ignoreStatic)) {
+ continue;
+ }
+ $here = $frame['class'] . '::' . $func;
+ break;
+ } else if (isset($frame['type']) && $frame['type'] == '->') {
+ if ($frame['object'] === $this && in_array($func, $ignore)) {
+ continue;
+ }
+ if (in_array($func, $ignoreStatic)) {
+ continue; // @fixme this shouldn't be needed?
+ }
+ $here = get_class($frame['object']) . '->' . $func;
+ break;
+ }
+ $here = $func;
+ break;
+ }
+
+ if (php_sapi_name() == 'cli') {
+ $context = basename($_SERVER['PHP_SELF']);
+ } else {
+ $context = $_SERVER['REQUEST_METHOD'];
+ }
+
+ // Slip the comment in after the first command,
+ // or DB_DataObject gets confused about handling inserts and such.
+ $parts = explode(' ', $string, 2);
+ $parts[0] .= " /* $context $here */";
+ return implode(' ', $parts);
+ }
+
// Sanitize a query for logging
// @fixme don't trim spaces in string literals
function sanitizeQuery($string)
@@ -505,6 +574,9 @@ class Memcached_DataObject extends Safe_DataObject
if ($this->id) {
$id .= ':' . $this->id;
}
+ if ($message instanceof PEAR_Error) {
+ $message = $message->getMessage();
+ }
throw new ServerException("[$id] DB_DataObject error [$type]: $message");
}
@@ -533,5 +605,30 @@ class Memcached_DataObject extends Safe_DataObject
return $c->set($cacheKey, $value);
}
+
+ static function valueString($v)
+ {
+ $vstr = null;
+ if (is_object($v) && $v instanceof DB_DataObject_Cast) {
+ switch ($v->type) {
+ case 'date':
+ $vstr = $v->year . '-' . $v->month . '-' . $v->day;
+ break;
+ case 'blob':
+ case 'string':
+ case 'sql':
+ case 'datetime':
+ case 'time':
+ throw new ServerException("Unhandled DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
+ break;
+ default:
+ throw new ServerException("Unknown DB_DataObject_Cast type passed as cacheKey value: '$v->type'");
+ break;
+ }
+ } else {
+ $vstr = strval($v);
+ }
+ return $vstr;
+ }
}