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