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:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user