Commit b642599f authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua
Browse files

Merge sanja.is.com.ua:/home/bell/mysql/mysql-4

into sanja.is.com.ua:/home/bell/mysql/work-qc
parents ff0504b0 63b2a551
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -36304,9 +36304,8 @@ If a table changes (@code{INSERT}, @code{UPDATE}, @code{DELETE},
then all cached queries that used this table (possibly through a
@code{MRG_MyISAM} table!) become invalid and are removed from the cache.
Currently all @code{InnoDB} tables are invalidated on @code{COMMIT},
in the future this will be changed so only tables changed in the
transaction cause the corresponding cache entries to be invalidated.
Changed transactional @code{InnoDB} tables will be invalidated on
@code{COMMIT}.
A query cannot be cached if it contains one of the functions:
@multitable @columnfractions .25 .25 .25 .25
+86 −1
Original line number Diff line number Diff line
drop table if exists t1;
drop table if exists t1, t2, t3;
flush status;
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
@@ -13,3 +14,87 @@ Qcache_queries_in_cache 0
drop table t1;
commit;
set autocommit=1;
begin;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
a
1
2
3
show status like "Qcache_queries_in_cache";
Variable_name	Value
Qcache_queries_in_cache	0
drop table t1;
commit;
create table t1 (a int not null) type=innodb;
create table t2 (a int not null) type=innodb;
create table t3 (a int not null) type=innodb;
insert into t1 values (1),(2);
insert into t2 values (1),(2);
insert into t3 values (1),(2);
select * from t1;
a
1
2
select * from t2;
a
1
2
select * from t3;
a
1
2
show status like "Qcache_queries_in_cache";
Variable_name	Value
Qcache_queries_in_cache	3
show status like "Qcache_hits";
Variable_name	Value
Qcache_hits	0
begin;
select * from t1;
a
1
2
select * from t2;
a
1
2
select * from t3;
a
1
2
show status like "Qcache_queries_in_cache";
Variable_name	Value
Qcache_queries_in_cache	3
show status like "Qcache_hits";
Variable_name	Value
Qcache_hits	0
insert into t1 values (3);
insert into t2 values (3);
insert into t1 values (4);
select * from t1;
a
1
2
3
4
select * from t2;
a
1
2
3
select * from t3;
a
1
2
show status like "Qcache_queries_in_cache";
Variable_name	Value
Qcache_queries_in_cache	3
show status like "Qcache_hits";
Variable_name	Value
Qcache_hits	0
commit;
show status like "Qcache_queries_in_cache";
Variable_name	Value
Qcache_queries_in_cache	1
+36 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@
#
# Without auto_commit.
#
drop table if exists t1;
drop table if exists t1, t2, t3;
flush status;
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
@@ -12,3 +13,37 @@ show status like "Qcache_queries_in_cache";
drop table t1;
commit;
set autocommit=1;
begin;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
show status like "Qcache_queries_in_cache";
drop table t1;
commit;
create table t1 (a int not null) type=innodb;
create table t2 (a int not null) type=innodb;
create table t3 (a int not null) type=innodb;
insert into t1 values (1),(2);
insert into t2 values (1),(2);
insert into t3 values (1),(2);
select * from t1;
select * from t2;
select * from t3;
show status like "Qcache_queries_in_cache";
show status like "Qcache_hits";
begin;
select * from t1;
select * from t2;
select * from t3;
show status like "Qcache_queries_in_cache";
show status like "Qcache_hits";
insert into t1 values (3);
insert into t2 values (3);
insert into t1 values (4);
select * from t1;
select * from t2;
select * from t3;
show status like "Qcache_queries_in_cache";
show status like "Qcache_hits";
commit;
show status like "Qcache_queries_in_cache";
 No newline at end of file
+8 −5
Original line number Diff line number Diff line
@@ -272,6 +272,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
  if (opt_using_transactions)
  {
    bool operation_done= 0;
    bool transaction_commited= 0;
    /* Update the binary log if we have cached some queries */
    if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
	my_b_tell(&thd->transaction.trans_log))
@@ -289,6 +290,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
	my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
	error=1;
      }
      else
	transaction_commited= 1;
      trans->bdb_tid=0;
    }
