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 |
