• unknown's avatar
    BUG#21051: RESET QUERY CACHE very slow when query_cache_type=0 · 877477f1
    unknown authored
    There were two problems: RESET QUERY CACHE took a long time to complete
    and other threads were blocked during this time.
    
    The patch does three things:
      1 fixes a bug with improper use of test-lock-test_again technique.
          AKA Double-Checked Locking is applicable here only in few places.
      2 Somewhat improves performance of RESET QUERY CACHE.
          Do my_hash_reset() instead of deleting elements one by one.  Note
          however that the slowdown also happens when inserting into sorted
          list of free blocks, should be rewritten using balanced tree.
      3 Makes RESET QUERY CACHE non-blocking.
          The patch adjusts the locking protocol of the query cache in the
          following way: it introduces a flag flush_in_progress, which is
          set when Query_cache::flush_cache() is in progress.  This call
          sets the flag on enter, and then releases the lock.  Every other
          call is able to acquire the lock, but does nothing if
          flush_in_progress is set (as if the query cache is disabled).
          The only exception is the concurrent calls to
          Query_cache::flush_cache(), that are blocked until the flush is
          over.  When leaving Query_cache::flush_cache(), the lock is
          acquired and the flag is reset, and one thread waiting on
          Query_cache::flush_cache() (if any) is notified that it may
          proceed.
    
    
    include/mysql_com.h:
      Add comment for NET::query_cache_query.
    sql/net_serv.cc:
      Use query_cache_init_query() for initialization of
      NET::query_cache_query if query cache is used.
      Do not access net->query_cache_query without a lock.
    sql/sql_cache.cc:
      Fix bug with accessing query_cache_size, Query_cache_query::wri and
      thd->net.query_cache_query before acquiring the lock---leave
      double-check locking only in safe places.
      Wherever we check that cache is usable (query_cache_size > 0) we now
      also check that flush_in_progress is false, i.e. we are not in the
      middle of cache flush.
      Add Query_cache::not_in_flush_or_wait() method and use it in
      Query_cache::flush_cache(), so that threads doing cache flush will
      wait it to finish, while other threads will bypass the cache as if
      it is disabled.
      Extract Query_cache::free_query_internal() from Query_cache::free_query(),
      which does not removes elements from the hash, and use it together with
      my_hash_reset() in Query_cache::flush_cache().
    sql/sql_cache.h:
      Add declarations for new members and methods.
      Make is_cacheable() a static method.
      Add query_cache_init_query() function.
    sql/sql_class.cc:
      Use query_cache_init_query() for initialization of
      NET::query_cache_query.
    877477f1
sql_class.cc 57.9 KB