#endif
@@ -302,12 +305,12 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
      }
      trans->innodb_active_trans=0;
      if (trans == &thd->transaction.all)
      {
	query_cache.invalidate(Query_cache_table::INNODB);
	operation_done=1;
      }
	operation_done= transaction_commited= 1;
	
    }
#endif
    if (transaction_commited)
      query_cache.invalidate(thd->transaction.changed_tables);
    if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
      sql_print_error("Error: Got error during commit;  Binlog is not up to date!");
    thd->tx_isolation=thd->session_tx_isolation;
+94 −80
Original line number Diff line number Diff line
@@ -271,8 +271,6 @@ If join_results allocated new block(s) then we need call pack_cache again.

TODO list:

  - Invalidate queries that use innoDB tables changed in transaction & remove
      invalidation by table type
  - Delayed till after-parsing qache answer (for column rights processing)
  - Optimize cache resizing
      - if new_size < old_size then pack & shrink
@@ -280,8 +278,6 @@ TODO list:
  - Move MRG_MYISAM table type processing to handlers, something like:
        tables_used->table->file->register_used_filenames(callback,
                                                          first_argument);
  - In Query_cache::insert_table eliminate strlen(). To do this we have to
        add db_len to the TABLE_LIST and TABLE structures.
*/

#include "mysql_priv.h"
@@ -1030,7 +1026,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
  Remove all cached queries that uses any of the tables in the list
*/

void Query_cache::invalidate(TABLE_LIST *tables_used)
void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
			     my_bool using_transactions)
{
  DBUG_ENTER("Query_cache::invalidate (table list)");
  if (query_cache_size > 0)
@@ -1039,54 +1036,76 @@ void Query_cache::invalidate(TABLE_LIST *tables_used)
    if (query_cache_size > 0)
    {
      DUMP(this);

      using_transactions = using_transactions &&
	(thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN));
      for ( ; tables_used; tables_used=tables_used->next)
      {
	DBUG_ASSERT(!using_transactions || tables_used->table!=0);
	if (using_transactions && 
	   tables_used->table->file->has_transactions())
	  /* 
	     Tables_used->table can't be 0 in transaction.
	     Only 'drop' invalidate not opened table, but 'drop' 
	     force transaction finish.
	  */
	  thd->add_changed_table(tables_used->table);
	else
	  invalidate_table(tables_used);
      }
    }
    STRUCT_UNLOCK(&structure_guard_mutex);
  }
  DBUG_VOID_RETURN;
}

/*
  Remove all cached queries that uses the given table
*/

void Query_cache::invalidate(TABLE *table)
void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
{
  DBUG_ENTER("Query_cache::invalidate (table)");
  if (query_cache_size > 0)
  DBUG_ENTER("Query_cache::invalidate (changed table list)");
  if (query_cache_size > 0 && tables_used)
  {
    STRUCT_LOCK(&structure_guard_mutex);
    if (query_cache_size > 0)
      invalidate_table(table);
    {
      DUMP(this);
      for ( ; tables_used; tables_used=tables_used->next)
      {
	invalidate_table(tables_used->key, tables_used->key_length);
	DBUG_PRINT("qcache", (" db %s, table %s", tables_used->key,
			      tables_used->table_name));
      }
    }
    STRUCT_UNLOCK(&structure_guard_mutex);
  }
  DBUG_VOID_RETURN;
}

/*
  Remove all cached queries that uses the given table type.
  Remove all cached queries that uses the given table
*/

