query_classifier.cc: added detection for CREATE TEMPORARY TABLE and setting a new query type QUERY_TYPE_CREATE_TMP_TABLE for it.

query_classifier.h: added QUERY_TYPE_CREATE_TMP_TABLE and QUERY_TYPE_READ_TMP_TABLE for use of temporary table support.
hashtable.c:Added variant of hashtable which is 'flat', that is, stored to existing memory instead of allocating memory as a part of the call. Existing function declarations don't change but added hashtable_alloc_flat for the purpose. Both hashtable_alloc and hashtable_alloc_flat now call the real allocation function, hashtable_alloc_real. hashtable_free only frees memory which is allocated in hashtable_alloc_real.
hashtable.h: added a flag to HASHTABLE struct to indicate whether hashtable owns its memory or not.
readwritesplit.h: Added RSES_PROP_TYPE_TMPTABLES property type to be used for keeping the hashtable for tablenames.
readwritesplit.c: Added comments about temporary table support implementation.
This commit is contained in:
VilhoRaatikka 2014-08-29 10:08:48 +03:00
parent 493feb49ba
commit 531d8d7b47
6 changed files with 175 additions and 8 deletions

View File

@ -494,8 +494,15 @@ static skygw_query_type_t resolve_query_type(
force_data_modify_op_replication)
{
type |= QUERY_TYPE_SESSION_WRITE;
} else {
}
else
{
type |= QUERY_TYPE_WRITE;
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
type |= QUERY_TYPE_CREATE_TMP_TABLE;
}
}
goto return_qtype;
@ -692,6 +699,17 @@ static skygw_query_type_t resolve_query_type(
break;
}
} /**< for */
#if defined(TEMPORARY_TABLES)
if ((skygw_query_type_t)type == QUERY_TYPE_READ)
{
/**
* Find out the database name and all tables the query
* uses. Create a hashvalue from each and if any of the
* values can be found from property's hashtable, set
* query type to QUERY_TYPE_READ_TMP_TABLE.
*/
}
#endif
} /**< if */
return_qtype:
qtype = (skygw_query_type_t)type;
@ -816,3 +834,25 @@ char* skygw_query_classifier_get_stmtname(
return ((THD *)(mysql->thd))->lex->prepared_stmt_name.str;
}
/**
* Finds the head of the list of tables affected by the current select statement.
* @param thd Pointer to a valid thread descriptor structure
* @return Head of the TABLE_LIST chain or NULL in case of an error
*/
void* skygw_get_affected_tables(void* thdp)
{
THD* thd = (THD*)thdp;
if(thd == NULL ||
thd->lex == NULL ||
thd->lex->current_select == NULL)
{
ss_dassert(thd != NULL &&
thd->lex != NULL &&
thd->lex->current_select != NULL);
return NULL;
}
return (void*)thd->lex->current_select->table_list.first;
}

View File

