Index: modules/block/block.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.schema,v
retrieving revision 1.1
diff -u -r1.1 block.schema
--- modules/block/block.schema	25 May 2007 12:46:43 -0000	1.1
+++ modules/block/block.schema	23 Jun 2007 00:35:07 -0000
@@ -44,6 +44,8 @@
     'primary key' => array('bid'),
   );
 
+  $schema['cache_block'] = drupal_get_schema_unprocessed('system', 'cache');
+
   return $schema;
 }

Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.266
diff -u -r1.266 block.module
--- modules/block/block.module	22 Jun 2007 08:32:26 -0000	1.266
+++ modules/block/block.module	23 Jun 2007 00:27:41 -0000
@@ -13,6 +13,19 @@
 define('BLOCK_REGION_NONE', -1);
 
 /**
+ * Flags defining cache granularity for cached blocks.
+ *
+ * BLOCK_CACHE_CUSTOM lets modules define their own critrions
+ * using hook_block('cache_id').
+ */
+define('BLOCK_NO_CACHE', -1);
+define('BLOCK_CACHE_GLOBAL', 0x0001);
+define('BLOCK_CACHE_PER_PAGE', 0x0002);
+define('BLOCK_CACHE_PER_USER', 0x0004);
+define('BLOCK_CACHE_PER_ROLE', 0x0008);
+define('BLOCK_CACHE_CUSTOM', 0x0010);
+
+/**
  * Implementation of hook_help().
  */
 function block_help($section) {
@@ -217,7 +230,7 @@
 /**
  * Generate main block administration form.
  */
-function block_admin_display($theme = NULL) {
+function block_admin_display(&$form_state, $theme = NULL) {
   global $theme_key, $custom_theme;
 
   // Add CSS
@@ -379,7 +392,7 @@
 /**
  * Menu callback; displays the block configuration form.
  */
-function block_admin_configure($module = NULL, $delta = 0) {
+function block_admin_configure(&$form_state, $module = NULL, $delta = 0) {
 
   $form['module'] = array('#type' => 'value', '#value' => $module);
   $form['delta'] = array('#type' => 'value', '#value' => $delta);
@@ -524,8 +537,8 @@
 /**
  * Menu callback: display the custom block addition form.
  */
-function block_add_block_form() {
-  return block_admin_configure('block', NULL);
+function block_add_block_form(&$form_state) {
+  return block_admin_configure($form_state, 'block', NULL);
 }
 
 function block_add_block_form_validate($form, &$form_state) {
@@ -728,7 +741,17 @@
         // Check the current throttle status and see if block should be displayed
         // based on server load.
         if (!($block->throttle && (module_invoke('throttle', 'status') > 0))) {
-          $array = module_invoke($block->module, 'block', 'view', $block->delta);
+          // Try fetching block from cache.
+          if (($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
+            $array = unserialize($cache->data);
+          }
+          else {
+            $array = module_invoke($block->module, 'block', 'view', $block->delta);
+            if ($cid) {
+              cache_set($cid, serialize($array), 'cache_block', variable_get('cache_lifetime', CACHE_TEMPORARY));
+            }
+          }
+
           if (isset($array) && is_array($array)) {
             foreach ($array as $k => $v) {
               $block->$k = $v;
@@ -752,3 +775,42 @@
   }
   return $blocks[$region];
 }
+
+function _block_get_cache_id($block) {
+  global $theme, $base_root, $user;
+
+  if (variable_get('block_cache', 0) && $block->cache_mode != BLOCK_NO_CACHE && $user->uid != 1) {
+    $base_cid = "$block->module:$block->delta:$theme";
+    if (module_exists('locale')) {
+      global $language;
+      $base_cid .= ":$language->language";
+    }
+
+    // Use 'per role' as a default.
+    if (!isset($block->cache_mode)) {
+      $block->cache_mode = BLOCK_CACHE_PER_ROLE;
+    }
+
+    $cid_parts = array();
+
+    // Let hook_block($op = 'cid') define specific granularity.
+    if ($block->cache_mode & BLOCK_CACHE_CUSTOM) {
+      $cid_parts[] = module_invoke($block->module, 'block', 'cache_id', $block->delta);
+    }
+
+    // 'per role' and 'per user' are mutually exclusive :
+    // we favor the less expensive 'per role'.
+    if ($block->cache_mode & BLOCK_CACHE_PER_ROLE) {
+      $cid_parts[] = 'r_'. implode(',', array_keys($user->roles));
+    }
+    elseif ($block->cache_mode & BLOCK_CACHE_PER_USER) {
+      $cid_parts[] = "u_$user->uid";
+    }
+
+    if ($block->cache_mode & BLOCK_CACHE_PER_PAGE) {
+      $cid_parts[] = $base_root . request_uri();
+    }
+
+    return "$base_cid:". implode(':', $cid_parts);
+  }
+}
\ No newline at end of file
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.117
diff -u -r1.117 menu.module
--- modules/menu/menu.module	22 Jun 2007 08:32:27 -0000	1.117
+++ modules/menu/menu.module	23 Jun 2007 00:27:42 -0000
@@ -520,6 +520,8 @@
     foreach ($custom_menus as $name => $title) {
       // Default "Navigation" block is handled by user.module.
       $blocks[$name]['info'] = check_plain($title);
+      // menu blocks might be different on every page
+      $blocks[$name]['cache_mode'] = BLOCK_NO_CACHE;
     }
     return $blocks;
   }
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.226
diff -u -r1.226 search.module
--- modules/search/search.module	22 Jun 2007 08:32:28 -0000	1.226
+++ modules/search/search.module	23 Jun 2007 00:27:44 -0000
@@ -144,6 +144,7 @@
 function search_block($op = 'list', $delta = 0) {
   if ($op == 'list') {
     $blocks[0]['info'] = t('Search form');
+    $blocks[0]['cache_mode'] = BLOCK_CACHE_GLOBAL;
     return $blocks;
   }
   else if ($op == 'view' && user_access('search content')) {
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.802
diff -u -r1.802 user.module
--- modules/user/user.module	22 Jun 2007 08:46:16 -0000	1.802
+++ modules/user/user.module	23 Jun 2007 00:27:49 -0000
@@ -599,10 +599,14 @@
 
   if ($op == 'list') {
      $blocks[0]['info'] = t('User login');
+     // Contains a redirect url which changes each page view.
+     $blocks[0]['cache_mode'] = BLOCK_CACHE_PER_PAGE;
      $blocks[1]['info'] = t('Navigation');
+     $blocks[1]['cache_mode'] = BLOCK_CACHE_PER_PAGE & BLOCK_CACHE_PER_USER;
      $blocks[2]['info'] = t('Who\'s new');
+     // too dynamic to cache
      $blocks[3]['info'] = t('Who\'s online');
-
+     $blocks[3]['cache_mode'] = BLOCK_NO_CACHE;
      return $blocks;
   }
   else if ($op == 'configure' && $delta == 2) {
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.835
diff -u -r1.835 node.module
--- modules/node/node.module	22 Jun 2007 08:32:27 -0000	1.835
+++ modules/node/node.module	23 Jun 2007 00:27:43 -0000
@@ -1896,6 +1896,7 @@
 function node_block($op = 'list', $delta = 0) {
   if ($op == 'list') {
     $blocks[0]['info'] = t('Syndicate');
+    $blocks[0]['cache_mode'] = BLOCK_CACHE_GLOBAL;
     return $blocks;
   }
   else if ($op == 'view') {
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.495
diff -u -r1.495 system.module
--- modules/system/system.module	22 Jun 2007 08:32:28 -0000	1.495
+++ modules/system/system.module	23 Jun 2007 00:27:47 -0000
@@ -704,6 +704,22 @@
     '#description' => t('On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.')
   );
 
+  $form['block_cache'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Block cache'),
+    // TODO
+    '#description' => t(''),
+  );
+
+  $form['block_cache']['block_cache'] = array(
+    '#type' => 'radios',
+    '#title' => t('Block cache'),
+    '#default_value' => variable_get('block_cache', CACHE_DISABLED),
+    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Enabled (recommended)')),
+    // TODO
+    '#description' => t(''),
+  );
+
   $form['bandwidth_optimizations'] = array(
     '#type' => 'fieldset',
     '#title' => t('Bandwidth optimizations'),
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.122
diff -u -r1.122 system.install
--- modules/system/system.install	15 Jun 2007 18:40:14 -0000	1.122
+++ modules/system/system.install	23 Jun 2007 00:34:01 -0000
@@ -3362,6 +3362,28 @@
 }
 
 /**
+ * Add cache_block table.
+ */
+function system_update_6025() {
+  $ret = array();
+  $schema['cache_block'] = array(
+    'fields' => array(
+      'cid'        => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'data'       => array('type' => 'blob', 'not null' => FALSE, 'size' => 'big'),
+      'expire'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'created'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'headers'    => array('type' => 'text', 'not null' => FALSE),
+      'serialized' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
+    ),
+    'indexes' => array('expire' => array('expire')),
+    'primary key' => array('cid'),
+  );
+  _drupal_initialize_schema('block', $schema);
+  db_create_table($ret, $schema['cache_block']);
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.x-to-6.x"
  * The next series of updates should start at 7000.
  */