void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
void Query_cache::invalidate(THD *thd, TABLE *table, 
			     my_bool using_transactions)
{
  DBUG_ENTER("Query_cache::invalidate (type)");
  DBUG_ENTER("Query_cache::invalidate (table)");
  
  if (query_cache_size > 0)
  {
    STRUCT_LOCK(&structure_guard_mutex);
    DUMP(this);
    if (query_cache_size > 0)
    {
      /* invalidate_table reduce list while only root of list remain */
      while (tables_blocks[type] != 0)
	invalidate_table(tables_blocks[type]);
      using_transactions = using_transactions &&
	(thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN));
      if (using_transactions && table->file->has_transactions())
	thd->add_changed_table(table);
      else
	invalidate_table(table);
    }
    STRUCT_UNLOCK(&structure_guard_mutex);
  }
  DBUG_VOID_RETURN;
}


/*
  Remove all cached queries that uses the given database
*/
@@ -1100,12 +1119,9 @@ void Query_cache::invalidate(char *db)
    if (query_cache_size > 0)
    {
      DUMP(this);
      for (int i=0 ; i < (int) Query_cache_table::TYPES_NUMBER; i++)
      {
	/* invalidate_table reduce list while only root of list remain */
	while (tables_blocks[i] !=0 )
	  invalidate_table(tables_blocks[i]);
      }
      while (tables_blocks !=0 )
	invalidate_table(tables_blocks);
    }
    STRUCT_UNLOCK(&structure_guard_mutex);
  }
@@ -1120,7 +1136,8 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
  {
    /* Calculate the key outside the lock to make the lock shorter */
    char key[MAX_DBKEY_LENGTH];
    uint key_length= filename_2_table_key(key, filename);
    uint32 db_length;
    uint key_length= filename_2_table_key(key, filename, &db_length);
    STRUCT_LOCK(&structure_guard_mutex);
    if (query_cache_size > 0)			// Safety if cache removed
    {
@@ -1800,11 +1817,15 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list)
}

void Query_cache::invalidate_table(TABLE *table)
{
  invalidate_table((byte*) table->table_cache_key, table->key_length);
}

void Query_cache::invalidate_table(byte * key, uint32  key_length)
{
  Query_cache_block *table_block;
  if ((table_block = ((Query_cache_block*)
		      hash_search(&tables, (byte*) table->table_cache_key,
				  table->key_length))))
		      hash_search(&tables, key, key_length))))
    invalidate_table(table_block);
}

@@ -1842,8 +1863,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
    block_table->n=n;
    if (!insert_table(tables_used->table->key_length,
		      tables_used->table->table_cache_key, block_table,
		      Query_cache_table::type_convertion(tables_used->table->
							 db_type)))
		      tables_used->db_length))
      break;

    if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
@@ -1855,10 +1875,12 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
	   table++)
      {
	char key[MAX_DBKEY_LENGTH];
	uint key_length =filename_2_table_key(key, table->table->filename);
	uint32 db_length;
	uint key_length =filename_2_table_key(key, table->table->filename,
					      &db_length);
	(++block_table)->n= ++n;
	if (!insert_table(key_length, key, block_table,
			  Query_cache_table::type_convertion(DB_TYPE_MYISAM)))
			  db_length))
	  goto err;
      }
    }
@@ -1885,7 +1907,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
my_bool
Query_cache::insert_table(uint key_len, char *key,
			  Query_cache_block_table *node,
			  Query_cache_table::query_cache_table_type type)
			  uint32 db_length)
{
  DBUG_ENTER("Query_cache::insert_table");
  DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@@ -1909,9 +1931,8 @@ Query_cache::insert_table(uint key_len, char *key,
      DBUG_RETURN(0);
    }
    Query_cache_table *header = table_block->table();
    header->type(type);
    double_linked_list_simple_include(table_block,
				      &tables_blocks[type]);
				      &tables_blocks);
    Query_cache_block_table *list_root = table_block->table(0);
    list_root->n = 0;
    list_root->next = list_root->prev = list_root;
@@ -1923,7 +1944,7 @@ Query_cache::insert_table(uint key_len, char *key,
      DBUG_RETURN(0);
    }
    char *db = header->db();
    header->table(db + strlen(db) + 1);
    header->table(db + db_length + 1);
  }

  Query_cache_block_table *list_root = table_block->table(0);
