diff --git a/modules/book/book.install b/modules/book/book.install
old mode 100644
new mode 100755
index 899ee81..3b3da66
--- a/modules/book/book.install
+++ b/modules/book/book.install
@@ -91,5 +91,20 @@ function book_schema() {
     ),
   );
 
+  // Create cache bin for book link data.
+  $schema['cache_book'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_book']['description'] = 'Cache table for the Book module to store previous, up, and next tree associations.';
   return $schema;
 }
+
+/**
+ * Add in the book cache bin.
+ */
+function book_update_7001() {
+  // Create cache bin for book link data.
+  if (!db_table_exists('cache_book')) {
+    $schema = drupal_get_schema_unprocessed('system', 'cache');
+    $schema['description'] = 'Cache table for the Book module to store previous, up, and next tree associations.';
+    db_create_table('cache_book', $schema);
+  }
+}
diff --git a/modules/book/book.module b/modules/book/book.module
index 7afed9a..781e66b 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -914,6 +914,10 @@ function book_page_alter(&$page) {
  * Implements hook_node_presave().
  */
 function book_node_presave($node) {
+  // make sure this is a book or in a book and not a new one
+  if (!empty($node->book['bid']) && $node->book['bid'] != 'new') {
+    _book_cache_clear($node->book['bid'], TRUE);
+  }
   // Always save a revision for non-administrators.
   if (!empty($node->book['bid']) && !user_access('administer nodes')) {
     $node->revision = 1;
@@ -979,6 +983,8 @@ function book_node_delete($node) {
       ->condition('mlid', $node->book['mlid'])
       ->execute();
     drupal_static_reset('book_get_books');
+    // unset the book cache
+    _book_cache_clear($node->book['bid'], TRUE);
   }
 }
 
@@ -1059,6 +1065,26 @@ function _book_link_defaults($nid) {
 }
 
 /**
+ * Invalidates cached data relating to book_cache.
+ *
+ * @param $cid
+ *   (optional) Cache ID of the record to clear from the private update module
+ *   cache. If empty, all records will be cleared from the table except fetch
+ *   tasks. Defaults to NULL.
+ * @param $wildcard
+ *   (optional) If TRUE, cache IDs starting with $cid are deleted in addition to
+ *   the exact cache ID specified by $cid. Defaults to FALSE.
+ */
+function _book_cache_clear($cid = NULL, $wildcard = FALSE) {
+  if (empty($cid)) {
+    cache_clear_all('*', 'cache_book', TRUE);
+  }
+  else {
+    cache_clear_all($cid, 'cache_book', $wildcard);
+  }
+}
+
+/**
  * Processes variables for book-all-books-block.tpl.php.
  *
  * All non-renderable elements are removed so that the template has full access
@@ -1095,46 +1121,80 @@ function template_preprocess_book_navigation(&$variables) {
   // Provide extra variables for themers. Not needed by default.
   $variables['book_id'] = $book_link['bid'];
   $variables['book_title'] = check_plain($book_link['link_title']);
-  $variables['book_url'] = 'node/' . $book_link['bid'];
+  $variables['book_url'] = 'node/'. $book_link['bid'];
   $variables['current_depth'] = $book_link['depth'];
-  $variables['tree'] = '';
 
   if ($book_link['mlid']) {
-    $variables['tree'] = book_children($book_link);
-
-    if ($prev = book_prev($book_link)) {
+    // Use book_link to see if we can obtain info about it from cache.
+    $data = FALSE;
+    // generate a unique call signature for bid and mlid.
+    $cid = $book_link['bid'] . ':' . $book_link['mlid'];
+    // Statically cache future calls.
+    $data = &drupal_static(__FUNCTION__);
+    // @ignore druplart_conditional_assignment
+    if (!$data && $cache = cache_get($cid, 'cache_book')) {
+      $data = $cache->data;
+    }
+    // We got data from a previous source so use that instead.
+    if ($data) {
+      $prev = $data['prev'];
+      $next = $data['next'];
+      $tree = $data['tree'];
+      $parent = $data['parent'];
+    }
+    else {
+      // Manual look up to generate these items
+      $prev = book_prev($book_link);
+      $next = book_next($book_link);
+      $tree = book_children($book_link);
+      $parent = book_link_load($book_link['plid']);
+      $data = array(
+        'prev' => $prev,
+        'next' => $next,
+        'tree' => $tree,
+        'parent' => $parent,
+      );
+      cache_set($cid, $data, 'cache_book');
+    }
+    $variables['tree'] = $tree;
+    $variables['book_id'] = $book_link['bid'];
+    // Check for prev link.
+    if ($prev) {
       $prev_href = url($prev['href']);
       drupal_add_html_head_link(array('rel' => 'prev', 'href' => $prev_href));
       $variables['prev_url'] = $prev_href;
       $variables['prev_title'] = check_plain($prev['title']);
     }
-
-    if ($book_link['plid'] && $parent = book_link_load($book_link['plid'])) {
+    // Check for a parent, otherwise return an empty one.
+    if ($book_link['plid'] && $parent) {
       $parent_href = url($parent['href']);
       drupal_add_html_head_link(array('rel' => 'up', 'href' => $parent_href));
       $variables['parent_url'] = $parent_href;
       $variables['parent_title'] = check_plain($parent['title']);
     }
-
-    if ($next = book_next($book_link)) {
+    else {
+      $variables['parent_url'] = FALSE;
+    }
+    // Check for a next link.
+    if ($next) {
       $next_href = url($next['href']);
       drupal_add_html_head_link(array('rel' => 'next', 'href' => $next_href));
       $variables['next_url'] = $next_href;
       $variables['next_title'] = check_plain($next['title']);
     }
-  }
 
-  $variables['has_links'] = FALSE;
-  // Link variables to filter for values and set state of the flag variable.
-  $links = array('prev_url', 'prev_title', 'parent_url', 'parent_title', 'next_url', 'next_title');
-  foreach ($links as $link) {
-    if (isset($variables[$link])) {
-      // Flag when there is a value.
-      $variables['has_links'] = TRUE;
-    }
-    else {
-      // Set empty to prevent notices.
-      $variables[$link] = '';
+    $variables['has_links'] = FALSE;
+    // Link variables to filter for values and set state of the flag variable.
+    $links = array('prev_url', 'prev_title', 'parent_title', 'next_url', 'next_title');
+    foreach ($links as $link) {
+      if (isset($variables[$link])) {
+        // Flag when there is a value.
+        $variables['has_links'] = TRUE;
+      }
+      else {
+        // Set empty to prevent notices.
+        $variables[$link] = '';
+      }
     }
   }
 }
@@ -1435,3 +1495,11 @@ function book_menu_subtree_data($link) {
 
   return $tree[$cid];
 }
+
+/**
+ * Implements hook_flush_caches().
+ */
+function book_flush_caches() {
+  _book_cache_clear();
+  return array();
+}
diff --git a/modules/book/book.pages.inc b/modules/book/book.pages.inc
index ac4f357..8caf713 100644
--- a/modules/book/book.pages.inc
+++ b/modules/book/book.pages.inc
@@ -202,6 +202,8 @@ function book_outline_form_submit($form, &$form_state) {
     else {
       drupal_set_message(t('The book outline has been updated.'));
     }
+    // Clear book_cache when book link updated outside of node ops.
+    _book_cache_clear($node->book['bid'], TRUE);
   }
   else {
     drupal_set_message(t('There was an error adding the post to the book.'), 'error');