@ -43,7 +43,9 @@ typedef enum {
QUERY_TYPE_COMMIT = 0x0200, /*< COMMIT */
QUERY_TYPE_PREPARE_NAMED_STMT = 0x0400, /*< Prepared stmt with name from user */
QUERY_TYPE_PREPARE_STMT = 0x0800, /*< Prepared stmt with id provided by server */
QUERY_TYPE_EXEC_STMT = 0x1000 /*< Execute prepared statement */
QUERY_TYPE_EXEC_STMT = 0x1000, /*< Execute prepared statement */
QUERY_TYPE_CREATE_TMP_TABLE = 0x2000, /*< Create temporary table */
QUERY_TYPE_READ_TMP_TABLE = 0x4000 /*< Read temporary table */
} skygw_query_type_t;
#define QUERY_IS_TYPE(mask,type) ((mask & type) == type)
@ -60,6 +62,8 @@ skygw_query_type_t skygw_query_classifier_get_type(
/** Free THD context and close MYSQL */
void skygw_query_classifier_free(MYSQL* mysql);
char* skygw_query_classifier_get_stmtname(MYSQL* mysql);
void* skygw_get_affected_tables(void* thdp);
EXTERN_C_BLOCK_END

View File

@ -63,6 +63,10 @@ static void hashtable_read_lock(HASHTABLE *table);
static void hashtable_read_unlock(HASHTABLE *table);
static void hashtable_write_lock(HASHTABLE *table);
static void hashtable_write_unlock(HASHTABLE *table);
static HASHTABLE *hashtable_alloc_real(HASHTABLE* target,
int size,
int (*hashfn)(),
int (*cmpfn)());
/**
* Special null function used as default memory allfunctions in the hashtable
@ -81,11 +85,75 @@ nullfn(void *data)
/**
* Allocate a new hash table
*
* @param target The address where hashtable is to be initialized, if NULL then allocate
* @param size The size of the hash table
* @param hashfn The user supplied hash function
* @param cmpfn The user supplied key comparison function
* @return The hashtable table
*/
#if 1
HASHTABLE *
hashtable_alloc(int size, int (*hashfn)(), int (*cmpfn)())
{
return hashtable_alloc_real(NULL, size, hashfn, cmpfn);
}
HASHTABLE* hashtable_alloc_flat(
HASHTABLE* target,
int size,
int (*hashfn)(),
int (*cmpfn)())
{
return hashtable_alloc_real(target, size, hashfn, cmpfn);
}
static HASHTABLE *
hashtable_alloc_real(
HASHTABLE* target,
int size,
int (*hashfn)(),
int (*cmpfn)())
{
HASHTABLE *rval;
if (target == NULL)
{
if ((rval = malloc(sizeof(HASHTABLE))) == NULL)
return NULL;
rval->ht_isflat = false;
}
else
{
rval = target;
rval->ht_isflat = true;
}
#if defined(SS_DEBUG)
rval->ht_chk_top = CHK_NUM_HASHTABLE;
rval->ht_chk_tail = CHK_NUM_HASHTABLE;
#endif
rval->hashsize = size;
rval->hashfn = hashfn;
rval->cmpfn = cmpfn;
rval->kcopyfn = nullfn;
rval->vcopyfn = nullfn;
rval->kfreefn = nullfn;
rval->vfreefn = nullfn;
rval->n_readers = 0;
rval->writelock = 0;
spinlock_init(&rval->spin);
if ((rval->entries = (HASHENTRIES **)calloc(size, sizeof(HASHENTRIES *))) == NULL)
{
free(rval);
return NULL;
}
memset(rval->entries, 0, size * sizeof(HASHENTRIES *));
return rval;
}
#else
HASHTABLE *
hashtable_alloc(int size, int (*hashfn)(), int (*cmpfn)())
{
@ -117,18 +185,49 @@ HASHTABLE *rval;
return rval;
}
#endif
/**
* Delete an entire hash table
*
* @param table The hash table to delete
*/
#if 1
void
hashtable_free(HASHTABLE *table)
{
int i;
HASHENTRIES *entry, *ptr;
hashtable_write_lock(table);
for (i = 0; i < table->hashsize; i++)
{
entry = table->entries[i];
while (entry)
{
ptr = entry->next;
table->kfreefn(entry->key);
table->vfreefn(entry->value);
free(entry);
entry = ptr;
}
}
free(table->entries);
if (!table->ht_isflat)
{
free(table);
}
}
#else
void
hashtable_free(HASHTABLE *table)
{
int i;
HASHENTRIES *entry, *ptr;
hashtable_write_lock(table);
for (i = 0; i < table->hashsize; i++)
{
@ -146,6 +245,7 @@ HASHENTRIES *entry, *ptr;
free(table);
}
#endif
/**
* Provide memory management functions to the hash table. This allows
* function pointers to be registered that can make copies of the

View File

@ -84,12 +84,17 @@ typedef struct hashtable {
SPINLOCK spin; /**< Internal spinlock for the hashtable */
int n_readers; /**< Number of clients reading the table */
int writelock; /**< The table is locked by a writer */
bool ht_isflat; /**< Indicates whether hashtable is in stack or heap */
#if defined(SS_DEBUG)
skygw_chk_t ht_chk_tail;
#endif
} HASHTABLE;
extern HASHTABLE *hashtable_alloc(int, int (*hashfn)(), int (*cmpfn)());
HASHTABLE *hashtable_alloc_flat(HASHTABLE* target,
int size,
int (*hashfn)(),
int (*cmpfn)());
/**< Allocate a hashtable */
extern void hashtable_memory_fns(HASHTABLE *, HASHMEMORYFN, HASHMEMORYFN, HASHMEMORYFN, HASHMEMORYFN);
/**< Provide an interface to control key/value memory

View File

@ -78,7 +78,8 @@ typedef enum rses_property_type_t {
RSES_PROP_TYPE_UNDEFINED=-1,
RSES_PROP_TYPE_SESCMD=0,
RSES_PROP_TYPE_FIRST = RSES_PROP_TYPE_SESCMD,
RSES_PROP_TYPE_LAST=RSES_PROP_TYPE_SESCMD,
RSES_PROP_TYPE_TMPTABLES,
RSES_PROP_TYPE_LAST=RSES_PROP_TYPE_TMPTABLES,
RSES_PROP_TYPE_COUNT=RSES_PROP_TYPE_LAST+1
} rses_property_type_t;
@ -143,6 +144,7 @@ struct rses_property_st {
rses_property_type_t rses_prop_type;
union rses_prop_data {
mysql_sescmd_t sescmd;
HASHTABLE tmp_table_hash;
void* placeholder; /*< to be removed due new type */
} rses_prop_data;
rses_property_t* rses_prop_next; /*< next property of same type */

View File

@ -1263,6 +1263,9 @@ static int routeQuery(
ss_dassert(succp);
goto return_ret;
}
/**
* qtype is QUERY_TYPE_WRITE or QUERY_TYPE_READ_TMP_TABLE
*/
else
{
bool succp = true;
@ -1287,7 +1290,15 @@ static int routeQuery(
if (!rses_begin_locked_router_action(router_cli_ses))
{
goto return_ret;
}
}
#if defined(TEMPORARY_TABLES)
/**
* If query is of type QUERY_TYPE_CREATE_TMP_TABLE then find out
* the database and table name, create a hashvalue and
* add it to the router client session's property. If property
* doesn't exist then create it first.
*/
#endif
if (master_dcb == NULL)
{
@ -2682,8 +2693,13 @@ static bool execute_sescmd_in_backend(
sescmd_cursor_clone_querybuf(scur));
break;
case MYSQL_COM_QUERY:
case MYSQL_COM_INIT_DB:
case MYSQL_COM_INIT_DB:
#if defined(TEMPORARY_TABLES)
/**
* Record database name and store to session.
*/
#endif
case MYSQL_COM_QUERY:
default:
/**
* Mark session command buffer, it triggers writing
@ -2969,7 +2985,7 @@ static bool route_session_write(
rses_property_done(prop);
succp = false;
goto return_succp;
}
}
/**
* Additional reference is created to querybuf to
* prevent it from being released before properties