Cache: Add TesterStorage class

A class dedicated for performing basic testing of Storages.
This commit is contained in:
Johan Wikman
2016-12-15 17:16:36 +02:00
parent 179762ff0a
commit eda84a1f96
2 changed files with 371 additions and 0 deletions

View 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;
}

View 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&);
};