List:Internals« Previous MessageNext Message »
From:ingo Date:May 27 2005 2:02pm
Subject:bk commit into 4.1 tree (ingo:1.2283) BUG#10602
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of mydev. When mydev does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2283 05/05/27 16:02:27 ingo@stripped +1 -0
  Bug#10602 - LOAD INDEX INTO CACHE deadlocks
  Fixed two deadlocks.
  Made minor changes.

  mysys/mf_keycache.c
    1.50 05/05/27 16:02:24 ingo@stripped +104 -23
    Bug#10602 - LOAD INDEX INTO CACHE deadlocks
    Fixed two deadlocks.
    Made keycache traces line buffered.
    Added comments and trace messages.
    Fixed two compiler warnings.
    Fixed some coding style issues.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	ingo
# Host:	chilla.local
# Root:	/home/mydev/mysql-4.1-4100

--- 1.49/mysys/mf_keycache.c	Wed Apr 27 13:31:00 2005
+++ 1.50/mysys/mf_keycache.c	Fri May 27 16:02:24 2005
@@ -184,10 +184,18 @@
 static FILE *keycache_debug_log=NULL;
 static void keycache_debug_print _VARARGS((const char *fmt,...));
 #define KEYCACHE_DEBUG_OPEN                                                   \
-          if (!keycache_debug_log) keycache_debug_log=fopen(KEYCACHE_DEBUG_LOG, "w")
+          if (!keycache_debug_log)                                            \
+          {                                                                   \
+            keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w");               \
+            (void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ);         \
+          }
 
 #define KEYCACHE_DEBUG_CLOSE                                                  \
-          if (keycache_debug_log) { fclose(keycache_debug_log); keycache_debug_log=0; }
+          if (keycache_debug_log)                                             \
+          {                                                                   \
+            fclose(keycache_debug_log);                                       \
+            keycache_debug_log= 0;                                            \
+          }
 #else
 #define KEYCACHE_DEBUG_OPEN
 #define KEYCACHE_DEBUG_CLOSE
@@ -213,7 +221,7 @@
 
 #define KEYCACHE_THREAD_TRACE_BEGIN(l)                                        \
             { struct st_my_thread_var *thread_var= my_thread_var;             \
-              keycache_thread_id= my_thread_var->id;                          \
+              keycache_thread_id= thread_var->id;                             \
               KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
 
 #define KEYCACHE_THREAD_TRACE_END(l)                                          \
@@ -240,12 +248,16 @@
 static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
 static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
 static int keycache_pthread_cond_signal(pthread_cond_t *cond);
+#ifdef NOT_USED
 static int keycache_pthread_cond_broadcast(pthread_cond_t *cond);
+#endif
 #else
 #define keycache_pthread_mutex_lock pthread_mutex_lock
 #define keycache_pthread_mutex_unlock pthread_mutex_unlock
 #define keycache_pthread_cond_signal pthread_cond_signal
+#ifdef NOT_USED
 #define keycache_pthread_cond_broadcast pthread_cond_broadcast
+#endif
 #endif /* defined(KEYCACHE_DEBUG) */
 
 static uint next_power(uint value)
@@ -508,6 +520,8 @@
   keycache->can_be_used= 0;
   while (keycache->cnt_for_resize_op)
   {
+    KEYCACHE_DBUG_PRINT("resize_key_cache: wait",
+                        ("suspend thread %ld", thread->id));
     keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
   }
 
@@ -520,7 +534,11 @@
   unlink_from_queue(wqueue, thread);
   /* Signal for the next resize request to proceeed if any */
   if (wqueue->last_thread)
+  {
+    KEYCACHE_DBUG_PRINT("resize_key_cache: signal",
+                        ("thread %ld", wqueue->last_thread->next->id));
     keycache_pthread_cond_signal(&wqueue->last_thread->next->suspend);
+  }
   keycache_pthread_mutex_unlock(&keycache->cache_lock);
   return blocks;
 }
@@ -544,7 +562,11 @@
   struct st_my_thread_var *last_thread;
   if (!--keycache->cnt_for_resize_op &&
       (last_thread= keycache->resize_queue.last_thread))
+  {
+    KEYCACHE_DBUG_PRINT("dec_counter_for_resize_op: signal",
+                        ("thread %ld", last_thread->next->id));
     keycache_pthread_cond_signal(&last_thread->next->suspend);
+  }
 }
 
 /*
@@ -761,8 +783,8 @@
   do
   {
     thread=next;
-    keycache_pthread_cond_signal(&thread->suspend);
     KEYCACHE_DBUG_PRINT("release_queue: signal", ("thread %ld", thread->id));
+    keycache_pthread_cond_signal(&thread->suspend);
     next=thread->next;
     thread->next= NULL;
   }
@@ -876,7 +898,8 @@
   BLOCK_LINK **pins;
 
   KEYCACHE_DBUG_ASSERT(! (block->hash_link && block->hash_link->requests));
-  if (!hot && keycache->waiting_for_block.last_thread) {
+  if (!hot && keycache->waiting_for_block.last_thread)
+  {
     /* Signal that in the LRU warm sub-chain an available block has appeared */
     struct st_my_thread_var *last_thread=
                                keycache->waiting_for_block.last_thread;