@@ -1947,7 +1968,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node)
    // list is empty (neighbor is root of list)
    Query_cache_block *table_block = neighbour->block();
    double_linked_list_exclude(table_block,
			       &tables_blocks[table_block->table()->type()]);
			       &tables_blocks);
    hash_delete(&tables,(byte *) table_block);
    free_memory_block(table_block);
  }
@@ -2513,8 +2534,8 @@ my_bool Query_cache::move_by_type(byte **border,
    new_block->n_tables=1;
    memmove((char*) new_block->data(), data, len-new_block->headers_len());
    relink(block, new_block, next, prev, pnext, pprev);
    if (tables_blocks[new_block->table()->type()] == block)
      tables_blocks[new_block->table()->type()] = new_block;
    if (tables_blocks == block)
      tables_blocks = new_block;

    Query_cache_block_table *nlist_root = new_block->table(0);
    nlist_root->n = 0;
@@ -2771,10 +2792,10 @@ my_bool Query_cache::join_results(ulong join_limit)
}


uint Query_cache::filename_2_table_key (char *key, const char *path)
uint Query_cache::filename_2_table_key (char *key, const char *path,
					uint32 *db_length)
{
  char tablename[FN_REFLEN+2], *filename, *dbname;
  uint db_length;
  DBUG_ENTER("Query_cache::filename_2_table_key");

  /* Safety if filename didn't have a directory name */
@@ -2785,10 +2806,10 @@ uint Query_cache::filename_2_table_key (char *key, const char *path)
  filename=  tablename + dirname_length(tablename + 2) + 2;
  /* Find start of databasename */
  for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
  db_length= (filename - dbname) - 1;
  DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename));
  *db_length= (filename - dbname) - 1;
  DBUG_PRINT("qcache", ("table '%-.*s.%s'", *db_length, dbname, filename));

  DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1,
  DBUG_RETURN((uint) (strmov(strmake(key, dbname, *db_length) + 1,
			     filename) -key) + 1);
}

@@ -2975,22 +2996,18 @@ void Query_cache::tables_dump()
  DBUG_PRINT("qcache", ("--------------------"));
  DBUG_PRINT("qcache", ("TABLES"));
  DBUG_PRINT("qcache", ("--------------------"));
  for (int i=0; i < (int) Query_cache_table::TYPES_NUMBER; i++)
  if (tables_blocks != 0)
  {
    DBUG_PRINT("qcache", ("--- type %u", i));
    if (tables_blocks[i] != 0)
    {
      Query_cache_block *table_block = tables_blocks[i];
    Query_cache_block *table_block = tables_blocks;
    do
    {
      Query_cache_table *table = table_block->table();
      DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
      table_block = table_block->next;
      } while ( table_block != tables_blocks[i]);
    } while ( table_block != tables_blocks);
  }
  else
    DBUG_PRINT("qcache", ("no tables in list"));
  }
  DBUG_PRINT("qcache", ("--------------------"));
}

@@ -3082,7 +3099,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
      break;
    }
    case Query_cache_block::TABLE:
      if (in_list(tables_blocks[block->table()->type()], block, "tables"))
      if (in_list(tables_blocks, block, "tables"))
	result = 1;
      if (in_table_list(block->table(0),  block->table(0), "table list root"))
	result = 1;
@@ -3197,9 +3214,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
  }

  DBUG_PRINT("qcache", ("check tables ..."));
  for (i=0 ; (int) i < (int) Query_cache_table::TYPES_NUMBER; i++)
  {
    if ((block = tables_blocks[i]))
  if ((block = tables_blocks))
  {
    do
    {
@@ -3217,8 +3232,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
      if (in_blocks(block))
	result = 1;
      block=block->next;
      } while (block != tables_blocks[i]);
    }
    } while (block != tables_blocks);
  }

  DBUG_PRINT("qcache", ("check free blocks"));
Loading