comparison cache/memcache/ad_cache_memcache.module @ 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.module,v 1.1.2.9.2.6 2009/02/16 23:12:28 jeremy Exp $
3
4 /**
5 * @file
6 * A plug in for the ad.module, integrating the ad module with memcache.
7 *
8 * Copyright (c) 2005-2009.
9 * Jeremy Andrews <jeremy@tag1consulting.com>.
10 */
11
12 /**
13 * Implementation of hook_requirements().
14 */
15 function ad_cache_memcache_requirements($phase = NULL) {
16 include_once './includes/install.inc';
17 // Connect to memcached so we can retrieve its version.
18 if (function_exists('memcache_add_server')) {
19 require_once(drupal_get_path('module', 'ad_cache_memcache') .'/ad_cache_memcache.inc');
20 $memcache = ad_memcache_init();
21 // Retrieve the version of memcache.
22 if (function_exists('memcache_get_version')) {
23 $severity = REQUIREMENT_OK;
24 $value = memcache_get_version($memcache);
25 }
26 else {
27 $severity = REQUIREMENT_ERROR;
28 $value = t('Memcache installation not valid, %function not found.', array('%function' => 'memcache_get_version'));
29 }
30 }
31 else {
32 $severity = REQUIREMENT_ERROR;
33 $value = t('Memcache is not installed, %function not found.', array('%function' => 'memcache_add_server'));
34 }
35
36 if ($phase) {
37 return array(
38 'memcache' => array(
39 'title' => t('Memcache'),
40 'value' => $value,
41 'severity' => $severity,
42 ),
43 );
44 }
45 else {
46 if ($severity == REQUIREMENT_OK) {
47 return TRUE;
48 }
49 else {
50 return $value;
51 }
52 }
53 }
54
55 /**
56 * Implementation of hook_help().
57 */
58 function ad_cache_memcache_help($path, $arg) {
59 $output = '';
60 switch ($path) {
61 case 'admin/modules#description':
62 $output = t('Utilize memcached to improve the performance of the ad module.');
63 break;
64
65 }
66 return $output;
67 }
68
69 /**
70 * Implementation of hook_adcacheapi().
71 */
72 function ad_cache_memcache_adcacheapi($op, &$node = array()) {
73 switch ($op) {
74 case 'method':
75 ad_cache_memcache_sync();
76 ad_cache_memcache_build();
77 return array('memcache' => t('Memcache'));
78 case 'description':
79 return t('Memcache allows improved performance by caching data directly in RAM.');
80 case 'settings':
81 $form['memcache'] = array(
82 '#type' => 'fieldset',
83 '#title' => t('Memcache settings'),
84 '#collapsible' => TRUE,
85 '#collapsed' => (variable_get('ad_cache', 'none') == 'memcache') ? FALSE : TRUE,
86 );
87 $period = drupal_map_assoc(array(60,120,180,240,300,600,900,1800,2700,3600,10800,21600,43200,86400), 'format_interval');
88 $form['memcache']['ad_cache_memcache_sync'] = array(
89 '#type' => 'select',
90 '#title' => t('Sync frequency'),
91 '#default_value' => variable_get('ad_cache_memcache_sync', 600),
92 '#options' => $period,
93 '#description' => t('Specify how often statistics stored in RAM should be synced to the database (requires cron runs with the same or greater frequency). The longer you store data in memcache, the more data you risk loosing in the event of a system failure. This configuration option is only relevant if memcache is enabled.'),
94 );
95 // Sanity tests...
96 if (variable_get('ad_cache', 'none') == 'memcache') {
97 $sync = variable_get('ad_cache_memcache_sync', 600);
98 $cron_last = variable_get('cron_last', NULL);
99 if (is_numeric($cron_last)) {
100 if (time() - $cron_last > $sync) {
101 drupal_set_message(t('Memcache warning: your last cron run was !time ago. Advertisement impressions data is only synchronized into the database when cron runs. You are risking data loss. To learn more about how Drupal cron works, please check the online help pages for <a href="@url">configuring cron jobs</a>.', array('@url' => 'http://drupal.org/cron', '!sync' => format_interval($sync), '!time' => format_interval(time() - $cron_last))), 'error');
102 }
103 }
104 else {
105 drupal_set_message(t('Memcache warning: Cron has not run. Advertisement impressions data is only synchronized into the database when cron runs. You are risking data loss. It appears cron jobs have not been setup on your system. Please check the help pages for <a href="@url">configuring cron jobs</a>.', array('@url' => 'http://drupal.org/cron')), 'error');
106 }
107 }
108 return $form;
109 case 'settings_submit':
110 variable_set('ad_cache_memcache_sync', $node['ad_cache_memcache_sync']);
111 break;
112
113 case 'insert':
114 case 'update':
115 case 'delete':
116 if (variable_get('ad_cache', 'none') == 'memcache') {
117 ad_cache_memcache_sync_ad($node->nid);
118 ad_cache_memcache_build($node);
119 }
120 break;
121 }
122 }
123
124 /**
125 * Regularily syncronize counters into RAM.
126 */
127 function ad_cache_memcache_cron() {
128 $ad_memcache_timestamp = variable_get('ad_memcache_timestamp', '');
129 if ((time() - $ad_memcache_timestamp) >= variable_get('ad_cache_memcache_sync', 600)) {
130 ad_cache_memcache_sync();
131 }
132
133 $ad_memcache_build = variable_get('ad_memcache_build', '');
134 // rebuild cache every 12 hours
135 // TODO: Make configurable
136 if ((time() - $ad_memcache_build) >= 43200) {
137 ad_cache_memcache_build();
138 }
139 }
140
141 /**
142 * Load advertisements into memory.
143 */
144 function ad_cache_memcache_sync() {
145 variable_set('ad_memcache_timestamp', time());
146 if (($error = ad_cache_memcache_requirements()) === TRUE) {
147 $result = db_query("SELECT aid, adtype FROM {ads} WHERE adstatus = 'active'");
148 while ($ad = db_fetch_object($result)) {
149 ad_cache_memcache_sync_ad($ad->aid);
150 }
151 // Sync counters.
152 ad_cache_memcache_sync_ad(0);
153 }
154 else {
155 drupal_set_message(t('!module: Unable to syncronize cache: !error', array('!module' => 'ad_cache_memcache.module', '!error' => $error)), 'error');
156 }
157 }
158
159 /**
160 * Syncronize counts for given advertisement with database.
161 */
162 function ad_cache_memcache_sync_ad($aid) {
163 if (($error = ad_cache_memcache_requirements()) !== TRUE) {
164 drupal_set_message(t('!module: Unable to syncronize cache: !error', array('!module' => 'ad_cache_memcache.module', '!error' => $error)), 'error');
165 return;
166 }
167
168 if (!ad_memcache_lock("ad-counters-$aid")) {
169 // Another process is already updating these values.
170 return;
171 }
172 $counters = ad_memcache_get("ad-counters-$aid");
173 if (!is_array($counters)) {
174 ad_memcache_unlock("ad-counters-$aid");
175 // There's nothing currently in memory for this ad.
176 return;
177 }
178 ad_memcache_delete("ad-counters-$aid");
179 ad_memcache_unlock("ad-counters-$aid");
180 foreach ($counters as $map) {
181 list($action, $group, $hostid, $timestamp) = explode(':', $map);
182 if ($action && $group && $hostid && $timestamp) {
183 $count = ad_memcache_get("ad-$action-$aid-$group-$hostid-$timestamp");
184 if ($count) {
185 ad_memcache_decrement("ad-$action-$aid-$group-$hostid-$timestamp", $count);
186 db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $count, $aid, $action, $timestamp, $group, $hostid);
187 // If column doesn't already exist, we need to add it.
188 if (!db_affected_rows()) {
189 db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, hostid, count) VALUES(%d, %d, '%s', '%s', '%s', %d)", $aid, $timestamp, $action, $group, $hostid, $count);
190 // If another process already added this row our INSERT will fail, if
191 // so we still need to increment it so we don't loose a count.
192 if (!db_affected_rows()) {
193 db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $count, $aid, $action, $timestamp, $group, $hostid);
194 }
195 }
196 }
197 // If counting ad impressions, see if we've hit a limit
198 if ($action = 'view') {
199 $limits = db_fetch_object(db_query('SELECT activated, maxviews, maxclicks, adstatus FROM {ads} WHERE aid = %d', $aid));
200 if ($limits->adstatus == 'active') {
201 if ($limits->maxviews) {
202 $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $limits->activated)));
203 if ($views >= $limits->maxviews) {
204 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
205 ad_statistics_increment($aid, 'autoexpired');
206 ad_statistics_increment($aid, 'expired');
207 }
208 }
209 if ($limits->maxclicks) {
210 $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, date('YmdH', $limits->activated)));
211 if ($clicks >= $limits->maxclicks) {
212 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
213 ad_statistics_increment($aid, 'autoexpired');
214 ad_statistics_increment($aid, 'expired');
215 }
216 }
217 }
218 }
219 }
220 }
221 }
222
223 /**
224 * Caches ad information into memory.
225 */
226 function ad_cache_memcache_build($changed = NULL) {
227 variable_set('ad_memcache_build', time());
228 if (($error = ad_cache_memcache_requirements()) !== TRUE) {
229 drupal_set_message(t('!module: Unable to build cache: !error', array('!module' => 'ad_cache_memcache.module', '!error' => $error)), 'error');
230 return;
231 }
232
233 if (is_object($changed) && isset($changed->aid)) {
234 // An advertisement has changed, rebuild cache on next cron run.
235 variable_set('ad_memcache_build', '');
236 }
237 else {
238 // Rebuilding entire cache.
239 $result = db_query("SELECT aid, adtype, redirect FROM {ads} WHERE adstatus = 'active' OR adstatus = 'approved' OR adstatus = 'offline'");
240 while ($ad = db_fetch_object($result)) {
241 $node = node_load($ad->aid);
242 $ad->display = module_invoke("ad_$ad->adtype", 'display_ad', $node);
243 ad_memcache_set("ad-aid-$ad->aid", $ad);
244 $ads[] = $ad->aid;
245
246 // Owner indexes.
247 $ad_owners = db_query('SELECT o.uid, h.hostid FROM {ad_owners} o LEFT JOIN {ad_hosts} h ON o.uid = h.uid WHERE aid = %d', $ad->aid);
248 $counter = 0;
249 while ($owner = db_fetch_object($ad_owners)) {
250 $owners[$owner->uid][$ad->aid] = $ad->aid;
251 ad_memcache_set("ad-$ad->aid-uid", $owner->uid);
252 }
253
254 $match = FALSE;
255 // Taxonomy index.
256 $terms = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $ad->aid);
257 while ($term = db_fetch_object($terms)) {
258 $taxonomy[$term->tid][$ad->aid] = $ad->aid;
259 $match = TRUE;
260 }
261 if (!$match) {
262 $taxonomy[0][] = $ad->aid;
263 }
264 }
265 ad_memcache_set("ad-ads", $ads);
266 ad_memcache_set("ad-owners", $owners);
267 ad_memcache_set("ad-taxonomy", $taxonomy);
268
269 // HostID index
270 $owners = db_query('SELECT uid, hostid FROM {ad_hosts}');
271 while ($owner = db_fetch_object($owners)) {
272 ad_memcache_set("ad-hosts-$owner->uid", $owner->hostid);
273 if (($user = user_load(array('uid' => $owner->uid))) &&
274 (user_access('host remote advertisements', $user))) {
275 ad_memcache_set("ad-hostid-$owner->hostid", TRUE);
276 }
277 }
278 // Always invoke hooks, they can decide to queue or act immediately.
279 ad_memcache_set('ad-cache-hook', module_invoke_all('ad_build_cache'));
280 }
281 }
282