Index: visitor.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/visitor/visitor.install,v
retrieving revision 1.1
diff -u -p -r1.1 visitor.install
--- visitor.install	25 Oct 2008 07:52:38 -0000	1.1
+++ visitor.install	28 Oct 2008 18:02:28 -0000
@@ -32,14 +32,16 @@ function visitor_schema() {
         'default' => 0,
       ),
       'expire' => array(
-        'description' => t("Timestamp when vistor's cookie expires."),
+        'description' => t("Timestamp when visitor's cookie expires."),
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
       ),
     ),
-    // TODO: Indexes?
     'primary key' => array('visitor_id'),
+    'indexes' => array(
+      'cookie' => array('cookie'),
+    ),
   );
 
   return $schema;
Index: visitor.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/visitor/visitor.module,v
retrieving revision 1.1
diff -u -p -r1.1 visitor.module
--- visitor.module	25 Oct 2008 07:52:38 -0000	1.1
+++ visitor.module	28 Oct 2008 18:02:28 -0000
@@ -7,6 +7,14 @@
  */
 
 /**
+ * Include $base_path in visitor cookie name so a user can be a visitor in
+ * more than one Drupal site per domain without troubles (e.g., suppose
+ * one of the sites has a really short VISITOR_DEFAULT_EXPIRE).
+ */
+global $base_path;
+define('VISITOR_COOKIE', 'VISITOR_'. preg_replace('/[^a-zA-Z0-9_]/', '_', $base_path));
+
+/**
  * Default expire time for visitor cookies.
  */
 define('VISITOR_DEFAULT_EXPIRE', 3600);
@@ -27,10 +35,13 @@ function visitor_get_id() {
 
   // TODO: Make sure cookies are enabled. If not, return FALSE.
   // Validate the existing user's cookie.
-  if (isset($_COOKIE['visitor']) && $visitor_data = visitor_validate_id($_COOKIE['visitor'], $user)) {
+  if (isset($_COOKIE[VISITOR_COOKIE]) && $visitor_data = visitor_validate_id($_COOKIE[VISITOR_COOKIE], $user)) {
     // Looks okay; update the expire date of the cookie.
     $expire = variable_get('visitor_cookie_expire', VISITOR_DEFAULT_EXPIRE);
-    if ($expire) {
+    
+    // Last access time is updated no more frequently than once every 180 seconds.
+    // This reduces contention in the visitors table (see session_write()).
+    if ($expire && time() - $visitor_data['expire'] > variable_get('visitor_write_interval', 180)) {
       $visitor_data['expire'] = time() + $expire;
       db_query('UPDATE {visitor} SET expire = %d WHERE visitor_id = %d', $visitor_data['expire'], $visitor_data['visitor_id']);
     }
@@ -62,7 +73,7 @@ function visitor_set_id(&$account) {
   $key = uniqid(md5(mt_rand()), TRUE) . uniqid(md5(mt_rand()), TRUE);
   $cookie = md5(session_id() . $key);
   $expire = variable_get('visitor_cookie_expire', VISITOR_DEFAULT_EXPIRE);
-  setcookie('visitor', $cookie); //, $expire ? time() + $expire : 0);
+  setcookie(VISITOR_COOKIE, $cookie); //, $expire ? time() + $expire : 0);
 
   // Insert record into the database and return the information.
   db_query("INSERT INTO {visitor} (cookie, uid, expire) VALUES ('%s', %d, %d)", $cookie, $account->uid, $expire ? time() + $expire : 0);
@@ -85,6 +96,24 @@ function visitor_validate_id($cookie, $a
 }
 
 /**
+ * Delete a visitor. E.g., maybe we've discovered that
+ * the visitor does not accept cookies; no reason to have
+ * a record in the database, then.
+ */
+function visitor_delete_by_id($visitor_id) {
+  db_query('DELETE FROM {visitor} WHERE visitor_id = %d', $visitor_id);
+}
+
+/**
+ * Delete a visitor. E.g., maybe we've discovered that
+ * the visitor does not accept cookies; no reason to have
+ * a record in the database, then.
+ */
+function visitor_delete_by_cookie($cookie) {
+  db_query("DELETE FROM {visitor} WHERE cookie = '%s'", $cookie);
+}
+
+/**
  * Implementation of hook_menu().
  */
 function visitor_menu() {
@@ -124,13 +153,15 @@ function visitor_settings_form() {
 function visitor_user($op, &$edit, &$account, $category = NULL) {
   switch ($op) {
     case 'load':
-      // Nothing to do here?
+      // Nothing to do here because all of our stuff happens in hook_init().
       break;
     case 'login':
-      // Convert anonymous record to authenticated record. 
-      db_query('UPDATE {visitor} SET uid = %d WHERE visitor_id = %d', $account->uid, $accout->visitor['visitor_id']);     
+      // Convert anonymous record to authenticated record.
+      db_query('UPDATE {visitor} SET uid = %d WHERE visitor_id = %d', $account->uid, $account->visitor['visitor_id']);     
     case 'insert':
       // Add visitor record for users added via the admin panel?
+      // No, because they have not actually visited yet and thus
+      // don't have a cookie.
       break;
     case 'update':
       // Nothing to do here?
@@ -138,6 +169,7 @@ function visitor_user($op, &$edit, &$acc
     case 'delete':
       // Unset the uid associated with this user record when it is deleted.
       db_query('UPDATE {visitors} SET uid = 0 WHERE uid = %d', $account->uid);
+      // Notify other modules of visitor deletion here?
       break;
   }
 }
@@ -152,5 +184,11 @@ function visitor_cron() {
     db_query('DELETE FROM {visitor} WHERE expire < %d', time() - $expire);
 
     // TODO: Fire a hook as visitor records are cleared?
+    // Yeah, this is a problem because there's going to be a LOT
+    // of records. What are we going to do, delete them one by one
+    // and fire a hook for each one? See search_cron() for an approach
+    // that may work (as long as we can delete faster than records
+    // are being entered!). Probably most scalable to just let other
+    // modules handle the fact that they can't find a record?
   }
 }
