Index: includes/session.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/session.inc,v
retrieving revision 1.40
diff -u -p -r1.40 session.inc
--- includes/session.inc	25 May 2007 15:04:41 -0000	1.40
+++ includes/session.inc	29 Jun 2007 04:06:14 -0000
@@ -75,9 +75,8 @@ function sess_write($key, $value) {
   else {
     db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time(), $key);
 
-    // TODO: this can be an expensive query. Perhaps only execute it every x minutes. Requires investigation into cache expiration.
     if ($user->uid) {
-      db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid);
+      db_query("UPDATE {users_access} SET access = %d WHERE uid = %d", time(), $user->uid);
     }
   }
 
Index: modules/profile/profile.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/profile/profile.module,v
retrieving revision 1.210
diff -u -p -r1.210 profile.module
--- modules/profile/profile.module	28 Jun 2007 00:29:05 -0000	1.210
+++ modules/profile/profile.module	29 Jun 2007 04:06:14 -0000
@@ -496,7 +496,7 @@ function profile_browse() {
     }
 
     // Extract the affected users:
-    $result = pager_query("SELECT u.uid, u.access FROM {users} u INNER JOIN {profile_values} v ON u.uid = v.uid WHERE v.fid = %d AND $query AND u.access != 0 AND u.status != 0 ORDER BY u.access DESC", 20, 0, NULL, $arguments);
+    $result = pager_query("SELECT u.uid, ua.access FROM {users} u INNER JOIN {users_access} ua ON u.uid = ua.uid INNER JOIN {profile_values} v ON u.uid = v.uid WHERE v.fid = %d AND $query AND ua.access != 0 AND u.status != 0 ORDER BY ua.access DESC", 20, 0, NULL, $arguments);
 
     $output = '<div id="profile">';
     while ($account = db_fetch_object($result)) {
@@ -529,7 +529,7 @@ function profile_browse() {
     }
 
     // Extract the affected users:
-    $result = pager_query('SELECT uid, access FROM {users} WHERE uid > 0 AND status != 0 AND access != 0 ORDER BY access DESC', 20, 0, NULL);
+    $result = pager_query('SELECT u.uid, ua.access FROM {users} u INNER JOIN {users_access} ua ON u.uid = ua.uid WHERE u.uid > 0 AND u.status != 0 AND ua.access != 0 ORDER BY ua.access DESC', 20, 0, NULL);
 
     $output = '<div id="profile">';
     while ($account = db_fetch_object($result)) {
Index: modules/user/user.install
===================================================================
RCS file: modules/user/user.install
diff -N modules/user/user.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/user/user.install	29 Jun 2007 04:06:15 -0000
@@ -0,0 +1,36 @@
+<?php
+// $Id:$
+
+// Installation of user table is done by system.install.
+
+/**
+ * Moves access field and login field from users table to users_access table.
+ */
+function user_update_2000() {
+  $ret = array();
+
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("CREATE TABLE {users_access} SELECT uid, access, login FROM {users}");
+      $ret[] = update_sql("ALTER TABLE {users_access} ADD PRIMARY KEY uid (uid)");
+      $ret[] = update_sql("ALTER TABLE {users_access} ADD KEY access access");
+      $ret[] = update_sql("ALTER TABLE {users} DROP access");
+      $ret[] = update_sql("ALTER TABLE {users} DROP login");
+      break;
+    case 'pgsql':
+      $ret[] = update_sql("CREATE TABLE {users_access} (
+        uid int_unsigned default '0',
+        access int_unsigned NOT NULL default '0',
+        login int_unsigned NOT NULL default '0',
+        PRIMARY KEY (uid),
+        KEY (access)
+      )");
+      $ret[] = update_sql("INSERT INTO {users_access} (uid, access, login) SELECT uid, access, login FROM {users}");
+      $ret[] = update_sql("ALTER TABLE {users} DROP access");
+      $ret[] = update_sql("ALTER TABLE {users} DROP login");
+      break;
+  }
+
+  return $ret;
+}
\ No newline at end of file
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.809
diff -u -p -r1.809 user.module
--- modules/user/user.module	28 Jun 2007 07:48:41 -0000	1.809
+++ modules/user/user.module	29 Jun 2007 04:06:15 -0000
@@ -115,6 +115,11 @@ function user_external_login($account, $
 /**
  * Fetch a user object.
  *
+ * The user's last login time (login) and last access time (access) are stored in the 
+ * users_access table and retrieved as a separate query within hook_user() to prevent 
+ * read/write lock contentions and increase the lifetime a user query can be cached by 
+ * the database.
+ *
  * @param $array
  *   An associative array of attributes to search for in selecting the
  *   user, such as user name or e-mail address.
@@ -271,7 +276,7 @@ function user_save($account, $array = ar
           break;
         case 'mode':     case 'sort':
         case 'threshold':  case 'created':  case 'access':
-        case 'login':      case 'status':
+        case 'status':
           $fields[] = $key;
           $values[] = $value;
           $s[] = "%d";
@@ -478,7 +483,7 @@ function user_fields() {
     }
     else {
       // Make sure we return the default fields at least
-      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
+      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'status', 'timezone', 'language', 'init', 'data');
     }
   }
 
@@ -540,6 +545,15 @@ function user_search($op = 'search', $ke
  * Implementation of hook_user().
  */
 function user_user($type, &$edit, &$account, $category = NULL) {
+  if ($type == 'load' && $account->uid != 0) {
+    $u = db_fetch_object(db_query('SELECT access, login FROM {users_access} WHERE uid = %d', $account->uid));
+    // When user 1 registers, $u is NULL.
+    if ($u) {
+      $account->access = $u->access;
+      $account->login = $u->login;
+    }
+    return;
+  }
   if ($type == 'view') {
     $account->content['user_picture'] = array(
       '#value' => theme('user_picture', $account),
@@ -573,6 +587,10 @@ function user_user($type, &$edit, &$acco
     return _user_edit_submit(arg(1), $edit);
   }
 
+  if ($type == 'insert') {
+    db_query('INSERT INTO {users_access} (access, uid) VALUES (%d, %d)', time(), $account->uid);
+  }
+
   if ($type == 'categories') {
     return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
   }
@@ -669,7 +687,7 @@ function user_block($op = 'list', $delta
       case 2:
         if (user_access('access content')) {
           // Retrieve a list of new users who have subsequently accessed the site successfully.
-          $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 AND access != 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5));
+          $result = db_query_range('SELECT u.uid, u.name FROM {users} u INNER JOIN {users_access} ua ON u.uid = ua.uid WHERE u.status != 0 AND ua.access != 0 ORDER BY u.created DESC', 0, variable_get('user_block_whois_new_count', 5));
           while ($account = db_fetch_object($result)) {
             $items[] = $account;
           }
@@ -1156,7 +1174,7 @@ function user_login_submit($form, &$form
     watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
 
     // Update the user table timestamp noting user has logged in.
-    db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $user->uid);
+    db_query("UPDATE {users_access} SET login = %d WHERE uid = %d", time(), $user->uid);
 
     user_module_invoke('login', $form_state['values'], $user);
 
@@ -2202,7 +2220,7 @@ function user_admin_account() {
     t('Operations')
   );
 
-  $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, u.access FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
+  $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, ua.access FROM {users} u INNER JOIN {users_access} ua ON u.uid = ua.uid LEFT JOIN {users_roles} ur ON u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
   $sql .= tablesort_sql($header);
   $result = pager_query($sql, 50, 0, NULL, $filter['args']);
 
Index: modules/user/user.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.schema,v
retrieving revision 1.2
diff -u -p -r1.2 user.schema
--- modules/user/user.schema	15 Jun 2007 07:15:25 -0000	1.2
+++ modules/user/user.schema	29 Jun 2007 04:06:15 -0000
@@ -55,8 +55,6 @@ function user_schema() {
       'theme'     => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'signature' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'created'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'access'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
-      'login'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'status'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
       'timezone'  => array('type' => 'varchar', 'length' => 8, 'not null' => FALSE),
       'language'  => array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''),
@@ -65,13 +63,25 @@ function user_schema() {
       'data'      => array('type' => 'text', 'not null' => FALSE, 'size' => 'medium')
     ),
     'indexes' => array(
-      'access'  => array('access'),
       'created' => array('created')
     ),
     'unique keys' => array('name' => array('name')),
     'primary key' => array('uid'),
   );
 
+  $schema['users_access'] = array(
+    'fields' => array(
+      'uid'       => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'access'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'login'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+    ),
+    'indexes' => array(
+      'uid'  => array('uid'),
+      'access' => array('access')
+    ),
+    'primary key' => array('uid'),
+  );
+
   $schema['users_roles'] = array(
     'fields' => array(
       'uid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