@@ -894,6 +917,7 @@
       */
       if ((HASH_LINK *) thread->opt_info == hash_link)
       {
+        KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
         keycache_pthread_cond_signal(&thread->suspend);
         unlink_from_queue(&keycache->waiting_for_block, thread);
         block->requests++;
@@ -1000,11 +1024,10 @@
   linking it to the LRU chain if it's the last request
 
   SYNOPSIS
-
-    unreg_block()
-      keycache            pointer to a key cache data structure
-      block               pointer to the block to link to the LRU chain
-      at_end              <-> to link the block at the end of the LRU chain
+    unreg_request()
+    keycache            pointer to a key cache data structure
+    block               pointer to the block to link to the LRU chain
+    at_end              <-> to link the block at the end of the LRU chain
 
   RETURN VALUE
     none
@@ -1069,10 +1092,14 @@
   Remove a reader of the page in block
 */
 
-static inline void remove_reader(BLOCK_LINK *block)
+static inline void remove_reader(KEY_CACHE *keycache, BLOCK_LINK *block)
 {
   if (! --block->hash_link->requests && block->condvar)
+  {
+    KEYCACHE_DBUG_PRINT("remove_reader: signal",
+                        ("block %u", BLOCK_NUMBER(block)));
     keycache_pthread_cond_signal(block->condvar);
+  }
 }
 
 
@@ -1086,6 +1113,9 @@
   struct st_my_thread_var *thread= my_thread_var;
   while (block->hash_link->requests)
   {
+    KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
+                        ("suspend thread %ld  block %u",
+                         thread->id, BLOCK_NUMBER(block)));
     block->condvar= &thread->suspend;
     keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
     block->condvar= NULL;
@@ -1143,6 +1173,7 @@
       */
       if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
       {
+        KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
         keycache_pthread_cond_signal(&thread->suspend);
         unlink_from_queue(&keycache->waiting_for_hash_link, thread);
       }
@@ -1225,6 +1256,8 @@
       page.filepos= filepos;
       thread->opt_info= (void *) &page;
       link_into_queue(&keycache->waiting_for_hash_link, thread);
+      KEYCACHE_DBUG_PRINT("get_hash_link: wait",
+                        ("suspend thread %ld", thread->id));
       keycache_pthread_cond_wait(&thread->suspend,
                                  &keycache->cache_lock);
       thread->opt_info= NULL;
@@ -1343,6 +1376,8 @@
       add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
       do
       {
+        KEYCACHE_DBUG_PRINT("find_key_block: wait",
+                            ("suspend thread %ld", thread->id));
         keycache_pthread_cond_wait(&thread->suspend,
                                    &keycache->cache_lock);
       }
@@ -1360,7 +1395,9 @@
     /* This is a request for a page to be removed from cache */
 
     KEYCACHE_DBUG_PRINT("find_key_block",
-             ("request for old page in block %u",BLOCK_NUMBER(block)));
+                        ("request for old page in block %u "
+                         "wrmode: %d  block->status: %d",
+                         BLOCK_NUMBER(block), wrmode, block->status));
     /*
        Only reading requests can proceed until the old dirty page is flushed,
        all others are to be suspended, then resubmitted
@@ -1379,6 +1416,8 @@
         /* Wait until the request can be resubmitted */
         do
         {
+          KEYCACHE_DBUG_PRINT("find_key_block: wait",
+                              ("suspend thread %ld", thread->id));
           keycache_pthread_cond_wait(&thread->suspend,
                                      &keycache->cache_lock);
         }
@@ -1448,6 +1487,8 @@
           link_into_queue(&keycache->waiting_for_block, thread);
           do
           {
+            KEYCACHE_DBUG_PRINT("find_key_block: wait",
+                                ("suspend thread %ld", thread->id));
             keycache_pthread_cond_wait(&thread->suspend,
                                        &keycache->cache_lock);
           }
@@ -1528,9 +1569,13 @@
         else
         {
           /* This is for secondary requests for a new page only */
-            page_status= block->hash_link == hash_link &&
-                           (block->status & BLOCK_READ) ?
-                              PAGE_READ : PAGE_WAIT_TO_BE_READ;
+          KEYCACHE_DBUG_PRINT("find_key_block",
+                              ("block->hash_link: %p  hash_link: %p  "
+                               "block->status: %u", block->hash_link,
+                               hash_link, block->status ));
+          page_status= (((block->hash_link == hash_link) &&
+                         (block->status & BLOCK_READ)) ?
+                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
         }
       }
       keycache->global_cache_read++;
