Mercurial > defr > drupal > ad
comparison cache/memcache/ad_cache_memcache.inc @ 0:d8a3998dac8e ad
ajout module ad
author | pierre |
---|---|
date | Fri, 20 Feb 2009 14:04:09 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d8a3998dac8e |
---|---|
1 <?php | |
2 // $Id: ad_cache_memcache.inc,v 1.1.2.6.2.6 2009/02/16 23:12:28 jeremy Exp $ | |
3 | |
4 /** | |
5 * @file | |
6 * Memcache include. | |
7 * | |
8 * Copyright (c) 2005-2009. | |
9 * Jeremy Andrews <jeremy@tag1consulting.com>. | |
10 */ | |
11 | |
12 /** | |
13 * TODO: Debug Raw and IFrame display methods, neither currently seem to work | |
14 * with this cache type. | |
15 */ | |
16 | |
17 /** | |
18 * Called by adserve.inc, display an ad from memcache. | |
19 */ | |
20 function ad_cache_memcache() { | |
21 _debug_echo('Memcache: entering ad_cache_memcache().'); | |
22 | |
23 // TODO: Move the meat of this function into adserve.php, simplifying what | |
24 // cache plugins have to do and removing duplicated logic. | |
25 $init_cache = array(); | |
26 $init_func = ad_cache_memcache_hook($init_cache, 'include_file_init', 'include_func_init'); | |
27 | |
28 $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none'; | |
29 if ($hostid == 'none' || ad_memcache_get("ad-hostid-$hostid")) { | |
30 if (function_exists($init_func)) { | |
31 $init = $init_func($init_cache, $hostid); | |
32 } | |
33 if (!empty($init)) { | |
34 if (adserve_variable('debug')) { | |
35 echo "Memcache: initialized externally:<pre>\n"; | |
36 print_r($init); | |
37 echo '</pre>'; | |
38 } | |
39 $type = $init['type']; | |
40 $id = $init['id']; | |
41 $group = $init['group']; | |
42 $aids = explode(',', $id); | |
43 adserve_variable('quantity', $init['quantity']); | |
44 } | |
45 else { | |
46 if ($id = adserve_variable('nids')) { | |
47 $type = 'node'; | |
48 } | |
49 else if ($id = adserve_variable('tids')) { | |
50 $type = 'taxonomy'; | |
51 } | |
52 else { | |
53 $type = 'default'; | |
54 $id = 0; | |
55 } | |
56 $aids = ad_cache_memcache_get_ids($type, $id); | |
57 $group = $id; | |
58 } | |
59 adserve_variable('group', $group); | |
60 | |
61 if (adserve_variable('debug')) { | |
62 echo 'Memcache: selecting from the following ad id(s): '; | |
63 if (empty($aids)) { | |
64 echo 'none.<br />'; | |
65 } | |
66 else { | |
67 echo implode(', ', $aids) .'.<br />'; | |
68 } | |
69 } | |
70 | |
71 $ids = adserve_variable("$type-ids"); | |
72 if ($ids == NULL) { | |
73 $ids = array(); | |
74 } | |
75 | |
76 $output = ''; | |
77 $selected = adserve_select_ad($aids, adserve_variable('quantity'), $ids); | |
78 adserve_variable("$type-ids", array_merge($selected, $ids)); | |
79 foreach ($selected as $aid) { | |
80 if ($aid = (int)$aid) { | |
81 $ad = ad_cache_memcache_get_ad($aid); | |
82 | |
83 if (!empty($output)) { | |
84 $display_count++; | |
85 $output .= "<div class=\"space\" id=\"$id-$displayed_count\"></div>"; | |
86 } | |
87 | |
88 $output .= $ad->display; | |
89 } | |
90 else { | |
91 $ad = array(); | |
92 } | |
93 | |
94 _debug_echo("Displaying AID: $aid."); | |
95 $action = $aid ? 'view' : 'count'; | |
96 ad_cache_memcache_increment($action, $aid, $group, $hostid, $ad); | |
97 } | |
98 if (empty($output)) { | |
99 adserve_variable('error', TRUE); | |
100 $output = 'No active ads were found in the '. (empty($nids) ? 'tids' : 'nids') ." '$id'."; | |
101 _debug_echo("Memcache: {$output}"); | |
102 } | |
103 } | |
104 else { | |
105 _debug_echo("Memcache: invalid hostid: '$hostid'."); | |
106 $output = 'You do not have permission to display ads.'; | |
107 } | |
108 | |
109 return $output; | |
110 } | |
111 | |
112 function ad_cache_memcache_hook(&$cache, $hook, $func) { | |
113 | |
114 if (empty($cache)) { | |
115 _debug_echo('Memcache: retrieving hook info from cache.'); | |
116 $cache = ad_memcache_get('ad-cache-hook'); | |
117 } | |
118 $include_func = NULL; | |
119 if (is_array($cache) && !empty($cache)) { | |
120 $include_file = adserve_variable('root_dir') .'/'. $cache[$hook]; | |
121 if (file_exists($include_file) && is_file($include_file)) { | |
122 _debug_echo("Memcache: including external file: '$include_file'."); | |
123 include_once($include_file); | |
124 } | |
125 else if (is_file($include_file)) { | |
126 _debug_echo("Memcache: unable to find external file: '$include_file'."); | |
127 } | |
128 else { | |
129 _debug_echo('Memcache: no include file defined in cache.'); | |
130 } | |
131 $include_func = $cache[$func]; | |
132 if ($include_func) { | |
133 _debug_echo("Memcache: returning requested func($func): '$include_func'."); | |
134 } | |
135 } | |
136 return ($include_func); | |
137 } | |
138 | |
139 function ad_cache_memcache_get_ids($op = 'default', $id = 0) { | |
140 switch ($op) { | |
141 | |
142 case 'node': { | |
143 $ids = explode(',', $id); | |
144 break; | |
145 } | |
146 | |
147 case 'taxonomy': { | |
148 $ids = ad_memcache_get("ad-taxonomy-cache-$id"); | |
149 if (!$ids || empty($ids)) { | |
150 $taxonomy = ad_memcache_get('ad-taxonomy'); | |
151 $cache = array(); | |
152 $ids = explode(',', $id); | |
153 foreach ($ids as $tid) { | |
154 if (is_array($taxonomy[$tid])) { | |
155 $cache += $taxonomy[$tid]; | |
156 } | |
157 } | |
158 // Rebuild keys from 0, cache for quick re-use on next ad display. | |
159 $ids = array_values($cache); | |
160 ad_memcache_set("ad-taxonomy-cache-$id", $ids); | |
161 } | |
162 break; | |
163 } | |
164 | |
165 default: { | |
166 $taxonomy = ad_memcache_get('ad-taxonomy'); | |
167 $ids = $taxonomy[0]; | |
168 break; | |
169 } | |
170 | |
171 } | |
172 | |
173 return $ids; | |
174 } | |
175 | |
176 function ad_cache_memcache_get_ad($aid) { | |
177 static $load = FALSE; | |
178 | |
179 $ad = ad_memcache_get("ad-aid-$aid"); | |
180 | |
181 if (!$load && !is_object($ad)) { | |
182 $load = TRUE; | |
183 adserve_bootstrap(); | |
184 $ad_memcache_build = variable_get('ad_memcache_build', ''); | |
185 if ((time() - $ad_memcache_build) >= 60) { | |
186 ad_cache_memcache_build(); | |
187 } | |
188 } | |
189 | |
190 return $ad; | |
191 } | |
192 | |
193 /** | |
194 * Increment impressions counter in memcache. | |
195 */ | |
196 function ad_cache_memcache_increment($action, $aid, $group = '', $hostid = '', $ad = array()) { | |
197 static $timestamp = NULL; | |
198 | |
199 _debug_echo("Memcache: increment action($action) aid($aid) group($group) hostid($hostid)."); | |
200 | |
201 if ($aid && !is_object($ad)) { | |
202 _debug_echo("Invalid ad id: $aid."); | |
203 return (0); | |
204 } | |
205 | |
206 if (!isset($timestamp)) { | |
207 $timestamp = date('YmdH'); | |
208 } | |
209 $counters = ad_memcache_get("ad-counters-$aid"); | |
210 | |
211 $update = TRUE; | |
212 if (!is_array($counters) || !isset($counters["$action:$group:$hostid:$timestamp"])) { | |
213 _debug_echo("Memcache: adding map: action($action) aid($aid) group($group) hostid($hostid) timestamp($timestamp)"); | |
214 ad_memcache_increment_map($action, $aid, $group, $hostid, $timestamp); | |
215 } | |
216 | |
217 $rc = ad_memcache_increment("ad-$action-$aid-$group-$hostid-$timestamp"); | |
218 _debug_echo("Memcache: incrementing ad-$action-$aid-$group-$hostid-$timestamp ($rc)"); | |
219 } | |
220 | |
221 /** | |
222 * The maximum time any process can hold a given lock, in seconds. | |
223 */ | |
224 define('AD_MEMCACHE_LOCK_LIMIT', 2); | |
225 | |
226 /** | |
227 * Store a value in memcache. | |
228 */ | |
229 function ad_memcache_set($key, $value, $timeout = 86400) { | |
230 $memcache = ad_memcache_init(); | |
231 | |
232 return $memcache->set($key, $value, MEMCACHE_COMPRESSED, $timeout); | |
233 } | |
234 | |
235 /** | |
236 * Store a value in memcache. | |
237 */ | |
238 function ad_memcache_add($key, $value, $timeout = 86400) { | |
239 $memcache = ad_memcache_init(); | |
240 | |
241 return $memcache->add($key, $value, MEMCACHE_COMPRESSED, $timeout); | |
242 } | |
243 | |
244 /** | |
245 * Get a value from memcache. | |
246 */ | |
247 function ad_memcache_get($key) { | |
248 $memcache = ad_memcache_init(); | |
249 | |
250 return $memcache->get($key); | |
251 } | |
252 | |
253 /** | |
254 * Delete a value from memcache. | |
255 */ | |
256 function ad_memcache_delete($key) { | |
257 $memcache = ad_memcache_init(); | |
258 | |
259 return $memcache->delete($key); | |
260 } | |
261 | |
262 /** | |
263 * Get a lock in memcache. | |
264 */ | |
265 function ad_memcache_lock($key, $wait = TRUE) { | |
266 $loop = 0; | |
267 $lock = FALSE; | |
268 while ($lock == FALSE) { | |
269 $lock = ad_memcache_add("LOCK-$key-LOCK", TRUE, AD_MEMCACHE_LOCK_LIMIT); | |
270 if (!$lock && $wait) { | |
271 if ($loop++ > 50) { | |
272 // Hard limit of 5 seconds, after which we fail to grab a lock. | |
273 return FALSE; | |
274 } | |
275 // Wait 1/10th of a second and try again. | |
276 usleep(100000); | |
277 } | |
278 else if (!$lock && !$wait) { | |
279 return FALSE; | |
280 } | |
281 } | |
282 return TRUE; | |
283 } | |
284 | |
285 /** | |
286 * Release a lock in memcache. | |
287 */ | |
288 function ad_memcache_unlock($key) { | |
289 ad_memcache_delete("LOCK-$key-LOCK"); | |
290 } | |
291 | |
292 /** | |
293 * Increment a numerical value in memcache. | |
294 */ | |
295 function ad_memcache_increment($key, $value = 1) { | |
296 $memcache = ad_memcache_init(); | |
297 | |
298 $rc = $memcache->increment($key, $value); | |
299 if ($rc === FALSE) { | |
300 // We tried incrementing a counter that hasn't yet been initialized. | |
301 $rc = $memcache->set($key, $value); | |
302 if ($rc === FALSE) { | |
303 // Another process already initialized the counter, increment it. | |
304 $rc = $memcache->increment($key); | |
305 } | |
306 } | |
307 return $rc; | |
308 } | |
309 | |
310 /** | |
311 * Decrement a numerical value in memcache. | |
312 */ | |
313 function ad_memcache_decrement($key, $value = 1) { | |
314 $memcache = ad_memcache_init(); | |
315 | |
316 $rc = $memcache->decrement($key, $value); | |
317 if ($rc === FALSE) { | |
318 // We tried incrementing a counter that hasn't yet been initialized. | |
319 $rc = $memcache->set($key, $value); | |
320 if ($rc === FALSE) { | |
321 // Another process already initialized the counter, increment it. | |
322 $rc = $memcache->decrement($key); | |
323 } | |
324 } | |
325 return $rc; | |
326 } | |
327 | |
328 /** | |
329 * Update mapping which allows us to quickly find stats in memcache when | |
330 * feeding them into the database. | |
331 */ | |
332 function ad_memcache_increment_map($action, $aid, $group, $hostid, $timestamp) { | |
333 $key = "ad-counters-$aid"; | |
334 if (ad_memcache_lock($key)) { | |
335 $counters = ad_memcache_get($key); | |
336 if (!is_array($counters) || !isset($counters["$action:$group:$hostid:$timestamp"])) { | |
337 $counters["$action:$group:$hostid:$timestamp"] = "$action:$group:$hostid:$timestamp"; | |
338 ad_memcache_set($key, $counters); | |
339 } | |
340 ad_memcache_unlock($key); | |
341 } | |
342 } | |
343 | |
344 /** | |
345 * Decrement a numerical value in memcache. | |
346 * TODO: Use the same configuration style as Drupal's memcache module, | |
347 * supporting multiple memcache servers, etc. | |
348 */ | |
349 function ad_memcache_init() { | |
350 static $memcache = NULL; | |
351 | |
352 if (!$memcache) { | |
353 $memcache = new Memcache; | |
354 $memcache->addServer('localhost', 11211); | |
355 } | |
356 return $memcache; | |
357 } | |
358 | |
359 /** | |
360 * Allow external ad selection logic. | |
361 */ | |
362 function ad_cache_memcache_adserve_select($ads, $invalid) { | |
363 $cache = array(); | |
364 if ($select_func = ad_cache_memcache_hook($cache, 'include_file_select', 'include_func_select')) { | |
365 _debug_echo("Memcache: adserve_select: invoking '$select_func()'"); | |
366 if (function_exists($select_func)) { | |
367 if (is_array($cache) && !empty($cache)) { | |
368 return $select_func($ads, $invalid, $cache); | |
369 } | |
370 else { | |
371 _debug_echo("Memcache: unexpected error: cache empty."); | |
372 } | |
373 } | |
374 else { | |
375 _debug_echo("Memcache: adserve_select: '$include_func_select()' not found"); | |
376 } | |
377 } | |
378 else { | |
379 _debug_echo("Memcache: adserve_select: no select function defined"); | |
380 } | |
381 } | |
382 | |
383 /** | |
384 * Allow external exit text. | |
385 */ | |
386 function ad_cache_memcache_adserve_exit_text() { | |
387 $cache = array(); | |
388 if ($exit_text_func = ad_cache_memcache_hook($cache, 'include_file_exit_text', 'include_func_exit_text')) { | |
389 _debug_echo("Memcache: adserve_exit_text: invoking '$exit_text_func()'"); | |
390 if (function_exists($exit_text_func)) { | |
391 return $exit_text_func(); | |
392 } | |
393 else { | |
394 _debug_echo("Memcache: adserve_exit_text: '$exit_text_func()' not found"); | |
395 } | |
396 } | |
397 else { | |
398 _debug_echo("Memcache: adserve_exit_text: no exit_text function defined"); | |
399 } | |
400 } | |
401 |