Cache: Add TesterStorage class
A class dedicated for performing basic testing of Storages.
This commit is contained in:
219
server/modules/filter/cache/test/testerstorage.cc
vendored
Normal file
219
server/modules/filter/cache/test/testerstorage.cc
vendored
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testerstorage.hh"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include "storage.hh"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//
|
||||||
|
// class TesterStorage::HitTask
|
||||||
|
//
|
||||||
|
|
||||||
|
TesterStorage::HitTask::HitTask(ostream* pOut,
|
||||||
|
Storage* pStorage,
|
||||||
|
const CacheItems* pCache_items)
|
||||||
|
: Tester::Task(pOut)
|
||||||
|
, m_storage(*pStorage)
|
||||||
|
, m_cache_items(*pCache_items)
|
||||||
|
, m_puts(0)
|
||||||
|
, m_gets(0)
|
||||||
|
, m_dels(0)
|
||||||
|
, m_misses(0)
|
||||||
|
{
|
||||||
|
ss_dassert(m_cache_items.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TesterStorage::HitTask::run()
|
||||||
|
{
|
||||||
|
int rv = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
size_t n = m_cache_items.size();
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (!should_terminate())
|
||||||
|
{
|
||||||
|
if (i >= n)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CacheItems::value_type& cache_item = m_cache_items[i];
|
||||||
|
|
||||||
|
storage_action_t action = TesterStorage::get_random_action();
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case STORAGE_PUT:
|
||||||
|
{
|
||||||
|
cache_result_t result = m_storage.put_value(cache_item.first, cache_item.second);
|
||||||
|
if (result == CACHE_RESULT_OK)
|
||||||
|
{
|
||||||
|
++m_puts;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss_dassert(!true);
|
||||||
|
rv = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STORAGE_GET:
|
||||||
|
{
|
||||||
|
GWBUF* pQuery;
|
||||||
|
cache_result_t result = m_storage.get_value(cache_item.first, 0, &pQuery);
|
||||||
|
|
||||||
|
if (result == CACHE_RESULT_OK)
|
||||||
|
{
|
||||||
|
ss_dassert(GWBUF_LENGTH(pQuery) == GWBUF_LENGTH(cache_item.second));
|
||||||
|
ss_dassert(memcmp(GWBUF_DATA(pQuery), GWBUF_DATA(cache_item.second),
|
||||||
|
GWBUF_LENGTH(pQuery)) == 0);
|
||||||
|
|
||||||
|
gwbuf_free(pQuery);
|
||||||
|
++m_gets;
|
||||||
|
}
|
||||||
|
else if (result == CACHE_RESULT_NOT_FOUND)
|
||||||
|
{
|
||||||
|
++m_misses;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss_dassert(!true);
|
||||||
|
rv = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STORAGE_DEL:
|
||||||
|
{
|
||||||
|
cache_result_t result = m_storage.del_value(cache_item.first);
|
||||||
|
|
||||||
|
if (result == CACHE_RESULT_OK)
|
||||||
|
{
|
||||||
|
++m_dels;
|
||||||
|
}
|
||||||
|
else if (result == CACHE_RESULT_NOT_FOUND)
|
||||||
|
{
|
||||||
|
++m_misses;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss_dassert(!true);
|
||||||
|
rv = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ss_dassert(!true);
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringstream ss;
|
||||||
|
ss << "HitTask ending: "
|
||||||
|
<< m_gets << ", " << m_puts << ", " << m_dels << ", " << m_misses << "\n";
|
||||||
|
|
||||||
|
out() << ss.str() << flush;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// class TesterStorage
|
||||||
|
//
|
||||||
|
|
||||||
|
TesterStorage::TesterStorage(std::ostream* pOut, StorageFactory* pFactory)
|
||||||
|
: Tester(pOut)
|
||||||
|
, m_factory(*pFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TesterStorage::run(size_t n_threads, size_t n_seconds, std::istream& in)
|
||||||
|
{
|
||||||
|
int rv = EXIT_FAILURE;
|
||||||
|
|
||||||
|
Storage* pStorage = get_storage();
|
||||||
|
|
||||||
|
if (pStorage)
|
||||||
|
{
|
||||||
|
size_t n_items = get_n_items(n_threads, n_seconds);
|
||||||
|
|
||||||
|
CacheItems cache_items;
|
||||||
|
|
||||||
|
if (get_cache_items(in, n_items, *pStorage, &cache_items))
|
||||||
|
{
|
||||||
|
rv = run(n_threads, n_seconds, cache_items, *pStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TesterStorage::run(size_t n_threads,
|
||||||
|
size_t n_seconds,
|
||||||
|
const CacheItems& cache_items,
|
||||||
|
Storage& storage)
|
||||||
|
{
|
||||||
|
return run_hit_task(n_threads, n_seconds, cache_items, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TesterStorage::run_hit_task(size_t n_threads,
|
||||||
|
size_t n_seconds,
|
||||||
|
const CacheItems& cache_items,
|
||||||
|
Storage& storage)
|
||||||
|
{
|
||||||
|
int rv = EXIT_FAILURE;
|
||||||
|
|
||||||
|
Tasks tasks;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_threads; ++i)
|
||||||
|
{
|
||||||
|
tasks.push_back(new HitTask(&out(), &storage, &cache_items));
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = Tester::run(out(), n_seconds, tasks);
|
||||||
|
|
||||||
|
for_each(tasks.begin(), tasks.end(), Task::free);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
TesterStorage::storage_action_t TesterStorage::get_random_action()
|
||||||
|
{
|
||||||
|
storage_action_t action;
|
||||||
|
long l = random();
|
||||||
|
|
||||||
|
if (l < RAND_MAX / 3)
|
||||||
|
{
|
||||||
|
action = STORAGE_PUT;
|
||||||
|
}
|
||||||
|
else if (l < 2 * (RAND_MAX / 3))
|
||||||
|
{
|
||||||
|
action = STORAGE_GET;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action = STORAGE_DEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
152
server/modules/filter/cache/test/testerstorage.hh
vendored
Normal file
152
server/modules/filter/cache/test/testerstorage.hh
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <maxscale/cppdefs.hh>
|
||||||
|
#include "tester.hh"
|
||||||
|
|
||||||
|
class StorageFactory;
|
||||||
|
|
||||||
|
class TesterStorage : public Tester
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum storage_action_t
|
||||||
|
{
|
||||||
|
STORAGE_PUT, /*< Put an item to the storage. */
|
||||||
|
STORAGE_GET, /*< Get an item from the storage. */
|
||||||
|
STORAGE_DEL /*< Delete an item from the storage. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class HitTask
|
||||||
|
*
|
||||||
|
* A task whose sole purpose is to hit a Storage continuously
|
||||||
|
* and intensly.
|
||||||
|
*/
|
||||||
|
class HitTask : public Tester::Task
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param pOut The stream to use for (user) output.
|
||||||
|
* @param pStorage The storage to hit.
|
||||||
|
* @param pCache_items The cache items to use when hitting the storage.
|
||||||
|
*/
|
||||||
|
HitTask(std::ostream* pOut,
|
||||||
|
Storage* pStorage,
|
||||||
|
const CacheItems* pCache_items);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs continuously until the task is terminated.
|
||||||
|
*
|
||||||
|
* @return EXIT_SUCCESS or EXIT_FAILURE
|
||||||
|
*/
|
||||||
|
int run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HitTask(const HitTask&);
|
||||||
|
HitTask& operator = (const HitTask&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Storage& m_storage; /*< The storage that is hit. */
|
||||||
|
const CacheItems& m_cache_items; /*< The cache items that are used. */
|
||||||
|
size_t m_puts; /*< How many puts. */
|
||||||
|
size_t m_gets; /*< How many gets. */
|
||||||
|
size_t m_dels; /*< How many deletes. */
|
||||||
|
size_t m_misses; /*< How many misses. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads statements from the provided stream, converts them to cache items and
|
||||||
|
* runs all storage tasks using as many threads as specified for the specified
|
||||||
|
* number of seconds.
|
||||||
|
*
|
||||||
|
* @param n_threads How many threads to use.
|
||||||
|
* @param n_seconds For how many seconds to run the test.
|
||||||
|
* @param in Stream, assumed to refer to a file containing statements.
|
||||||
|
*
|
||||||
|
* @return EXIT_SUCCESS or EXIT_FAILURE.
|
||||||
|
*/
|
||||||
|
virtual int run(size_t n_threads, size_t n_seconds, std::istream& in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs all storage tasks using as many threads as specified, for the specified
|
||||||
|
* number of seconds.
|
||||||
|
*
|
||||||
|
* @param n_threads How many threads to use.
|
||||||
|
* @param n_seconds For how many seconds to run the test.
|
||||||
|
* @param cache_items The cache items to use. Assumed to have been created using
|
||||||
|
* @c storage.
|
||||||
|
* @param storage The storage items to use.
|
||||||
|
*
|
||||||
|
* @return EXIT_SUCCESS or EXIT_FAILURE.
|
||||||
|
*/
|
||||||
|
virtual int run(size_t n_threads, size_t n_seconds, const CacheItems& cache_items, Storage& storage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the HitTask using as many threads as specified, for the specified
|
||||||
|
* number of seconds.
|
||||||
|
*
|
||||||
|
* @param n_threads How many threads to use.
|
||||||
|
* @param n_seconds For how many seconds to run the test.
|
||||||
|
* @param cache_items The cache items to use. Assumed to have been created using
|
||||||
|
* @c storage.
|
||||||
|
* @param storage The storage items to use.
|
||||||
|
*
|
||||||
|
* @return EXIT_SUCCESS or EXIT_FAILURE.
|
||||||
|
*/
|
||||||
|
virtual int run_hit_task(size_t n_threads,
|
||||||
|
size_t n_seconds,
|
||||||
|
const CacheItems& cache_items,
|
||||||
|
Storage& storage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a random action.
|
||||||
|
*
|
||||||
|
* @return Some storage action.
|
||||||
|
*/
|
||||||
|
static storage_action_t get_random_action();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param pOut Pointer to the stream to be used for (user) output.
|
||||||
|
* @param pFactory Pointer to factory to be used.
|
||||||
|
*/
|
||||||
|
TesterStorage(std::ostream* pOut, StorageFactory* pFactory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a storage instance. The ownership is transferred to the caller.
|
||||||
|
*
|
||||||
|
* @return A storage instance or NULL.
|
||||||
|
*/
|
||||||
|
virtual Storage* get_storage() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the desired number of cache items to be used in the tests.
|
||||||
|
*
|
||||||
|
* @param n_threads How many threads are used.
|
||||||
|
* @param n_seconds For how many seconds the tests will be run.
|
||||||
|
*
|
||||||
|
* @return The desired number of items to use.
|
||||||
|
*/
|
||||||
|
virtual size_t get_n_items(size_t n_threads, size_t n_seconds) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StorageFactory& m_factory; /*< The storage factory that is used. */
|
||||||
|
|
||||||
|
private:
|
||||||
|
TesterStorage(const TesterStorage&);
|
||||||
|
TesterStorage& operator = (const TesterStorage&);
|
||||||
|
};
|
Reference in New Issue
Block a user