@@ -1538,17 +1583,22 @@
     else
     {
       reg_requests(keycache, block, 1);
-      page_status = block->hash_link == hash_link &&
-                    (block->status & BLOCK_READ) ?
-                      PAGE_READ : PAGE_WAIT_TO_BE_READ;
+      KEYCACHE_DBUG_PRINT("find_key_block",
+                          ("block->hash_link: %p  hash_link: %p  "
+                           "block->status: %u", block->hash_link,
+                           hash_link, block->status ));
+      page_status = (((block->hash_link == hash_link) &&
+                      (block->status & BLOCK_READ)) ?
+                     PAGE_READ : PAGE_WAIT_TO_BE_READ);
     }
   }
 
   KEYCACHE_DBUG_ASSERT(page_status != -1);
   *page_st=page_status;
   KEYCACHE_DBUG_PRINT("find_key_block",
-                      ("fd: %u  pos %lu  page_status %lu",
-                      (uint) file,(ulong) filepos,(uint) page_status));
+                      ("fd: %u  pos %lu  block->status %u  page_status %lu",
+                       (uint) file, (ulong) filepos, block->status,
+                       (uint) page_status));
 
 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
   DBUG_EXECUTE("check_keycache2",
@@ -1604,6 +1654,10 @@
 
     /* Page is not in buffer yet, is to be read from disk */
     keycache_pthread_mutex_unlock(&keycache->cache_lock);
+    /*
+      Here other threads may step in and register as secondary readers.
+      They will register in block->wqueue[COND_FOR_REQUESTED].
+    */
     got_length= my_pread(block->hash_link->file, block->buffer,
                          read_length, block->hash_link->diskpos, MYF(0));
     keycache_pthread_mutex_lock(&keycache->cache_lock);
@@ -1634,6 +1688,8 @@
       add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread);
       do
       {
+        KEYCACHE_DBUG_PRINT("read_block: wait",
+                            ("suspend thread %ld", thread->id));
         keycache_pthread_cond_wait(&thread->suspend,
                                    &keycache->cache_lock);
       }
@@ -1758,7 +1814,7 @@
         }
       }
 
-      remove_reader(block);
+      remove_reader(keycache, block);
       /*
          Link the block into the LRU chain
          if it's the last submitted request for the block
@@ -1855,6 +1911,10 @@
         /* The requested page is to be read into the block buffer */
 #if !defined(SERIALIZED_READ_FROM_CACHE)
         keycache_pthread_mutex_unlock(&keycache->cache_lock);
+        /*
+          Here other threads may step in and register as secondary readers.
+          They will register in block->wqueue[COND_FOR_REQUESTED].
+        */
 #endif
 
         /* Copy data from buff */
@@ -1865,12 +1925,18 @@
 
 #if !defined(SERIALIZED_READ_FROM_CACHE)
         keycache_pthread_mutex_lock(&keycache->cache_lock);
+        /* Here we are alone again. */
 #endif
         block->status= BLOCK_READ;
         block->length= read_length+offset;
+        KEYCACHE_DBUG_PRINT("key_cache_insert",
+                            ("primary request: new page in cache"));
+        /* Signal that all pending requests for this now can be processed. */
+        if (block->wqueue[COND_FOR_REQUESTED].last_thread)
+          release_queue(&block->wqueue[COND_FOR_REQUESTED]);
       }
 
-      remove_reader(block);
+      remove_reader(keycache, block);
       /*
          Link the block into the LRU chain
          if it's the last submitted request for the block
@@ -2074,9 +2140,16 @@
 {
   KEYCACHE_THREAD_TRACE("free block");
   KEYCACHE_DBUG_PRINT("free_block",
-                      ("block %u to be freed",BLOCK_NUMBER(block)));
+                      ("block %u to be freed, hash_link %p",
+                       BLOCK_NUMBER(block), block->hash_link));
   if (block->hash_link)
   {
+    /*
+      While waiting for readers to finish, new readers might request the
+      block. But since we set block->status|= BLOCK_REASSIGNED, they
+      will wait on block->wqueue[COND_FOR_SAVED]. They must be signalled
+      later.
+    */
     block->status|= BLOCK_REASSIGNED;
     wait_for_readers(keycache, block);
     unlink_hash(keycache, block->hash_link);
@@ -2102,6 +2175,10 @@
   keycache->free_block_list= block;
   /* Keep track of the number of currently unused blocks. */
   keycache->blocks_unused++;
+
+  /* All pending requests for this page must be resubmitted. */
+  if (block->wqueue[COND_FOR_SAVED].last_thread)
+    release_queue(&block->wqueue[COND_FOR_SAVED]);
 }
 
 
@@ -2334,6 +2411,8 @@
         add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
         do
         {
+          KEYCACHE_DBUG_PRINT("flush_key_blocks_int: wait",
+                              ("suspend thread %ld", thread->id));
           keycache_pthread_cond_wait(&thread->suspend,
                                      &keycache->cache_lock);
         }
@@ -2685,6 +2764,7 @@
 }
 
 
+#ifdef NOT_USED
 static int keycache_pthread_cond_broadcast(pthread_cond_t *cond)
 {
   int rc;
@@ -2692,6 +2772,7 @@
   rc= pthread_cond_broadcast(cond);
   return rc;
 }
+#endif
 
 #if defined(KEYCACHE_DEBUG_LOG)
 
Thread
bk commit into 4.1 tree (ingo:1.2283) BUG#10602ingo27 May