summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--classes/Notice.php21
-rw-r--r--classes/User.php57
-rw-r--r--lib/common.php6
-rw-r--r--lib/noticewrapper.php57
-rw-r--r--lib/util.php10
5 files changed, 150 insertions, 1 deletions
diff --git a/classes/Notice.php b/classes/Notice.php
index 6cfd0d786..181a3bd1b 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -111,6 +111,27 @@ class Notice extends DB_DataObject
common_save_replies($notice);
$notice->saveTags();
+
+ # Clear the cache for subscribed users, so they'll update at next request
+ # XXX: someone clever could prepend instead of clearing the cache
+
+ if (common_config('memcached', 'enabled')) {
+ $cache = new Memcache();
+ if ($cache->connect(common_config('memcached', 'server'), common_config('memcached', 'port'))) {
+ $user = new User();
+
+ $user->query('SELECT id ' .
+ 'FROM user JOIN subscription ON user.id = subscription.subscriber' .
+ 'WHERE subscription.subscribed = ' . $notice->profile_id);
+
+ while ($user->fetch()) {
+ $cache->delete(common_cache_key('user:notices_with_friends:' . $this->id));
+ }
+
+ $user->free();
+ unset($user);
+ }
+ }
return $notice;
}
diff --git a/classes/User.php b/classes/User.php
index 7eb21eaeb..17b1c9fea 100644
--- a/classes/User.php
+++ b/classes/User.php
@@ -18,11 +18,18 @@
*/
if (!defined('LACONICA')) { exit(1); }
+
+/* We keep the first three 20-notice pages, plus one for pagination check,
+ * in the memcached cache. */
+
+define('WITHFRIENDS_CACHE_WINDOW', 61);
+
/**
* Table Definition for user
*/
require_once 'DB/DataObject.php';
require_once 'Validate.php';
+require_once($INSTALLDIR.'/lib/noticewrapper.php');
class User extends DB_DataObject
{
@@ -134,6 +141,19 @@ class User extends DB_DataObject
}
function noticesWithFriends($offset=0, $limit=20) {
+
+ # We clearly need a more elegant way to make this work.
+
+ if (common_config('memcached', 'enabled')) {
+ if ($offset + $limit < WITHFRIENDS_CACHE_WINDOW) {
+ $cached = $this->noticesWithFriendsCachedWindow();
+ if (!$cached) {
+ $cached = $this->noticesWithFriendsWindow();
+ }
+ $wrapper = new NoticeWrapper(array_slice($cached, $offset, $limit));
+ return $wrapper;
+ }
+ }
$notice = new Notice();
@@ -146,6 +166,43 @@ class User extends DB_DataObject
return $notice;
}
+ function noticesWithFriendsCachedWindow() {
+ $cache = new Memcache();
+ $res = $cache->connect(common_config('memcached', 'server'), common_config('memcached', 'port'));
+ if (!$res) {
+ return NULL;
+ }
+ $notices = $cache->get(common_cache_key('user:notices_with_friends:' . $this->id));
+ return $notices;
+ }
+
+ function noticesWithFriendsWindow() {
+
+ $cache = new Memcache();
+ $res = $cache->connect(common_config('memcached', 'server'), common_config('memcached', 'port'));
+
+ if (!$res) {
+ return NULL;
+ }
+
+ $notice = new Notice();
+
+ $notice->query('SELECT notice.* ' .
+ 'FROM notice JOIN subscription on notice.profile_id = subscription.subscribed ' .
+ 'WHERE subscription.subscriber = ' . $this->id . ' ' .
+ 'ORDER BY created DESC, notice.id DESC ' .
+ 'LIMIT 0, ' . WITHFRIENDS_CACHE_WINDOW);
+
+ $notices = array();
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ $cache->set(common_cache_key('user:notices_with_friends:' . $this->id), $notices);
+ return $notices;
+ }
+
static function register($fields) {
# MAGICALLY put fields into current scope
diff --git a/lib/common.php b/lib/common.php
index 80aab806f..1aa60fc42 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -97,7 +97,11 @@ $config =
'daemon' =>
array('piddir' => '/var/run',
'user' => false,
- 'group' => false)
+ 'group' => false),
+ 'memcached' =>
+ array('enabled' => false,
+ 'server' => 'localhost',
+ 'port' => 11211)
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
diff --git a/lib/noticewrapper.php b/lib/noticewrapper.php
new file mode 100644
index 000000000..fbf7b59f4
--- /dev/null
+++ b/lib/noticewrapper.php
@@ -0,0 +1,57 @@
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('LACONICA')) { exit(1); }
+
+class NoticeWrapper {
+
+ public $id; // int(4) primary_key not_null
+ public $profile_id; // int(4) not_null
+ public $uri; // varchar(255) unique_key
+ public $content; // varchar(140)
+ public $rendered; // text()
+ public $url; // varchar(255)
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+ public $reply_to; // int(4)
+ public $is_local; // tinyint(1)
+ public $source; // varchar(32)
+
+ var $notices = NULL;
+ var $i = -1;
+
+ function __construct($arr) {
+ $this->notices = $arr;
+ }
+
+ function fetch() {
+ static $fields = array('id', 'profile_id', 'uri', 'content', 'rendered',
+ 'url', 'created', 'modified', 'reply_to', 'is_local', 'source');
+ $this->i++;
+ if ($this->i >= array_count($notices)) {
+ return false;
+ } else {
+ $n = $notices[$this->i];
+ foreach ($fields as $f) {
+ $this->$f = $n->$f;
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/util.php b/lib/util.php
index ff22ac644..349cff722 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -1528,3 +1528,13 @@ function common_session_token() {
}
return $_SESSION['token'];
}
+
+function common_cache_key($extra) {
+ return 'laconica:' . common_keyize(common_config('site', 'name')) . ':' . $extra;
+}
+
+function common_keyize($str) {
+ $str = strtolower($str);
+ $str = preg_replace('/\s/', '_', $str);
+ return $str;
+}