/[drupal]/contributions/modules/ad_memcache/ad_memcache.module
ViewVC logotype

Contents of /contributions/modules/ad_memcache/ad_memcache.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Sat Apr 18 03:04:23 2009 UTC (7 months, 1 week ago) by jeremy
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--2
File MIME type: text/x-php
Branched 6.x from 5.x-1.7, removed from core ad module (too many people were
blindly enabling this module and then running into problems if they didn't
have memcached installed).
1 <?php
2 // $Id: ad_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_help().
14 */
15 function ad_memcache_help($path, $arg) {
16 $output = '';
17 switch ($path) {
18 case 'admin/modules#description':
19 $output = t('Utilize memcached to improve the performance of the ad module.');
20 break;
21
22 }
23 return $output;
24 }
25
26 /**
27 * Implementation of hook_adcacheapi().
28 */
29 function ad_memcache_adcacheapi($op, &$node = array()) {
30 switch ($op) {
31 case 'method':
32 ad_memcache_sync();
33 ad_memcache_build();
34 return array('memcache' => t('Memcache'));
35 case 'description':
36 return t('Memcache allows improved performance by caching data directly in RAM.');
37 case 'settings':
38 $form['memcache'] = array(
39 '#type' => 'fieldset',
40 '#title' => t('Memcache settings'),
41 '#collapsible' => TRUE,
42 '#collapsed' => (variable_get('ad_cache', 'none') == 'memcache') ? FALSE : TRUE,
43 );
44 $period = drupal_map_assoc(array(60,120,180,240,300,600,900,1800,2700,3600,10800,21600,43200,86400), 'format_interval');
45 $form['memcache']['ad_memcache_sync'] = array(
46 '#type' => 'select',
47 '#title' => t('Sync frequency'),
48 '#default_value' => variable_get('ad_memcache_sync', 600),
49 '#options' => $period,
50 '#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.'),
51 );
52 // Sanity tests...
53 if (variable_get('ad_cache', 'none') == 'memcache') {
54 $sync = variable_get('ad_memcache_sync', 600);
55 $cron_last = variable_get('cron_last', NULL);
56 if (is_numeric($cron_last)) {
57 if (time() - $cron_last > $sync) {
58 drupal_set_message(t('Memcache warning: your last cron run was !time ago. Advertisement impression 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>. You can also !manually.', array('@url' => 'http://drupal.org/cron', '!sync' => format_interval($sync), '!time' => format_interval(time() - $cron_last), '!manually' => l(t('run cron manually'), 'admin/reports/status/run-cron', array('query' => drupal_get_destination())))), 'error');
59 }
60 }
61 else {
62 drupal_set_message(t('Memcache warning: Cron has not run. Advertisement impression 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>. You can also !manually.', array('@url' => 'http://drupal.org/cron', '!manually' => l(t('run cron manually'), 'admin/reports/status/run-cron', array('query' => drupal_get_destination())))), 'error');
63 }
64 }
65 return $form;
66 case 'settings_submit':
67 variable_set('ad_memcache_sync', $node['ad_memcache_sync']);
68 break;
69
70 case 'insert':
71 case 'update':
72 case 'delete':
73 if (variable_get('ad_cache', 'none') == 'memcache') {
74 ad_memcache_sync_ad($node->nid);
75 ad_memcache_build($node);
76 }
77 break;
78 }
79 }
80
81 /**
82 * Regularily syncronize counters into RAM.
83 */
84 function ad_memcache_cron() {
85 $ad_memcache_timestamp = variable_get('ad_memcache_timestamp', '');
86 if ((time() - $ad_memcache_timestamp) >= variable_get('ad_memcache_sync', 000)) {
87 require_once(drupal_get_path('module', 'ad') .'/adserve.inc');
88 ad_memcache_sync();
89 }
90
91 $ad_memcache_build = variable_get('ad_memcache_build', '');
92 // rebuild cache every 12 hours
93 // TODO: Make configurable
94 if ((time() - $ad_memcache_build) >= 43200 || TRUE) {
95 ad_memcache_build();
96 }
97 }
98
99 /**
100 * Load advertisements into memory.
101 */
102 function ad_memcache_sync() {
103 variable_set('ad_memcache_timestamp', time());
104 if (_ad_memcache_invoke('validate')) {
105 $result = db_query("SELECT aid, adtype FROM {ads} WHERE adstatus = 'active'");
106 while ($ad = db_fetch_object($result)) {
107 ad_memcache_sync_ad($ad->aid);
108 }
109 // Sync counters.
110 ad_memcache_sync_ad(0);
111 }
112 else {
113 drupal_set_message(t('!module: Unable to syncronize cache.', array('!module' => 'ad_memcache.module')), 'error');
114 }
115 }
116
117 /**
118 * Syncronize counts for given advertisement with database.
119 */
120 function ad_memcache_sync_ad($aid) {
121 if (!_ad_memcache_invoke('validate')) {
122 drupal_set_message(t('!module: Unable to syncronize cache.', array('!module' => 'ad_memcache.module')), 'error');
123 return;
124 }
125
126 if (!ad_memcache_lock("ad-counters-$aid")) {
127 // Another process is already updating these values.
128 return;
129 }
130 $counters = ad_memcache_get("ad-counters-$aid");
131 if (!is_array($counters)) {
132 ad_memcache_unlock("ad-counters-$aid");
133 // There's nothing currently in memory for this ad.
134 return;
135 }
136 ad_memcache_delete("ad-counters-$aid");
137 ad_memcache_unlock("ad-counters-$aid");
138 foreach ($counters as $map) {
139 list($action, $group, $hostid, $extra, $timestamp) = explode(':', $map);
140 if ($action && isset($group) && $hostid && $timestamp) {
141 $count = ad_memcache_get("ad-$action-$aid-$group-$hostid-$extra-$timestamp");
142 if ($count) {
143 ad_memcache_decrement("ad-$action-$aid-$group-$hostid-$extra-$timestamp", $count);
144 db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s' AND extra = '%s'", $count, $aid, $action, $timestamp, $group, $hostid, $extra);
145 // If column doesn't already exist, we need to add it.
146 if (!db_affected_rows()) {
147 db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, hostid, count, extra) VALUES(%d, %d, '%s', '%s', '%s', '%s', %d)", $aid, $timestamp, $action, $group, $hostid, $extra, $count);
148 // If another process already added this row our INSERT will fail, if
149 // so we still need to increment it so we don't loose a count.
150 if (!db_affected_rows()) {
151 db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s' AND extra = '%s'", $count, $aid, $action, $timestamp, $group, $hostid, $extra);
152 }
153 }
154 }
155 // If counting ad impressions, see if we've hit a limit
156 if ($action = 'view') {
157 $limits = db_fetch_object(db_query('SELECT activated, maxviews, maxclicks, adstatus FROM {ads} WHERE aid = %d', $aid));
158 if ($limits->adstatus == 'active') {
159 if ($limits->maxviews) {
160 $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)));
161 if ($views >= $limits->maxviews) {
162 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
163 ad_statistics_increment($aid, 'autoexpired');
164 ad_statistics_increment($aid, 'expired');
165 }
166 }
167 if ($limits->maxclicks) {
168 $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)));
169 if ($clicks >= $limits->maxclicks) {
170 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
171 ad_statistics_increment($aid, 'autoexpired');
172 ad_statistics_increment($aid, 'expired');
173 }
174 }
175 }
176 }
177 }
178 }
179 }
180
181 /**
182 * Caches ad information into memory.
183 */
184 function ad_memcache_build($changed = NULL) {
185 variable_set('ad_memcache_build', time());
186 if (!_ad_memcache_invoke('validate')) {
187 drupal_set_message(t('!module: Unable to build cache.', array('!module' => 'ad_memcache.module')), 'error');
188 return;
189 }
190
191 if (is_object($changed) && isset($changed->aid)) {
192 // An advertisement has changed, rebuild cache on next cron run.
193 variable_set('ad_memcache_build', '');
194 }
195 else {
196 // Rebuilding entire cache.
197 $result = db_query("SELECT aid, adtype, redirect FROM {ads} WHERE adstatus = 'active' OR adstatus = 'approved' OR adstatus = 'offline'");
198 while ($ad = db_fetch_object($result)) {
199 $node = node_load($ad->aid);
200 $ad->display = module_invoke("ad_$ad->adtype", 'display_ad', $node);
201 ad_memcache_set("ad-aid-$ad->aid", $ad);
202 $ads[$ad->aid] = $ad->aid;
203
204 // Owner indexes.
205 $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);
206 $counter = 0;
207 while ($owner = db_fetch_object($ad_owners)) {
208 $owners[$owner->uid][$ad->aid] = $ad->aid;
209 ad_memcache_set("ad-$ad->aid-uid", $owner->uid);
210 }
211
212 $match = FALSE;
213 // Taxonomy index.
214 $terms = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $ad->aid);
215 while ($term = db_fetch_object($terms)) {
216 $taxonomy[$term->tid][$ad->aid] = $ad->aid;
217 $match = TRUE;
218 }
219 if (!$match) {
220 $taxonomy[0][] = $ad->aid;
221 }
222 }
223 ad_memcache_set("ad-ads", $ads);
224 ad_memcache_set("ad-owners", $owners);
225 ad_memcache_set("ad-taxonomy", $taxonomy);
226
227 // HostID index
228 $owners = db_query('SELECT uid, hostid FROM {ad_hosts}');
229 while ($owner = db_fetch_object($owners)) {
230 ad_memcache_set("ad-hosts-$owner->uid", $owner->hostid);
231 if (($user = user_load(array('uid' => $owner->uid))) &&
232 (user_access('host remote advertisements', $user))) {
233 ad_memcache_set("ad-hostid-$owner->hostid", TRUE);
234 }
235 }
236
237 _debug_echo('Ad memcache: invoking external ad_build_cache hooks.');
238 $cache = array();
239 $external = module_invoke_all('ad_build_cache');
240 // TODO: Move helper function adserve_cache_build_hooks from adcache.inc to
241 // ad.module to share.
242 foreach ($external as $module => $return) {
243 // supported cache hooks
244 foreach (array('hook_init', 'hook_filter', 'hook_weight', 'hook_select',
245 'hook_init_text', 'hook_exit_text',
246 'hook_increment_extra') as $hook) {
247 if (isset($return[$hook]) && is_array($return[$hook])) {
248 $weight = isset($return[$hook]['weight']) ? (int)$return[$hook]['weight'] : 0;
249 $cache[$hook]['file'][$weight][] = $return[$hook]['file'];
250 $cache[$hook]['function'][$weight][] = $return[$hook]['function'];
251 unset($external[$module][$hook]);
252 }
253 }
254 }
255 $cache['external-hooks'] = $external;
256 // Always invoke hooks, they can decide to queue or act immediately.
257 ad_memcache_set('ad-cache-hooks', $cache);
258
259 }
260 }
261
262 function _ad_memcache_invoke($function = 'validate') {
263 if ($function == 'validate') {
264 if (!function_exists('memcache_add_server')) {
265 drupal_set_message(t('Memcache is not !installed. Ad cache memcache can not be used.', array('!installed' => l(t('properly installed'), 'admin/reports/status')), 'error'));
266 return FALSE;
267 }
268 }
269 require_once(drupal_get_path('module', 'ad_memcache') .'/ad_cache_memcache.inc');
270 return TRUE;
271 }
272

  ViewVC Help
Powered by ViewVC 1.1.2