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