]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - classes/Memcached_DataObject.php
Merge branch '0.8.x' of git@gitorious.org:laconica/dev into 0.8.x
[quix0rs-gnu-social.git] / classes / Memcached_DataObject.php
1 <?php
2 /*
3  * Laconica - a distributed open-source microblogging tool
4  * Copyright (C) 2008, Controlez-Vous, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 if (!defined('LACONICA')) { exit(1); }
21
22 require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
23
24 class Memcached_DataObject extends DB_DataObject
25 {
26     function &staticGet($cls, $k, $v=null)
27     {
28         if (is_null($v)) {
29             $v = $k;
30             # XXX: HACK!
31             $i = new $cls;
32             $keys = $i->keys();
33             $k = $keys[0];
34             unset($i);
35         }
36         $i = Memcached_DataObject::getcached($cls, $k, $v);
37         if ($i) {
38             return $i;
39         } else {
40             $i = DB_DataObject::staticGet($cls, $k, $v);
41             if ($i) {
42                 $i->encache();
43             }
44             return $i;
45         }
46     }
47
48     function &pkeyGet($cls, $kv)
49     {
50         $i = Memcached_DataObject::multicache($cls, $kv);
51         if ($i) {
52             return $i;
53         } else {
54             $i = new $cls();
55             foreach ($kv as $k => $v) {
56                 $i->$k = $v;
57             }
58             if ($i->find(true)) {
59                 $i->encache();
60             } else {
61                 $i = null;
62             }
63             return $i;
64         }
65     }
66
67     function insert()
68     {
69         $result = parent::insert();
70         return $result;
71     }
72
73     function update($orig=null)
74     {
75         if (is_object($orig) && $orig instanceof Memcached_DataObject) {
76             $orig->decache(); # might be different keys
77         }
78         $result = parent::update($orig);
79         if ($result) {
80             $this->encache();
81         }
82         return $result;
83     }
84
85     function delete()
86     {
87         $this->decache(); # while we still have the values!
88         return parent::delete();
89     }
90
91     static function memcache() {
92         return common_memcache();
93     }
94
95     static function cacheKey($cls, $k, $v) {
96         return common_cache_key(strtolower($cls).':'.$k.':'.$v);
97     }
98
99     static function getcached($cls, $k, $v) {
100         $c = Memcached_DataObject::memcache();
101         if (!$c) {
102             return false;
103         } else {
104             return $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
105         }
106     }
107
108     function keyTypes()
109     {
110         global $_DB_DATAOBJECT;
111         if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
112             $this->databaseStructure();
113
114         }
115         return $_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"];
116     }
117
118     function encache()
119     {
120         $c = $this->memcache();
121         if (!$c) {
122             return false;
123         } else {
124             $pkey = array();
125             $pval = array();
126             $types = $this->keyTypes();
127             ksort($types);
128             foreach ($types as $key => $type) {
129                 if ($type == 'K') {
130                     $pkey[] = $key;
131                     $pval[] = $this->$key;
132                 } else {
133                     $c->set($this->cacheKey($this->tableName(), $key, $this->$key), $this);
134                 }
135             }
136             # XXX: should work for both compound and scalar pkeys
137             $pvals = implode(',', $pval);
138             $pkeys = implode(',', $pkey);
139             $c->set($this->cacheKey($this->tableName(), $pkeys, $pvals), $this);
140         }
141     }
142
143     function decache()
144     {
145         $c = $this->memcache();
146         if (!$c) {
147             return false;
148         } else {
149             $pkey = array();
150             $pval = array();
151             $types = $this->keyTypes();
152             ksort($types);
153             foreach ($types as $key => $type) {
154                 if ($type == 'K') {
155                     $pkey[] = $key;
156                     $pval[] = $this->$key;
157                 } else {
158                     $c->delete($this->cacheKey($this->tableName(), $key, $this->$key));
159                 }
160             }
161             # should work for both compound and scalar pkeys
162             # XXX: comma works for now but may not be safe separator for future keys
163             $pvals = implode(',', $pval);
164             $pkeys = implode(',', $pkey);
165             $c->delete($this->cacheKey($this->tableName(), $pkeys, $pvals));
166         }
167     }
168
169     function multicache($cls, $kv)
170     {
171         ksort($kv);
172         $c = Memcached_DataObject::memcache();
173         if (!$c) {
174             return false;
175         } else {
176             $pkeys = implode(',', array_keys($kv));
177             $pvals = implode(',', array_values($kv));
178             return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals));
179         }
180     }
181
182     function getSearchEngine($table)
183     {
184         require_once INSTALLDIR.'/lib/search_engines.php';
185         static $search_engine;
186         if (!isset($search_engine)) {
187                 $connected = false;
188                 if (common_config('sphinx', 'enabled')) {
189                     $search_engine = new SphinxSearch($this, $table);
190                     $connected = $search_engine->is_connected();
191                 }
192
193                 // unable to connect to sphinx' search daemon
194                 if (!$connected) {
195                     if ('mysql' === common_config('db', 'type')) {
196                         $search_engine = new MySQLSearch($this, $table);
197                     } else {
198                         $search_engine = new PGSearch($this, $table);
199                     }
200                 }
201         }
202         return $search_engine;
203     }
204
205     static function cachedQuery($cls, $qry, $expiry=3600)
206     {
207         $c = Memcached_DataObject::memcache();
208         if (!$c) {
209             $inst = new $cls();
210             $inst->query($qry);
211             return $inst;
212         }
213         $key_part = common_keyize($cls).':'.md5($qry);
214         $ckey = common_cache_key($key_part);
215         $stored = $c->get($ckey);
216         if ($stored) {
217             return new ArrayWrapper($stored);
218         }
219
220         $inst = new $cls();
221         $inst->query($qry);
222         $cached = array();
223         while ($inst->fetch()) {
224             $cached[] = clone($inst);
225         }
226         $inst->free();
227         $c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
228         return new ArrayWrapper($cached);
229     }
230 }